如何实现在构建阶段通过自定义打包插件对冗余语言包代码的自动剔除

作者:袖梨 2026-07-26
多语言项目可通过自定义打包插件剔除未使用的语言包以减小体积。插件在构建阶段静态分析 locale 路径,仅保留白名单语言,支持 Vite(resolveId 钩子)和 Webpack(NormalModuleReplacementPlugin),并可进阶结合 AST 扫描自动推断语言标识。

在多语言项目中,构建产物常因引入完整语言包(如 momentant-designelement-plus 的 locale 文件)而体积膨胀。自定义打包插件可在构建阶段静态分析并剔除未使用的语言包代码,无需手动维护,效果直接且可复用。

识别冗余语言包的关键路径

多数 UI 库或工具库将语言包组织为独立模块,路径有明显规律,例如:

  • antd/es/locale/zh_CN.jsantd/es/locale/en_US.js
  • element-plus/lib/locale/lang/zh-cn.jsen.js
  • dayjs/locale/zh-cn.jsja.js

插件需监听这些路径的导入语句,在依赖图生成阶段捕获实际被引用的语言包,其余视为冗余。

在 Vite 中编写简易剔除插件

Vite 插件可通过 transformresolveId 钩子介入模块解析。推荐使用 resolveId 拦截 locale 路径,仅保留白名单语言:

export default function localePrunePlugin(options = {}) {  const { include = ['zh-CN', 'zh-cn', 'en-US', 'en-us'] } = options;  const validLocales = new Set(include.map(s => s.toLowerCase()));  return {    name: 'locale-prune',    resolveId(id) {      // 匹配常见 locale 路径模式      const localeMatch = id.match(//locale/(?:lang/)?([a-z_-]+).js$/i);      if (localeMatch) {        const lang = localeMatch[1].toLowerCase();        if (!validLocales.has(lang)) {          return { id: 'virtual:empty-locale', external: true };        }      }    },    load(id) {      if (id === 'virtual:empty-locale') return 'export default {};';    }  };}

vite.config.ts 中启用:

import localePrune from './plugins/locale-prune';export default defineConfig({  plugins: [localePrune({ include: ['zh-cn', 'en-us'] })],});

Webpack 场景下使用 NormalModuleReplacementPlugin

Webpack 更适合用 NormalModuleReplacementPlugin 在模块解析时重定向:

const webpack = require('webpack');module.exports = {  plugins: [    new webpack.NormalModuleReplacementPlugin(      //locale/(?:lang/)?([a-z_-]+).js$/i,      (resource) => {        const lang = resource.request.match(//locale/(?:lang/)?([a-z_-]+).js$/i)?.[1]?.toLowerCase();        if (lang && !['zh-cn', 'en-us'].includes(lang)) {          resource.request = path.resolve(__dirname, 'src/stubs/empty-locale.js');        }      }    )  ]};

确保 src/stubs/empty-locale.js 存在且导出空对象或兼容接口,避免运行时报错。

进阶:结合编译期语言检测自动推断

若项目通过 import locale from 'xxx/locale/zh-CN' 显式引入,可进一步在 transform 阶段扫描 AST,提取所有字面量语言标识,动态构建白名单。例如用 @babel/parser 解析源码,查找 CallExpressionImportDeclaration 中匹配 /locale/[a-z_-]+/i 的字符串,汇总后用于后续剔除逻辑。这种方式无需硬编码 include,更适合大型多语言切换项目。

相关文章

精彩推荐