如何阻止Webpack将Base64编码字体提取为独立文件?
问题:CRA+craco下内联Base64字体被提取为独立文件导致显示异常
使用Create React App(CRA)搭配craco开发时,引入的第三方组件通过Base64编码字符串加载自定义字体:
src:url(data:application/x-font-ttf;charset=utf-8;base64,AAEA...AAAAA==) format("truetype")}
构建后该语句被转为提取独立文件的形式:
src:url(/static/media/1653a5f7) format("truetype")}
即使修改assetModuleFilename解决了文件名无扩展名的问题,文件返回状态码200,但字体仍无法正常显示。未使用craco的版本中字体加载正常,另有环境下字体保持内联未被提取。
解决方案:阻止webpack提取内联Base64字体
核心思路是调整webpack规则,让内联的Base64字体资源保持原状态,不被提取为独立文件。可通过以下两种方式修改craco配置:
方式一:强制字体资源内联
定位处理字体的loader,设置limit: Infinity(针对url-loader)或type: 'asset/inline'(针对asset module),让所有字体资源保持内联:
修改后的craco.config.js:
module.exports = { webpack: { configure: (config) => { config.module.rules.forEach((rule) => { if (rule.oneOf instanceof Array) { // 定位处理字体的规则 const fontRule = rule.oneOf.find( (loader) => (loader.test?.test('.ttf')) || (loader.loader?.includes('url-loader') && loader.test?.test('.ttf')) ); if (fontRule) { // 针对url-loader:设置无限大limit,强制内联 if (fontRule.loader?.includes('url-loader')) { fontRule.options.limit = Infinity; fontRule.options.name = 'static/media/[name][hash:8].[ext]'; } // 针对asset module:指定类型为内联 if (fontRule.type === 'asset') { fontRule.type = 'asset/inline'; } } // 保留原有exclude配置 rule.oneOf[rule.oneOf.length - 1].exclude = [ /\.(js|mjs|jsx|cjs|ts|tsx)$/, /\.html$/, /\.json$/ ]; } }); // 保留原有输出配置 config.output.filename = 'static/js/[name][contenthash:8].js'; config.output.assetModuleFilename = 'static/media/[name][hash:8][ext]'; config.output.chunkFilename = 'static/js/[name][contenthash:8].chunk.js'; return config; }, } };
方式二:优先跳过data URL资源的处理
在webpack规则最前面添加一条规则,匹配所有data:开头的资源,直接标记为内联,避免后续loader处理提取:
修改后的craco.config.js:
module.exports = { webpack: { configure: (config) => { // 新增规则:匹配data URL资源,直接内联 config.module.rules.unshift({ test: /^data:/, type: 'asset/inline', }); // 原有规则处理逻辑 config.module.rules.forEach((rule) => { if (rule.oneOf instanceof Array) { const urlLoader = rule.oneOf.find( (loader) => loader.loader && loader.loader.includes('url-loader') ); if (urlLoader) { urlLoader.options.name = 'static/media/[name][hash:8].[ext]'; } rule.oneOf[rule.oneOf.length - 1].exclude = [ /\.(js|mjs|jsx|cjs|ts|tsx)$/, /\.html$/, /\.json$/ ]; } }); // 原有输出配置 config.output.filename = 'static/js/[name][contenthash:8].js'; config.output.assetModuleFilename = 'static/media/[name][hash:8][ext]'; config.output.chunkFilename = 'static/js/[name][contenthash:8].chunk.js'; return config; }, } };
修改配置后重新构建项目,检查字体加载语句是否保持原Base64内联形式,部署后即可正常显示字体。
内容的提问来源于stack exchange,提问作者Ivo D
相关产品推荐
相关产品推荐

