描述在 grunt 中实现字体子集化以支持多语言

解读

面试官真正想考察的是:

  1. 你是否理解“字体子集化”对多语言性能优化的意义:剔除未用字形,减少包体,缩短 FCP/LCP。
  2. 能否把Grunt 插件生态国内常见语言场景(简体中文、繁体中文、日文、韩文、拉丁扩展、图标字体)结合起来,给出可落地的任务链
  3. 是否具备工程化思维:配置一次,CI 自动跑,支持增量构建,出错可回滚。
  4. 字体版权合规有没有意识,避免“拿方正/汉仪直接切”这类红线。

知识点

  • grunt-webfont:把 SVG 图标批量生成图标字体,可配合 unicode-map 做码点去重。
  • grunt-fontmin:国内阿里团队开源,基于 fontmin 核心,可扫描本地文件远程模板中的字符,输出子集。
  • grunt-unicode-db:生成 Unicode 范围正则,方便按语言区块(CJK Unified Ideographs、Hangul Syllables、Latin-1 Supplement)批量过滤。
  • grunt-contrib-watch + grunt-contrib-connect:监听翻译文件变动,自动重跑子集任务并触发 Livereload,方便多语言同事并行调试。
  • grunt-cache-bust:子集字体文件名加 hash,避免 CDN 缓存旧版本。
  • 多语言字符来源最佳实践
    • 业务代码:扫描 src/**/*.{vue,jsx,ts,html} 中的字面量。
    • 翻译文件:扫描 locales/**/*.json,把 value 合并成字符池。
    • 动态文案:若走接口,需把后端返回的高频词提前落库到白名单文本
  • 版权红线:确认原字体授权允许Web 嵌入及修改生成衍生字体;国内大厂通常采购思源黑体、阿里巴巴普惠体、OPPO Sans,可放心子集化。
  • 构建策略
    • 开发阶段:保留完整字体,方便新增文案。
    • 提测/上线:CI 触发 grunt build:prod,自动切到子集。
    • 增量优化:利用 grunt-newer,只重编变动的语言包。

答案

我之前的项目用 Grunt 做多语言门户,字体包体从 6.3 MB 压到 430 KB,核心思路分三步:

  1. 收集字符池

    • grunt-icontochar 扫描图标组件,输出已用 icon 的 unicode 数组。
    • grunt-fontmin 自带的 text 插件,把 locales/**/*.json 里所有文案合并成去重后的超大字符串。
    • 再加一份产品名、运营活动关键词白名单,避免动态接口文案缺字。
  2. 生成子集字体

    • 任务链:grunt.registerTask('subset', ['fontmin:zhCN', 'fontmin:zhTW', 'fontmin:jaJP', 'fontmin:koKR'])
    • 每个 target 指定各自的 Unicode 范围:
      fontmin: {
        zhCN: {
          options: { text: '<%= grunt.file.read("tmp/zhCN.txt") %>' },
          src: 'src/fonts/AlibabaPuHuiTi-Regular.ttf',
          dest: 'dist/fonts/zhCN/'
        }
      }
      
    • 图标字体单独跑 webfont 任务,与文本字体分离,避免混排导致的 baseline 异常。
  3. 注入与缓存

    • grunt-replacedist/index.html 中的 <link rel="preload"> 路径替换成带 hash 的新字体。
    • grunt-cache-bust 给字体文件加 8 位 hash,Nginx 开启 Cache-Control: max-age=31536000, immutable
    • 最后 grunt-contrib-compress 打成 fonts-zhCN.gz,OSS 自动回源,移动端节省 30% 额外流量。

整个流程接入 GitLab CI,合并请求阶段跑 grunt subset --lang=all,若包体增长超 5% 会中断流水线,防止意外引入全量字符。

拓展思考

  1. 可变字体(Variable Font)+ 子集化:未来可把字重轴(wght)从 200-900 切成 3 档,再按语言子集,进一步省 20%-40%。
  2. 动态增量:若文案走 CMS,可在发布接口回调里触发 Lambda 版 fontmin,实时生成新子集并推送到边缘节点,实现“文案上线 30 秒内字体就绪”。
  3. 合规自动化:在 Gruntfile 里加 grunt-license-finder,扫描字体目录授权文件,若缺失则中断构建,避免法务风险。
  4. 性能衡量:把 /dist/fonts/*.woff2 加入 WebPageTest 的“自定义指标”,子集化前后对比字形加载时间(Glyph Load Time),用数据说服老板继续投入工程化资源。