postcss-url icon indicating copy to clipboard operation
postcss-url copied to clipboard

copy fonts

Open asicfr opened this issue 7 years ago • 9 comments

Hi, i know that you do not encourage the use of copy, but i have a tricky need.
I have a node_module with a css file and relative font urls : @font-face{font-family:"Avenir";src:url("./fonts/avenir-lighter.woff") format("woff")}

My app uses Nextjs and with style-loader + css-loader, my css module is well integrated to the output /.next/static/style.css but font files url are not copied magically to that folder.

So i want to use postcss-url to copy all fonts files to /.next/static/ and adapt url to point to that files.
I try that :

module.exports = {
  plugins: [
    require('postcss-url')({
      url: 'copy',
      basePath: `${path.resolve('node_modules/my-styleguide')}/dist/build/`,
      assetsPath: '/.next/static/',
    }),
  ]
};

Sadly, it doesn't work and i get the following error :
These relative modules were not found:

  • ../../../../.next/static/fonts/avenir-bold-black-heavy.woff in ./node_modules/my-styleguide/dist/build/styleguide.css

Have you got any idea ?

Thx

asicfr avatar Apr 10 '18 15:04 asicfr

Here's what I use. First, I require typeface fonts from npm (e.g., https://yarnpkg.com/en/package/typeface-roboto). Then I configure the task as follows:

const postcssPlugins = [ 
  postcssUrl([
    {
      filter: '**/~typeface-*/files/*',
      url: (asset) => {
        const relpath = asset.pathname.substr(1)
        const abspath = path.resolve('node_modules', relpath)
        const basename = path.basename(abspath)
        const destpath = path.join(dest, 'font', basename)
        if (!fs.pathExistsSync(destpath)) fs.copySync(abspath, destpath)
        return path.join('..', 'font', basename)
      },
    },
  ]),
]

This puts the fonts into the "font" folder inside the dest directory, where I can bundle them with my app.

mojavelinux avatar Dec 29 '18 12:12 mojavelinux

@mojavelinux a little bit tricky but very helpful! Kudo.

One note, please add that you use fs-extra package

vatson avatar Jul 19 '19 11:07 vatson

I think we should write @mojavelinux solution in Readme, somewhere.

Thanks @mojavelinux.

frederikhors avatar Dec 20 '19 00:12 frederikhors

I think this qualifies as a bug. Enabling the useHash option works just fine:

module.exports = {
  // inherited 'to' from the postcss-cli command flags
  plugins: [
    require('postcss-import')(),
    require('postcss-url')({
      url: 'copy',
      assetsPath: 'static',
      useHash: true,
    }),
    ...otherPlugins,
  ],
}

Imported files were copied to the assetsPath inside the to folder and correctly referenced in the processed CSS.

Roboe avatar May 01 '20 23:05 Roboe

On top of @mojavelinux 's solution I had to ensure destpath directory exists and provide dest path pointing to the PostCSS output directory relative to the project root.

Is there any way to get the PostCSS out directory inside the custom url function?

shishkin avatar Aug 15 '22 19:08 shishkin

Here's what I did:

postcssUrl([
  {
    url: (asset) => {
      const relpath = asset.pathname.substr(1)
      const abspath = require.resolve(relpath)
      const basename = ospath.basename(abspath)
      const destpath = ospath.join(dest, 'font', basename)
      if (!fs.pathExistsSync(destpath)) fs.copySync(abspath, destpath)
      return path.join('..', 'font', basename)
    },
  },
]),

(I just realized I shared exactly the same snippet above).

mojavelinux avatar Aug 16 '22 08:08 mojavelinux

@mojavelinux maybe I miss something here, but where does dest variable come from?

shishkin avatar Aug 16 '22 08:08 shishkin

It's the value passed into the function that is handling writing the processed CSS. In my case, I'm using postCSS in a vinyl-fs pipeline. So dest is the vinyl-fs dest target.

mojavelinux avatar Aug 16 '22 08:08 mojavelinux