史上最清晰易懂的babel配置解析
准备工作
- 新建文件夹
webpack-babel - 初始化
yarn init -y - 安装
webpackyarn add webpack webpack-cli -D - 安装
webpack插件yarn add -D html-webpack-plugin clean-webpack-pluginhtml-webpack-plugin用于自动生成index.html
clean-webpack-plugin用于每次打包时对上一次的dist文件进行清理,这两个插件跟babel没关系,只是这里用起来方便 - 安装
webpack-dev-server用于启动一个web服务yarn add -D webpack-dev-server - 新建
src及入口文件index.js,内容如下let ele = document.createElement("div") ele.innerHTML = "Hello world!" document.body.appendChild(ele) - 新建
webpack配置文件,内容如下const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { entry: { index: "./src/index.js" }, devServer: { port: 9998 }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title: '管理输出' }) ], } - 在
package.json中添加脚本"scripts": { "serve": "webpack-dev-server --config webpack.config.js", "build": "webpack" } - 跑一下试试
yarn serve

- 打个包试试
yarn build

babel 部分
准备工作就绪之后,开始 babel 相关的部分
-
安装相关包
yarn add -D babel-loader @babel/core @babel/preset-envbabel-loader 允许你使用 Babel 和 webpack 转译
JavaScript文件
@babel/core 用于转换新的语法
@babel/preset-env 用于配置哪些语法或 API 需要转换 -
首先修改
index.js内容let a = 1; console.log(a); const fn = () => { }; console.log(fn);这里使用了
ES6的let,和箭头函数 -
使用 Can I use 查询语法支持情况,红色是不支持
可以得知,在IE11上,这两种语法是都不支持的,实际运行的结果也是如此
报语法错误 -
修改
webpack.config.jsmodule: { rules: [ { test: /\.m?js$/, exclude: /(node_modules|bower_components)/, use: { loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { debug: true, targets: { browsers: ["ie >= 11"] } } ] ], } } } ] }, -
再跑一次
yarn serve

这证明语法已经转换成功,我们修改一下
webpack.config.js 的配置,将模式设置为 development,以便 yarn build 时看到的代码是未经压缩的。此外,关闭 sourcemap。
mode: "development", // 强制声明为 development 模式
devtool: "none" // 关闭 sourcemap
- 修改完后,打包
yarn build

如果我们把条件换成支持这两种语法的浏览器呢?
- 修改
webpack.config.js,chrome 60版本已经支持let和箭头函数,打包后代码 不应该 再被转换。browsers: ["chrome >= 60"] - 再次打包
yarn build

补充一下,如果开启了
debug,就可以在终端查看相关代码转换信息
开启 debug 后
-
换回之前的条件,继续调试
browsers: ["ie >= 11"] -
清空
index.js,将index.js的内容改为const fn = async () => { let r = await Promise.resolve(666) console.log(r) } fn() -
运行
yarn serve继续在ie11中查看
报错了 -
从报错可以看到,需要引入
regenerator-runtime。可以通过以下三种方式解决:
方法1:引入@babel/polyfill,注意是生产依赖yarn add @babel/polyfill引入
@babel/polyfill后,可以发现还引入了两个依赖,core-js和regenerator-runtime,而后者正是我们需要的
补充一下
@babel/core,core-js和regenerator-runtime的作用
| 名称 | 作用 |
|---|---|
| @babel/core | 处理新语法,比如 模板字符串,let,const,扩展运算符 等 |
| core-js | 处理新 API,比如 Promise,Set,Map,Object.assign 等 |
| regenerator-runtime | 处理 async,await,generator 等 |
以上内容可在开启 debug 后,在终端查看日志

在 index.js 中引入 @babel/polyfill,注意,是在所有代码最上面引入
import "@babel/polyfill"
运行
yarn serve

打包看一下
yarn build
一万多行。。

这是由于虽然我们只使用了
async,但是引入的是完整的 @babel/polyfill,等于把好多不用的 API 都引了进来,查看打包后的文件,可以看到
这时我们就可以使用
useBuiltIns 配置项了
presets: [
[
'@babel/preset-env',
{
debug: true,
targets: {
browsers: ["ie >= 11"]
},
useBuiltIns: "usage" // 看这里
}
]
]
再次打包,剩下 2000 多行,只保留了处理 async 的部分

再回头说一下这个 useBuiltIns 配置项,注意,是
@babel/preset-env 的 useBuiltIns
一共有三个值
| 值 | 作用 | 是否需要在入口文件引入 @babel/polyfill |
|---|---|---|
| false | 默认值,无脑引入完整的 polyfill
|
是 |
| entry | 引入 targets 中指定的浏览器版本所需的全部 polyfill
|
是 |
| usage | 引入代码中用到的并且是 targets 中指定的浏览器版本所需的 polyfill
|
否(安装还是需要安的,就是不需要在入口引入了) |
以上可以通过开启 debug 在控制台中查看


方法二:
首先移除 @babel/polyfill
yarn remove @babel/polyfill
安装@babel/plugin-transform-runtime,@babel/runtime
yarn add -D @babel/plugin-transform-runtime
yarn add @babel/runtime
安装 @babel/runtime 时可以发现只有 regenerator-runtime,没有 core-js,这就意味着 Promise,assign 不会被转译

安装完之后,修改一下
webpack.config.js 中 babel-loader 的部分配置
plugins: [
[
"@babel/plugin-transform-runtime"
]
]
运行一下

正如预期,由于缺少了
core-js 导致部 Promise,assign 不能被支持。如果希望被支持,则还需安装 @babel/polyfill
方法三:
先移除 @babel/runtime 再安装 @babel/runtime-corejs2
yarn remove @babel/runtime
yarn add @babel/runtime-corejs2

修改
webpack.config.js 中 babel-loader 配置项
module: {
rules: [
{
test: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'@babel/preset-env',
{
debug: true,
targets: {
browsers: ["ie >= 11"]
// browsers: ["chrome >= 60"]
},
useBuiltIns: "usage"
}
]
],
plugins: [
[
"@babel/plugin-transform-runtime",
{
"corejs": 2,
}
]
]
}
}
}
]
}
修改后,再次运行项目,又恢复了正常 Promise,async,Object.assign 均可以跑在 IE11 上了

- 直接引入
@babel/polyfill的方式和引入@babel/plugin-transform-runtime + @babel/runtime-corejs2的方式区别在于,前者会污染全局变量。
例如,如果使用@babel/polyfill的方式,在IE11控制台输入Promise会正常打印,而使用后面的方式,在IE11控制台中输入Promise则会提示未定义


- 补充一下,比如多个文件都使用了
class语法,语法转换时,会出现多个转换的帮助函数,使用@babel/plugin-transform-runtime用于将多个帮助函数合并为一个,此外,生产环境需要@babel/runtime配合






