postcss-url
postcss-url copied to clipboard
copy fonts
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
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 a little bit tricky but very helpful! Kudo.
One note, please add that you use fs-extra package
I think we should write @mojavelinux solution in Readme, somewhere.
Thanks @mojavelinux.
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.
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?
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 maybe I miss something here, but where does dest variable come from?
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.