从@babel/preset-env谈多浏览支持构建

@babel/preset-env谈多浏览支持构建

最近需要把一个在特定浏览器环境运行的Web应用移植到多浏览器,特别是要支持部分IE浏览器。项目打包完成,在IE 11下运行,并不能成功,提示Map()未定义。很显然,IE浏览器并不支持ES6语法,而在构建中也没有使用相应的填补

在基于Webpack + Babel构建的应用中,我们一般会使用到@babel/preset-env这个包,它使用了各种工具转译我们编写的ES6代码,我们一般这么使用它:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// .babelrc
{
"presets": ["@babel/preset-env"]
}
// 或
// webpack.config.js
{
...
module: {
rules: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
options: {
presets: [
"@babel/preset-env"
]
}
}
]
}
...
}

不做额外配置的情况下,@babel/preset-env并不知道哪些ES6+的语法需要转译,所以最终的结果就是并没有转译。

@babel/preset-envtargets属性

为了兼容多浏览器,我们需要告知哪些应用构件时需要支持哪些浏览器,@babel/preset-env提供了targets属性进行配置,例如为IE 10构建,可以这样配置:

1
2
3
{
targets: "ie 10"
}

我们可以使用browserslist包来指定构建的目标浏览器,可以在.browserslistrc或是package.json中进行配置:

1
2
3
4
5
6
"browserslist": [
">0.2%",
"not dead",
"not ie <= 10",
"not op_mini all"
],

上面的配置中包含4条查询语句,>0.2%表示大于0.2%的市场份额,not dead表示近24个月还在支持的浏览器,所有查询语句见npm

配置完成后,可以运行npx browserslist查看具体支持的浏览器版本。

必不可少的useBuiltIns属性

设置browserslist后构建的代码仍然不能很好的运行,这是因为项目中并没有加入polyfill,并且也未告知@babel/preset-env该如何处理pliyfilluseBuiltIns正是用来解决这一问题。

1
useBuiltIns: false | "entry" | "usage"

useBuiltIns设置为"entry" | "usage"的时候,@babel/preset-env将会使用core-js提供的填补。

"entry"的意思就是,当我们在某个文件中import 'core-js'但是该文件中只使用了到了ES6中的String.prototype.padStart方法,那么就上一句import就会在构建的时候被替换成import 'core-js/modules/es.string.pad-start'

"usage"的作用同其字面意义,即为:按需加载。如果我们在某个文件中使用了Map,如果构建目标支持Map,那么就不会使用相应填补,否则会在构建时加上import 'core-js/modules/es.map'

现在设置useBuiltIns: "usage"

core-js及其使用

core-js是一个ES6+语法的polyfill,简单而言就是使用ES3的语法实现了到目前为止几乎所有ES新特性。并且可以按需加载且不会污染全局命名空间。

core-js2.x3.x两个版本,其区别就是2.x不支持目前最新的语法,这里可以按需选择2.x或者3.x版本安装。

安装core-js

1
yarn add core-js

使用core-js的需要注意的是该包需要在入口文件顶部导入,因为只有这样填补才会被完全用到。
对已使用webpack构建的项目可以在config中在入口中引入:

1
entry: ['core-js/stable', 'index.js']

也可以在入口文件(一般为src/index.js)的顶部引入:

1
2
// index.js
import 'core-js/stable'

引入完毕,再进行构建,不出意外已经能够在指定版本的浏览器中运行了。

其它

ES6+语法的多浏览器兼容的确告一段落了,但是浏览器APICSS兼容还有很多问题,浏览器兼容才刚刚开始。

比如,IE并不支持fetch API,所以要么我们需要一个polyfill,要么就修改业务代码。

1
yarn add whatwg-fetch

然后在入口文件中引入,

1
import 'whatwg-fetch';

某些CSS3支持得也不够好,需要我们一个个去考虑。

兼容性是前端开发无法规避的问题,而解决兼容的过程是”痛苦的”,特别是当业务开发完成后才考虑兼容的问题,痛苦加倍。

痛苦并快乐着。

完。

分享到 评论