Babel 学习笔记
参考文档
babel是什么
Babel与polyfill的关系:Babel 默认只转换新的 JavaScript 语法,而不转换新的 API。所以当使用Array.prototype.find、Object.assign等静态方法和实例方法时,需要引入polyfill。
Babel 是一个编译器(输入源码 => 输出编译后的代码)。可以让你提前使用新的语法,而不用管浏览器是否已经支持。
实现的方式为:1、转换源代码为目标浏览器支持的语法;2、添加新功能的polyfill;
编译过程分为三个阶段:解析、转换和打印输出。
babel工作模式
输入文本 =》输出文本;
支持plugin模式,本质就是对源文本内容转换后输出新的源文本给下一级。
preset,用于预定义一组plugin集合,这样不用再手动一个个引入plugin。
@babel/preset-env,babel官方提供的一个preset。
Plugin插件
分转换插件和语法插件,
注意:转换插件会自动启用语法插件。因此,如果你已经使用了相应的转换插件,则不需要指定语法插件。
转换插件
这些插件用于转换你的代码。
转换插件会自动启用语法插件。因此,如果你已经使用了相应的转换插件,则不需要指定语法插件。
语法插件
这些插件只允许 Babel 解析(parse) 特定类型的语法(而不是转换)。
parserOpts ??
插件名称
- npm可以直接指定名称,如果插件名称的前缀为 babel-plugin-,你还可以使用它的短名称。
babel-plugin-myPlugin->myPlugin。带scope的插件也一样。 - 还可以使用相对/绝对路径。
1 | { |
插件顺序
将根据转换插件或 preset 的排列顺序依次执行。
- 插件在
Presets前运行。 - 插件顺序从前往后排列。
Preset顺序是颠倒的(从后往前)。
插件参数
插件和 preset 都可以接受参数,参数由插件名和参数对象组成一个数组。
如果不指定参数,下面这几种形式都是一样的:
1 | { "plugins": ["pluginA", ["pluginA"], ["pluginA", {}]] } |
要指定参数,则传递一个以参数名作为键(key)的对象。
1 | { |
preset 的设置参数的工作原理完全相同。
插件开发
本质上就是一个函数。
预设(Presets)
官方 Preset
我们已经针对常用环境编写了一些 preset:
- @babel/preset-env
- @babel/preset-flow
- @babel/preset-react
- @babel/preset-typescript
Stage-X (实验性质的 Presets)
这些提案可能会有变化,因此,特别是处于 stage-3 之前的任何提案,请务必谨慎使用。
TC39 将提案分为以下几个阶段:
Stage 0- 设想(Strawman):只是一个想法,可能有 Babel插件。Stage 1- 建议(Proposal):这是值得跟进的。Stage 2- 草案(Draft):初始规范。Stage 3- 候选(Candidate):完成规范并在浏览器上初步实现。Stage 4- 完成(Finished):将添加到下一个年度版本发布中
创建 Preset
如需创建一个自己的 preset,只需导出一份配置即可。preset 可以包含其他的 preset,以及带有参数的插件。
1 | module.exports = function() { |
preset-env 与 polyfill
官方文档
知乎 - Babel7 中 @babel/preset-env 的使用
babel使用preset-env能将最新的语法转换为ecmascript5的写法,当我们需要使用新增的全局函数(比如promise,Array.from)和实例方法(比如Array.prototype.includes)时就需要引入polyfill, 一般用法在index.js文件的最上层引入,或是在打包文件的entry入口处引入,这样做的缺点是会全局引入整个polyfill包,比如promise会全局引入,污染全局环境。
引入方式:
1 | import "@babel/polyfill"; |
与 useBuiltIns 结合使用
结合useBuiltIns选项可以定义@babel/polyfill的引入方式。
entry:需要在项目入口文件最顶部引入import '@babel/polyfilll',会结合targets转换为一系列引入语句,去掉目标浏览器已支持的polyfilll模块,不管代码里有没有用到,只要目标浏览器不支持都会引入对应的polyfilll模块。usage:不需要手动在代码里写import '@babel/polyfilll',打包时会自动根据实际代码的使用情况,结合targets引入代码里实际用到的部分polyfilll模块,但任然需要被install。false:需要手动引入,babel对import '@babel/polyfilll'不作任何处理,也不会自动引入polyfilll模块。官方建议在webpack配置中作为入口(entry)引入,而不是在入口js文件中使用import/require语句。
1 | // useBuiltIns选项为false 或 干脆就没用preset-env 的情况下,建议使用该方式引入polyfill |
@babel/plugin-transform-runtime
babel-polyfill 使用场景
Babel 默认只转换新的 JavaScript 语法,而不转换新的 API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。如果想使用这些新的对象和方法,必须使用 babel-polyfill,为当前环境提供一个垫片。
babel-runtime 使用场景
Babel 转译后的代码要实现源代码同样的功能需要借助一些帮助函数,而这些帮助函数可能会重复出现在一些模块里,导致编译后的代码体积变大。Babel 为了解决这个问题,提供了单独的包 babel-runtime 供编译模块复用工具函数。