postcss / postcss-url

PostCSS plugin to rebase url(), inline or copy asset.
MIT License
377 stars 59 forks source link

copy fonts #121

Open asicfr opened 6 years ago

asicfr commented 6 years ago

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:

Have you got any idea ?

Thx

mojavelinux commented 5 years ago

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.

vatson commented 5 years ago

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

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

frederikhors commented 4 years ago

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

Thanks @mojavelinux.

Roboe commented 4 years ago

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.

shishkin commented 2 years ago

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?

mojavelinux commented 2 years ago

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).

shishkin commented 2 years ago

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

mojavelinux commented 2 years ago

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.