参考了很多文章,只是为了搞清楚babel 7 之后容易搞混的概念。
介绍
本文主要解决如下几个问题:
- babel 是什么?
- babel 的原理是什么?
- babel 7 常见的核心包有哪些?
- babel 7 的最佳配置实践
一、babel 是什么?
babel 是一个 JavaScript 编译器。
除了常用的 将新语法转换为向后兼容的语法
外,还支持如下功能:
- 支持语法扩展(例如 JSX)
- 支持静态类型检查的流式语法
二、babel 的原理是什么?
babel 的 三个主要处理步骤分别是:解析(parse)
、转换(transform)
、生成(generate)
。
2.1 解析
解析步骤接收代码并输出抽象语法树(AST)。
- 词法分析
词法分析阶段把字符串形式的代码转换为令牌(tokens)
流。 - 语法分析
语法分析阶段使用令牌中的信息把令牌流转换成 AST 的形式。
2.2 转换
转换步骤接收 AST 并对其进行遍历,在此过程中对节点进行添加、更新及移除等操作。
2.3 生成
代码生成步骤把最终的 AST 转换成字符串形式的代码,同时还会创建源码映射。
三、babel 7 常见的核心包有哪些?
babel 73.1 @babel/preset-env
@babel/preset-env
是一个智能的 babel 预设,让你能使用最新的 JavaScript 语法,他会帮你转换成代码的目标运行环境支持的语法,提升你的开发效率并让打包后的代码体积更小。
运行机制:
@babel/preset-env
依赖了许多优秀的开源库,并利用它们维护和增强 Babel 语法转换、语法实现,来支持对于的目标环境的版本的语法、特征。
重要的配置项:
target
可以指定浏览器类型。
这里推荐使用单独的文件 browserslistrc
来指定目标浏览器,因为除了 babel 还有其他插件,例如 postcss 也会用到。
useBuiltIns
配置@babel/preset-env
如何处理 polyfill
- entry
这个属性将会把import "@babel/polyfill
或者require("@babel/polyfill")
替换成对应环境(基于配置的目标环境)的 polyfill。 - usage
按需加载需要的polyfill, 一个打包的 bundle 之后加载一次。 - false
不加载polyfill
3.2 @babel/polyfill
@babel/polyfill
模块包括core-js
和一个自定义的 regenerator runtime
模块用于模拟完整的 ES2015+ 环境。
- 新的内置组件:Promise、WeakMap
- 静态方法:Array.from、Object,assign()
- 实例方法:Array.prototype.includes
- 生成器函数
弊端:会污染全局
Babel 7.4 之后废弃了 @babel/polyfill
, 不再推荐使用。需要分别引入
import "core-js/stable";
import "regenerator-runtime/runtime";
3.3 @babel/plugin-transform-runtime
@babel/plugin-transform-runtime
是一个可重新使用Babel注入的帮助程序代码以节省代码大小的插件。
诸如“ foobar” .includes(“ foo”)之类的实例方法仅适用于core-js @ 3。
如果您需要填充它们,则可以直接导入“ core-js”或使用@babel/preset-env的useBuiltIns选项。
为什么需要 @babel/plugin-transform-runtime
?
默认情况下,辅助函数将被添加到需要它的每个文件中。有时不需要重复,特别是当您的应用程序分布在多个文件中时。
-
所有辅助函数都将引用模块
@babel/runtime
,以避免在编译后的输出中出现重复。运行时将被编译到您的构建中。 -
该插件的另一个目的是为您的代码创建一个沙盒环境。如果直接导入core-js或@babel/polyfill及其提供的内置程序(例如Promise,Set和Map),则这些将污染全局范围。虽然这对于应用程序或命令行工具可能是可以的,但是如果您的代码是要发布供他人使用的库,或者您无法完全控制代码运行的环境,则将成为一个问题。
corejs option | Install command |
---|---|
false | npm install --save @babel/runtime |
2 | npm install --save @babel/runtime-corejs2 |
3 | npm install --save @babel/runtime-corejs3 |
四、区分开发依赖和生产依赖
Babel 7.4 版本
需要作为开发依赖的:
@babel/preset-env
、@babel/plugin-transform-runtime
、@babel/polyfill
需要作为生产依赖的:
@babel/runtime
、regenerator-runtime
、core-js
总结
@babel/preset-env
是为了解决按需加载 polyfill
@babel/polyfill
是为了提供语法之外的垫片(内置组件、静态方法、实例方法等)
@babel/plugin-transform-runtime
是为了解决全局污染和辅助函数的重复引入
五、实践
5.1 babel 的疑惑解答
说明一:@babel/preset-env
默认配置,并不能完整的转换 es6、以及 es7、es8 等新提案,它只能够转换新语法,但是对于Array.includes() 、Promise 等并不支持
说明二:@babel/polyfill
提供了语法之外的垫片(内置组件、静态方法、实例方法等),@babel/polyfill
依赖于 core-js
和 regenerator-runtime
实现的垫片
说明三: babel 7.4
之后废弃了 @babel/polyfill
。
说明四:core-js
是 JavaScript 的模块化标准库,提供了大部分 ES2015+ 的 polyfill 。现在推荐使用 core-js@3
。
说明五:regenerator-runtime
facebook 出品的一个提供编译 generator
、async/await
的独立运行时。
总结:babel 7.4
之后@babel/preset-env
需要和 core-js
、regenerator-runtime
搭配使用,才能提供完整的 ES2015+ 环境
5.2 普通应用的 babel 配置
安装babel 相关的依赖
yarn add @babel/core @babel/preset-env babel-loader --dev
yarn add core-js@3
yarn add regenerator-runtime
webpack.config.js
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
.babelrc
文件
{
"presets": [
[
"@babel/preset-env",
{
"useBuiltIns": "usage",
"corejs": 3
}
]
]
}
说明一:babel-loader 是 webpack 的插件, 会默认读取 .babelrc
中的配置
说明二:core-js@3
和 regenerator-runtime
需要作为 dependencies
, 因为这两个依赖中的部分或全部代码会被引入进代码,作为 polyfill,属于生产依赖。
说明三:useBuiltIns
的参数选择,推荐选择 usage
,此选项将按需导入 polyfill。而 entry
会把全部的 polyfill 都引入到打包后的文件中。
说明四:useBuiltIns
会把 polyfill 引入到全局,所以会污染全局。
说明五: useBuiltIns: usage
配置时,需要在主文件中主动引入 core-js
import "core-js/stable";
import "regenerator-runtime/runtime";
5.3 第三方库的 babel 配置(待更新)
@babel/transform-runtime
会从 core-js-pure
这个包里去加载对应的polyfill代码,core-js-pure里面的代码不会污染全局变量,适合第三方库的开发。
-- 2020/01/07 更新 --
参考
babel 中文文档-使用说明
Babel 手册
刘小夕:不容错过的 Babel7 知识
知乎:babel 只编译语法
知乎:致我们学前端的小时光—corejs与env、runtime的不解之缘
知乎:Babel学习系列4-polyfill和runtime差别(必看)
怎么给新手科普Babel:polyfill/preset-env/plugin-transform-runtime
关于Babel你只需要知道三个插件
一口(很长的)气了解 babel
荒山:深入浅出 Babel 上篇:架构和原理 + 实战
倪晓磊:【工程化】@babel/preset-env 与@babel/plugin-transform-runtime 使用及场景区别
网友评论