刚接触bable的同学会犯一个错误,认为在使用了Babel后就可以畅快的使用 es2015 了,事实上Babel只能转换语法(如箭头函数、let、const、class等),像Promise 、Async、Object.assign、Array.find()等api是依赖浏览器实现的,想在不支持的浏览器上使用新的API,需要采用Polyfill技术,实现Polyfill有多种方式,方式对比请点我。
Babel 推荐使用 @babel/preset-env 套件来处理转译需求。顾名思义,preset 即“预制套件”,包含了各种可能用到的转译工具。之前的以年份为准的 preset 已经废弃了,现在统一用这个总包。同时,babel 已经放弃开发 stage-* 包,以后的转译组件都只会放进 preset-env 包里。
一、重要参数
1. target
@babel/preset-env 支持一些参数,用来处理哪些 feature 要转译,哪些不要。其中比较重要的是 targets
,用来指定目标环境。targets
使用 browserslist 来筛选浏环境,这样我们就不需要指定所有浏览器版本,而可以使用类似 last 2 versions
这样的描述。具体怎写,可以看文档,这里不再赘述。
如果你想知道自己配置的是否合适,可以在仓库目录下执行 npx browserslist
,列出所有目标浏览器。
Babel 官方建议我们把 targets
写到 .browserslistrc
或者 package.json
里,不然除了babel外,其他的工具,例如browserslist等无法从 .babelrc
等 babel 配置文件里读取配置。
2. useBuiltIns
接下来,我们可以配置 useBuiltIns
,这个属性决定是否引入 polyfill。它有三个可选值:
false
,不引入,或者说,Babel 编译结果不引入。把引入的位置、引入哪些 polyfill 交给用户处理。
entry, 开发者
在核心入口文件中使用 import '@babel/polyfill'
语句引入,其实并不理想,因为大部分浏览器不需要这些。
usage,
即“按需引用”。如果目标浏览器(从target中知道目标浏览器)不支持需要的 feature,那么就自动引入 polyfill,不然的话就不引用。由于目前的打包工具越发智能,随着 tree shaking 的完善,这样可以最低限度引入 polyfill。
3. corejs
core-js 目前最新版本是 3.0.1,关于 v3 和 v2 的对比,大家可以看这篇博文:https://github.com/zloirock/core-js/blob/master/docs/2019-03-19-core-js-3-babel-and-a-look-into-the-future.md。这里简单总结一下,core-js 2 封版于 1.5 年之前,所以里面只有对 1.5 年之前 feature 的 polyfill,最近 1.5 年新增的 feature 都不支持,也就存在因为新功能没有 polyfill 于是在旧浏览器里失败的风险。
所以我们应当升级到最新版,npm i core-js@3 -D
然后修改 babel 配置:
{ "presets": [ [ "@babel/preset-env", { "targets": "> 5%", "useBuiltIns": "usage", "corejs": 3 } ] ] }
此选项仅在与useBuiltIns:usage或useBuiltIns:entry一起使用时有效,并确保@babel/preset env为您的核心js版本注入正确的导入。
默认情况下,corejs只会使用已确定的ECMAScript进行polyfill:如果要使用stage-1(proposal)的polyfill,有三个不同的选项 :
当使用useBuiltIns:“entry”时,可以直接导入一个建议polyfill:import“core js/propositions/string replace all”。
使用useBuiltIns:"usage"时:“用法”有两种不同的选择:
将shippedprovals选项设置为true。这将使polyfills和proposition转换成为可能,这些建议已经在浏览器中发布了一段时间。
使用corejs:{version:3,propositions:true}。这将使核心js支持的每一个提案都能实现多元化。
备注: TC39 将提案分为以下几个阶段:
- Stage 0 - 设想(Strawman):只是一个想法,可能有 Babel插件。
- Stage 1 - 建议(Proposal):这是值得跟进的。
- Stage 2 - 草案(Draft):初始规范。
- Stage 3 - 候选(Candidate):完成规范并在浏览器上初步实现。
- Stage 4 - 完成(Finished):将添加到下一个年度版本发布中。
有关详细信息,请务必查看 current TC39 proposals 及其 process document。
TC39 各阶段的流程也在一些文章中有详细的解释,在 Yehuda Katz (@wycatz) 的 thefeedbackloop.xyz网站上:Stage 0 and 1、Stage 2、Stage 3
二、@babel/polyfill
@babel/polyfill 是对 core-js 的封装,引入该库时,实际上是引用了 core-js 的内容和生成器(regenerator-runtime)。 v7.4 之后,这个仓库就被废弃了,希要用户自己选择使用哪个兼容库。
换言之,以前是这么引用的:
import "@babel/polyfill";
现在需要:
import "core-js/stable";
import "regenerator-runtime/runtime";
对于绝大部分情况,使用 @babel/preset-env + useBuiltIns: 'usage'
仍然是最好的选择。