You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何阻止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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 20:58:23