segmentfault.com/a/119000002… (@babel/preset-env 与@babel/plugin-transform-runtime 使用及场景区别)
babel
www.babeljs.cn/docs/ babel7
Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法, 可以使之运行在当前和旧版本的浏览器或其他环境中。
Plugin 实现 "转换"
- transform-es2015-template-literals : 转译模版字符串的 plugin
preset: babel 插件集合的预设,包含某些插件 plugin。显然像上面那样一个一个配置插件会非常的麻烦,为了方便,babel 为我们提供了一个配置项叫做 persets(预设)。
preset 命名: env --> babel-preset-env
☆ ☆ lugins 与 presets 同时存在的执行顺序
先执行 plugins 的配置项,再执行 Preset 的配置项 ;
- plugins 配置项,按照声明顺序执行;
- Preset 配置项,按照声明逆序执行。 ** 列入以下代码的执行顺序为:**
// .babelrc 文件
{
"plugins": [
"transform-es2015-template-literals" // 转译模版字符串的 plugins
],
"presets": ["env", "stage-2"]
}
transform-es2015-template-literals > stage-2 > env
balel-preset-env
根据目标环境选择不支持的新特性来转译(有的环境支持的话就不用转码了)。
"babel": {
"presets": [
[
"env",
{
"targets": {
"browsers": ["last 2 versions", "ie >= 7"]
}
}
]
]
},
配置
modules : 将ES6模块语法转换为另一种模块类型,可选值:
各种流行的模块化规范:"amd"、 "commonjs"、 "systemjs"、 "umd" 禁止转译:false
useBuiltIns (boolean, 默认值: false)
babel为标准库中的新功能提供了polyfill,为内置对象,静态方法,实例方法,生成器函数提供支持。 babel-preset-env可以实现基于特定环境引入需要的polyfill。 (polyfill是个大的包,里面有很多小包,env可以按需加载需要的部分)
useBuiltIns “usage” | “entry” | false, defaults to false.
This option adds direct references to the core-js module as bare imports. Thus core-js will be resolved relative to the file itself and needs to be accessible. You may need to specify core-js@2 as a top level dependency in your application if there isn’t a core-js dependency or there are multiple versions.
useBuiltIns: 'usage'
Adds specific imports for polyfills when they are used in each file. We take advantage of the fact that a bundler will load the same polyfill only once.
和@babel/preset-env 一起用的时候 When used alongside @babel/preset-env,
-
If useBuiltIns: 'usage' is specified in .babelrc then do not include @babel/polyfill in either webpack.config.js entry array nor source. Note, @babel/polyfill still needs to be installed.
-
If useBuiltIns: 'entry' is specified in .babelrc then include @babel/polyfill at the top of the entry point to your application via require or import as discussed above.
-
If useBuiltIns key is not specified or it is explicitly set with useBuiltIns: false in your .babelrc, add @babel/polyfill directly to the entry array in your webpack.config.js.
1. 如果在.babelrc 中指定 useBuiltIns: 'usage'的话,那么就不要在webpack.config.js 的 entry array 和source 中包含 @babel/polyfill 了。注意,@babel/polyfill 依然需要安装 (按需加载)
1. 如果在.babelrc 中指定 useBuiltIns: 'entry'的话,那么就在你应用的入口文件顶部通过require 或者 import 引入@babel/polyfill (此种方式是错误的, 应该要通过env来自动加载polyfill )
- 如果在.babelrc 中没有指定 useBuiltIns 的值为 false. 可以直接在webpack.config.js 的 entry array 中添加 @babel/polyfill
module.exports = {
entry: ['@babel/polyfill', './app']
}
在.babelrc配置了"useBuiltIns": "usage"后,Babel 会在你使用到 ES2015+ 新特性时,自动添加 babel-polyfill 的引用,并且是 partial 级别的引用。按我的理解按需引入。。。
babel-polyfill
"version": "6.26.0",
"dependencies": {
"babel-runtime": "^6.26.0",
"core-js": "^2.5.7",
"regenerator-runtime": "^0.12.0"
}
regenerator-runtime 是什么?能做什么?
www.iteye.com/blog/schifr… [源码分析]
@babel/polyfill (自babel7.4 后就 deprecated, polyfill的历史结束了)
"dependencies": {
"core-js": "^2.6.5",#这里可以看出来 最新的@babel/polyfill 也不支持core-js@3
"regenerator-runtime": "^0.13.4"
}
☆ ☆ ☆ ☆ 一个正确的配置 不用安装@babel/polyfill
//
"babel": {
"presets": [
[
"@babel/preset-env",
{
"modules": false, // 对ES6的模块文件不做转化,以便使用tree shaking、sideEffects等
"targets": {
"browsers": [
"> 1%",
"last 2 versions",
"not ie <= 8"
]
},
"useBuiltIns": "usage", //按需加载
"corejs": 3
}
]
],
"plugins": [
"transform-vue-jsx"
]
}
三种方案对比
| 方案 | 优点 | 缺点 |
|---|---|---|
| @babel/runtime & @babel/plugin-transform-runtime | 按需引入, 打包体积小 | 不能兼容实例方法 |
| @babel/polyfill | 完整模拟 ES2015+ 环境 | 打包体积过大、污染全局对象和内置的对象原型 |
| @babel/preset-env | 按需引入, 可配置性高 | 不支持 stage-x 插件,没有利用针对特定浏览器的功能 |
babel-runtime
const key = 'babel'
const obj = {
[key]: 'polyfill',
}
==>
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
} else {
obj[key] = value;
}
return obj;
}
var key = 'babel';
var obj = _defineProperty({}, key, Object.assign({}, { key: 'polyfill' }));
babel-polyfill解决了Babel不转换新API的问题,但是直接在代码中插入帮助函数,会导致污染了全局环境,并且不同的代码文件中包含重复的代码,导致编译后的代码体积变大。 (比如:上述的帮助函数_defineProperty有可能在很多的代码模块文件中都会被插入)
Babel为了解决这个问题,提供了单独的包babel-runtime用以提供编译模块的工具函数, 启用插件babel-plugin-transform-runtime后,Babel就会使用babel-runtime下的工具函数,上述的代码就会变成这样
var _defineProperty2 = __webpack_require__("./node_modules/babel-runtime/helpers/defineProperty.js");
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _assign = __webpack_require__("./node_modules/babel-runtime/core-js/object/assign.js");
var _assign2 = _interopRequireDefault(_assign);
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : { default: obj };
}
var key = 'babel';
var obj = (0, _defineProperty3.default)(
{}, key, (0, _assign2.default)({}, { key: 'polyfill' })
);
可以看到上述转换后的代码中_defineProperty帮助函数是通过babel-runtime下的模块引用的, 同时Object.assign也变成了模块引用, 这样可以避免自行引入polyfill时导致的污染全局命名空间的问
TODO ? @babel/runtime和@babel/plugin-transform-runtime 区别?
core-js
core-js 是babel-polyfill 的底层依赖,通过各种奇技淫巧,用 ES3 实现了大部分的 ES2017 原生标准库,同时还要严格遵循规范。
提供了es5、es6的polyfills,包括promises、symbols、collections、iterators、typed arrays、ECMAScript 7+ proposals、setImmediate 等等。 如果使用了 babel-runtime、babel-plugin-transform-runtime 或者 babel-polyfill,你就可以间接的引入了 core-js 标准库
blog.meathill.com/js/some-tip…
core-js 2 封版于 1.5 年之前,所以里面只有对 1.5 年之前 feature 的 polyfill,最近 1.5 年新增的 feature 都不支持,也就存在因为新功能没有 polyfill 于是在旧浏览器里失败的风险。
Stable ECMAScript features
Stable ECMAScript features had already been almost completely supported by core-js for a long time, however, core-js@3 introduced some new features:
- Added support of @@isConcatSpreadable and @@species well-known symbols, introduced in ECMAScript 2015, to all the methods which use them.
- Added Array.prototype.flat and Array.prototype.flatMap methods from ECMAScript 2018 (core-js@2 provided a polyfill for an old version of this proposal with Array.prototype.flatten).
- Added Object.fromEntries method, introduced in ECMAScript 2019.
- Added Symbol.prototype.description accessor, introduced ECMAScript 2019.
Some features that have already been available for a long time as proposals have been accepted in ES2016-ES2019 and are now marked as stable:
-
Array.prototype.includes and %TypedArray%.prototype.includes methods (ECMAScript 2016)
-
Object.values and Object.entries methods (ECMAScript 2017)
-
Object.getOwnPropertyDescriptors method (ECMAScript 2017)
-
String.prototype.padStart and String.prototype.padEnd methods (ECMAScript 2017)
-
Promise.prototype.finally method (ECMAScript 2018)
-
Symbol.asyncIterator well-known symbol (ECMAScript 2018)
-
Object.prototype._ _ define(Getter|Setter) _ _ and Object.prototype._ _ lookup(Getter|Setter) _ _ methods (ECMAScript 2018)
-
String.prototype.trim(Start|End|Left|Right) methods (ECMAScript 2019)
-
Added many fixes for browsers bugs/issues. For example, Safari 12.0 Array.prototype.reverse bug has been fixed.