We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Babel 是一个 JavaScript 编译器,用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前版本和旧版本的浏览器或其他环境中。简单来说 Babel 的工作就是:
Polyfill
@babel/polyfill
Babel 的编译过程和大多数其他语言的编译器相似,可以分为三个阶段:
Babel 的编译器,核心 API 都在这里面,比如常见的 transform、parse。
Babel
transform
parse
cli 是命令行工具, 安装了 @babel/cli 就能够在命令行中使用 babel 命令来编译文件。当然我们一般不会用到,打包工具已经帮我们做好了。
cli
@babel/cli
babel
直接在 node 环境中,运行 ES6 的代码
node
ES6
Babel 的解析器
用于对 AST 的遍历,维护了整棵树的状态,并且负责替换、移除和添加节点。
用于 AST 节点的 Lodash 式工具库, 它包含了构造、验证以及变换 AST 节点的方法,对编写处理 AST 逻辑非常有用。
Babel 的代码生成器,它读取 AST 并将其转换为代码和源码映射(sourcemaps)
Babel 构建在插件之上,使用现有的或者自己编写的插件可以组成一个转换通道,Babel 的插件分为两种: 语法插件和转换插件。
这些插件只允许 Babel 解析(parse) 特定类型的语法(不是转换),可以在 AST 转换时使用,以支持解析新语法,例如:
import * as babel from "@babel/core"; const code = babel.transformFromAstSync(ast, { //支持可选链 plugins: ["@babel/plugin-proposal-optional-chaining"], babelrc: false }).code;
转换插件会启用相应的语法插件(因此不需要同时指定这两种插件),这点很容易理解,如果不启用相应的语法插件,意味着无法解析,连解析都不能解析,又何谈转换呢?
@babel/plugin-transform-runtime 是一个可以重复使用 Babel 注入的帮助程序,以节省代码大小的插件
我们假设 ES6 有 10 个新特性,那为了把 ES6 转换成 ES5 就需要安装 10 个转换插件,配置文件很长不说,npm install 的时间也会很长。为了解决这个问题,babel 还提供了一组插件的集合,就叫 presets。
通过使用或创建一个 preset 即可轻松使用一组插件。
preset
presets 是这么分类的
官方 Preset:
Preset
@babel/preset-env 主要作用是对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载 polyfill,在不进行任何配置的情况下,@babel/preset-env 所包含的插件将支持所有最新的 JS 特性(ES2015,ES2016 等,不包含 stage 阶段),将其转换成 ES5 代码。例如,如果你的代码中使用了可选链(目前,仍在 stage 阶段),那么只配置 @babel/preset-env,转换时会抛出错误,需要另外安装相应的插件。
@babel/preset-env
polyfill
需要说明的是,@babel/preset-env 会根据你配置的目标环境,生成插件列表来编译。对于基于浏览器或 Electron 的项目,官方推荐使用 .browserslistrc 文件来指定目标环境。默认情况下,如果你没有在 Babel 配置文件中(如 .babelrc)设置 targets 或 ignoreBrowserslistConfig,@babel/preset-env 会使用 browserslist 配置源。
.browserslistrc
.babelrc
targets
ignoreBrowserslistConfig
browserslist
babel 对一些新的 API 是无法转换,比如 Generator、Set、Proxy、Promise 等全局对象,以及新增的一些方法:includes、Array.form 等。所以这个时候就需要一些工具来为浏览器做这个兼容。
Generator
Set
Proxy
Promise
includes
Array.form
官网的定义:babel-polyfill 是为了模拟一个完整的 ES6+ 环境,旨在用于应用程序而不是库/工具。
babel-polyfill
babel-polyfill 主要有两个缺点:
使用 babel-polyfill 会导致打出来的包非常大,很多其实没有用到,对资源来说是一种浪费。
babel-polyfill 可能会污染全局变量,给很多类的原型链上都作了修改,这就有不可控的因素存在。
因为上面两个问题,所以在 Babel7 中增加了 babel-preset-env,我们设置 "useBuiltIns":"usage" 这个参数值就可以实现按需加载 babel-polyfill。
Babel7
babel-preset-env
"useBuiltIns":"usage"
如果两个转换插件都将处理“程序(Program)”的某个代码片段,则将根据转换插件或 preset 的排列顺序依次执行。
例如:
{ "plugins": [ "@babel/plugin-proposal-class-properties", "@babel/plugin-syntax-dynamic-import" ] }
先执行 @babel/plugin-proposal-class-properties,后执行 @babel/plugin-syntax-dynamic-import
@babel/plugin-proposal-class-properties
@babel/plugin-syntax-dynamic-import
{ "presets": ["@babel/preset-env", "@babel/preset-react"] }
preset 的执行顺序是颠倒的,先执行 @babel/preset-react, 后执行 @babel/preset-env。
@babel/preset-react
插件和 preset 都可以接受参数,参数由插件名和参数对象组成一个数组。preset 设置参数也是这种格式。
如:
{ "plugins": [["@babel/plugin-proposal-class-properties", { "loose": true }]] }
如果插件名称为 @babel/plugin-XXX,可以使用短名称 @babel/XXX :
@babel/plugin-XXX
@babel/XXX
{ "plugins": [ "@babel/transform-arrow-functions" // 同 "@babel/plugin-transform-arrow-functions" ] }
如果插件名称为 babel-plugin-XXX,可以使用短名称 XXX,该规则同样适用于带有 scope 的插件:
babel-plugin-XXX
XXX
scope
{ "plugins": [ "newPlugin", // 同"babel-plugin-newPlugin" "@scp/myPlugin" // 同 "@scp/babel-plugin-myPlugin" ] }
可以简单的返回一个插件数组
module.exports = function () { return { plugins: ["A", "B", "C"], }; };
preset 中也可以包含其他的 preset,以及带有参数的插件。
module.exports = function () { return { presets: [require("@babel/preset-env")], plugins: [ [require("@babel/plugin-proposal-class-properties"), { loose: true }], require("@babel/plugin-proposal-object-rest-spread"), ], }; };
{ "presets": [ [ "@babel/preset-env", { "modules": false, "useBuiltIns": "usage", "corejs": { "version": 3, "proposals": true } } ] ] }
{ "presets": [ [ "@babel/env", { "modules": false } ] ], "plugins": [ [ "@babel/plugin-transform-runtime", { "corejs": { "version": 3, "proposals": true }, "useESModules": true } ] ] }
注意,这里需要配置一下 corejs 的版本号,不配置编译的时候会报警告。 useBuiltIns 的机构参数:
import ' @babel/polyfill'
The text was updated successfully, but these errors were encountered:
No branches or pull requests
什么是 Babel
Babel 是一个 JavaScript 编译器,用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前版本和旧版本的浏览器或其他环境中。简单来说 Babel 的工作就是:
Polyfill
的方式在目标环境中添加缺失的特性(@babel/polyfill
模块)Babel 三个编译阶段
Babel 的编译过程和大多数其他语言的编译器相似,可以分为三个阶段:
Babel 常用 API
@babel/core
Babel
的编译器,核心 API 都在这里面,比如常见的transform
、parse
。@babel/cli
cli
是命令行工具, 安装了@babel/cli
就能够在命令行中使用babel
命令来编译文件。当然我们一般不会用到,打包工具已经帮我们做好了。@babel/node
直接在
node
环境中,运行ES6
的代码babylon
Babel
的解析器babel-traverse
用于对 AST 的遍历,维护了整棵树的状态,并且负责替换、移除和添加节点。
babel-types
用于 AST 节点的 Lodash 式工具库, 它包含了构造、验证以及变换 AST 节点的方法,对编写处理 AST 逻辑非常有用。
babel-generator
Babel
的代码生成器,它读取 AST 并将其转换为代码和源码映射(sourcemaps)插件 Plugins
Babel
构建在插件之上,使用现有的或者自己编写的插件可以组成一个转换通道,Babel
的插件分为两种: 语法插件和转换插件。语法插件
这些插件只允许 Babel 解析(parse) 特定类型的语法(不是转换),可以在 AST 转换时使用,以支持解析新语法,例如:
转换插件
转换插件会启用相应的语法插件(因此不需要同时指定这两种插件),这点很容易理解,如果不启用相应的语法插件,意味着无法解析,连解析都不能解析,又何谈转换呢?
@babel/plugin-transform-runtime
预设 Preset
我们假设 ES6 有 10 个新特性,那为了把 ES6 转换成 ES5 就需要安装 10 个转换插件,配置文件很长不说,npm install 的时间也会很长。为了解决这个问题,babel 还提供了一组插件的集合,就叫 presets。
通过使用或创建一个
preset
即可轻松使用一组插件。presets 是这么分类的
官方
Preset
:@babel/preset-env
@babel/preset-env
主要作用是对我们所使用的并且目标浏览器中缺失的功能进行代码转换和加载polyfill
,在不进行任何配置的情况下,@babel/preset-env
所包含的插件将支持所有最新的 JS 特性(ES2015,ES2016 等,不包含 stage 阶段),将其转换成 ES5 代码。例如,如果你的代码中使用了可选链(目前,仍在 stage 阶段),那么只配置@babel/preset-env
,转换时会抛出错误,需要另外安装相应的插件。需要说明的是,
@babel/preset-env
会根据你配置的目标环境,生成插件列表来编译。对于基于浏览器或 Electron 的项目,官方推荐使用.browserslistrc
文件来指定目标环境。默认情况下,如果你没有在Babel
配置文件中(如.babelrc
)设置targets
或ignoreBrowserslistConfig
,@babel/preset-env
会使用browserslist
配置源。Polyfill
babel
对一些新的 API 是无法转换,比如Generator
、Set
、Proxy
、Promise
等全局对象,以及新增的一些方法:includes
、Array.form
等。所以这个时候就需要一些工具来为浏览器做这个兼容。babel-polyfill
主要有两个缺点:使用
babel-polyfill
会导致打出来的包非常大,很多其实没有用到,对资源来说是一种浪费。babel-polyfill
可能会污染全局变量,给很多类的原型链上都作了修改,这就有不可控的因素存在。因为上面两个问题,所以在
Babel7
中增加了babel-preset-env
,我们设置"useBuiltIns":"usage"
这个参数值就可以实现按需加载babel-polyfill
。插件/预设补充知识
顺序
如果两个转换插件都将处理“程序(Program)”的某个代码片段,则将根据转换插件或
preset
的排列顺序依次执行。例如:
先执行
@babel/plugin-proposal-class-properties
,后执行@babel/plugin-syntax-dynamic-import
preset
的执行顺序是颠倒的,先执行@babel/preset-react
, 后执行@babel/preset-env
。插件参数
插件和
preset
都可以接受参数,参数由插件名和参数对象组成一个数组。preset
设置参数也是这种格式。如:
插件的短名称
如果插件名称为
@babel/plugin-XXX
,可以使用短名称@babel/XXX
:如果插件名称为
babel-plugin-XXX
,可以使用短名称XXX
,该规则同样适用于带有scope
的插件:创建 Preset
可以简单的返回一个插件数组
preset 中也可以包含其他的 preset,以及带有参数的插件。
最佳实践
注意,这里需要配置一下 corejs 的版本号,不配置编译的时候会报警告。
useBuiltIns 的机构参数:
import ' @babel/polyfill'
参考资料
The text was updated successfully, but these errors were encountered: