开篇
Babel 对于前端开发者来说应该是很熟悉了,它能够转译 ECMAScript 2015+
的代码,使得代码能够在旧的浏览器或者环境中运行。
Babel 的转换工作可以分为三部分:
- Parse(解析):将源代码转换成更加抽象的表示方法(AST 抽象语法树);
- Transform(转换):对抽象语法树进行变换操作;
- Generate(代码生成):将转换阶段变换后的抽象语法树,生成新的源代码。
其中,Babel 插件应用于第二阶段 Transform
。
大多数插件的指责是转换代码,但除了这项重要工作外,插件还可以用于新的工作任务,比如用于处理 收集 工作。
业务背景
通常公司会有一个专门管理词条的数据池,包含了基础通用词条及和本工程相关词条,如果将词条资源全部引入,会造成引入体积过大,影响页面性能。
所以本篇围绕的主题:通过收集项目中使用到的 i18n 多语种词条 key,去词条数据池中查找与之对应的数据,生成最终的词条资源(按需打包词条资源)。
下面我们先来熟悉一下如何编写一个插件。
插件基本结构
插件本身是一个函数,函数的入参是 babel 对象,从中我们可以拿到 babel 的所有成员,最常用的是 types 对象,可以通过它来构造、变换 AST 节点。
如下是一个插件的基本结构:返回一个对象,其中访问者(visitor)的内容对应的是一个个 AST 节点类型,在遍历 AST 节点时,就会进入 visitor 中去匹配相应类型。
export default function ({ types: t }) {
return {
pre(file) {
this.cache = new Map();
},
visitor: {
...
},
post(file) {
console.log(this.cache);
}
};
}
pre 和 post 分别会在遍历 visitor 前后调用,接收 file
(当前要处理的文件)作为参数,通过 file.opts.filename
拿到文件路径;一般在这里可以做一些插件调用前后的逻辑。
注意,插件的函数体结构之后在构建时执行一次;但函数 return 的这个对象,会在每个文件中都执行一次完整的生命周期,即:在处理每个文件时都会执行 pre、visitor、post 属性方法。
代码演示
通常,我们在项目中可以通过 i18n
函数表达式接收词条 key
来渲染多语种文本,具体如下:
function Button() {
return (
<button>{i18n('save')}</button>
)
}
场景:
所有项目工程内的词条统一由一个数据存储池来集中管理。(可以是一个 git 仓库)
期望:
在经过打包后,收集到本项目中所有 i18n
函数表达式的参数 key
,与我们的词条存储池中的数据进行匹配,最终生成一个只包含本项目内所使用到的相关词条。
这里,我们先以 babel-plugin-collect-i18n
来表示插件名称。
我们可以这样使用,比如在