如何最好地在汇总包中包含 scss 文件中引用的资产(图像和字体)
我正在用 typescript、sass 和 rollup 编写一个 react 组件库,我希望它尽可能独立。
有人对如何最好地包含 scss 文件中引用的资产(图像和字体)有什么建议吗?
一种解决方案可能是某种加载器(例如 postcss 处理器)用 base64 版本替换 scss 文件中引用的所有图像和字体资产。
有人有以有效方式完成此操作的示例吗?任何解决方案或建议都将不胜感激🙏🏻
我的汇总配置如下所示:
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import resolve from "rollup-plugin-node-resolve";
import typescript from "rollup-plugin-typescript2";
import scss from 'rollup-plugin-scss'
import sass from "rollup-plugin-sass";
import commonjs from "rollup-plugin-commonjs";
import copy from "rollup-plugin-copy";
import url from '@rollup/plugin-url';
import packageJson from "./package.json";
export default {
input: "src/index.tsx",
output: [
{
file: packageJson.main,
format: "cjs",
sourcemap: true
},
{
file: packageJson.module,
format: "esm",
sourcemap: true
}
],
plugins: [
peerDepsExternal(),
resolve({
browser: true
}),
typescript({ objectHashIgnoreUnknownHack: true }),
commonjs({
include: ["node_modules/**"],
exclude: ["**/*.stories.js"],
namedExports: {
"node_modules/react/react.js": [
"Children",
"Component",
"PropTypes",
"createElement"
],
"node_modules/react-dom/index.js": ["render"]
}
}),
scss({
}),
sass({
insert: true
}),
copy({
targets: [
{
src: "src/variables.scss",
dest: "build",
rename: "variables.scss"
},
{
src: "src/typography.scss",
dest: "build",
rename: "typography.scss"
},
{
src: "src/assets",
dest: "build/",
},
]
})
]
};
更新:
因此,我所做的可能有些不妥,但它解决了我的问题。
我在 rollup.config.js 中的插件数组中添加了一个 postcss-plugin, 在 一个 commonjs 插件之后。
postcss({
inject: true,
plugins: [
postcssInlineBase64({
baseDir: 'src/assets/',
}),
postcssUrl({
url: 'inline',
}),
atImport({
path: path.resolve(__dirname, '../'),
}),
],
}),
我也使用 storybook,它在内部使用 webpack,因此我不得不在 .storybook/webpack.config.js 中重新创建相同的内容:
config.module.rules.push({
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
inject: true,
ident: 'postcss',
plugins: [
postcssInlineBase64({
baseDir: 'src/assets/',
}),
postCssUrl({ url: 'inline' }),
atImport({
path: path.resolve(__dirname, '../'),
}),
],
},
},
'sass-loader',
],
include: path.resolve(__dirname, '../'),
});
现在,在 scss 中使用 url 指令时(或可能在其他地方),我可以使用以下方式包围任何路径:
b64---<SOME_PATH>---
对于实例:
@font-face {
font-family: 'Open Sans';
font-display: swap;
font-style: normal;
font-weight: 300;
src: url('b64---./fonts/open-sans/open-sans-v15-latin-ext_latin-300.woff2---') format('woff2'),
url('b64---./fonts/open-sans/open-sans-v15-latin-ext_latin-300.woff---') format('woff');
}
这使得 post css 将资产打包为 base64。
致任何可能看到这篇文章的人。祝你好运!希望这能有所帮助!
使用 postcss-url 资源函数使其工作,使用真实的图像文件而不是 base64。
这个想法是,包将 CSS 提取到单独的文件中,并且
url()
中引用的所有资源都被拦截、散列并放入文件夹 (
_assets
),然后 postcss-url 将原始 url 更改为该文件夹。
消费者应用程序(例如使用
css-loader
等工具的 webpack)导入 CSS
import 'pkg-name/dist/index.css'
其中所有
url()
看起来都像
background-image: url(_assets/<hash>.png)
,并且该加载器还负责将这些资源带入包中,并将
url()
替换为具有公共路径的本地 url,例如
url(/static/<app-hash>.png)
。
由于无法从该回调访问插件实例,它不使用内置于
emitFile
的汇总,尽管这是理想的选择。
import fs from "fs-extra";
import path from "path";
import hasha from "hasha";
const IMAGES_RX = /\.(png|jpe?g|gif|webp|svg)$/;
// rollup config
plugins: [
postcss({
extract: true,
plugins: [
// extracts all url() assets into _assets folder, and replaces the url() to a relative path
// consumers of this package (e.g. webpack apps) will import the css and handle getting assets as well
postcssUrl({
url: (asset: any) => {
if (!IMAGES_RX.test(asset.url)) return asset.url;
const file = fs.readFileSync(asset.absolutePath);
const hash = hasha(file, { algorithm: "md5" });
const extname = path.extname(asset.absolutePath);
const hashedFileName = `${hash}${extname}`;
fs.ensureDirSync(path.join(OUT_DIR, "_assets"));
const hashedFilePath = path.join("_assets", hashedFileName);
fs.writeFileSync(path.join(OUT_DIR, hashedFilePath), file);
return hashedFilePath;
},
}),
],
}),
]