babel-polyfill与transform-runtime
概念
babel-polyfill是一个工具库吗?可以这么辅助理解,但它不仅仅是一个工具库,它存在的意义甚于工具。
它的作用是为应用提供es2015+
的运行环境,注入式的hack重写了原生方法。
transform-runtime是一个babel插件(babel-plugin-transform-runtime
),它的作用和polyfill类似,但它不会注入式的hack,而是重命名实现这个方法。另外,它所重写的方法是有限的,不是所有的es2015+方法都重写。
实践分析
1.transform-runtime
查看该插件源码后你会发现它的本质是babel-runtime
。我们用vue的会发现,初始化项目时,.babelrc
中默认带上了插件"transform-vue-jsx", "transform-runtime"
,查看文档你会发现transform-runtime
是支持传递options的
"helpers": true,
"polyfill": true,
"regenerator": true,
"moduleName": "babel-runtime"
细心的你肯定发现了该选项中也包含了polyfill,还有helpers,regenerator。这些默认都是true,那作用如何呢?
我们在概念中提到它是不会重写覆盖原生方法的,举个例子:我们在代码中使用Promise,打包后如下:
// 打包前
created() {
new Promise()
}
// 打包后
created: function created() {
new promise_default.a();
}
关于promise_default
// EXTERNAL MODULE: ./node_modules/babel-runtime/core-js/promise.js
var promise = __webpack_require__("//Fk");
var promise_default = /*#__PURE__*/__webpack_require__.n(promise);
我们会发现它引用自core-js,好了打住。我们知道polyfill的作用也是hack,那它与babel-polyfill
的区别是什么?
当我们查看网上的资料后都会发现:transform-runtime
只会提供对象静态的或全局的方法,不提供实例方法,例如Array.prototype.includes
。
我们需要再理解一层,也就是说transform-runtime
不会提供原型上的方法,我们可以利用obj.hasOwnProperty(pro)
来检测该方法是否为对象自身属性。
Array.hasOwnProperty('find') // false
Array.hasOwnProperty('true') // true
这样就好理解了,当我们开启polyfill: true
这个选项时,就知道哪些方法可以直接使用而不用引用babel-polyfill
了。
关于regenerator,我用的最多的是async await
了,它的作用是实现 generators、yield、async 及 await 等相关的 polyfills。
关于helpers,是babel内部自身用到的工具方法,设置为helpers: true
时,就会统一的去引用babel-runtime
里的方法,而不是在每个文件中都重写一遍工具方法,举例:
// helpers为false,你会在每个文件中看到
var _typeof = typeof symbol_default.a === "function" && typeof ...
var _extends = assign_default.a || function (target) { for (var i = ...
// helpers为true
// EXTERNAL MODULE: ./node_modules/babel-runtime/helpers/typeof.js
var helpers_typeof = __webpack_require__("pFYg");
var typeof_default = /*#__PURE__*/__webpack_require__.n(helpers_typeof);
// EXTERNAL MODULE: ./node_modules/babel-runtime/helpers/extends.js
var helpers_extends = __webpack_require__("Dd8w");
var extends_default = /*#__PURE__*/__webpack_require__.n(helpers_extends);
2.babel-polyfill
能发挥它最大用处的用法是结合babel-preset-env
使用,结合使用后会根据.babelrc
里的
"targets": {
"browsers": ["iOS >= 7"]
},
按需引入,利用useBuiltIns
属性来决定是在入口处统一引入还是在使用的地方引入。
注意,当我们使用babel-polyfill后,肯定不需要再使用transform-runtime里的polyfill,我们应当置为false。
结合case来实践
case 1:useBuiltIns: false
,在任一文件引入import "babel-polyfill"
,打包后
// EXTERNAL MODULE: ./node_modules/babel-polyfill/lib/index.js
var lib = __webpack_require__("j1ja");
var lib_default = /*#__PURE__*/__webpack_require__.n(lib);
你会发现此处的引用变成内部引用的一个模块,名为j1ja
,然后我们找到这个模块
/***/ "j1ja":
/***/ (function(module, exports, __webpack_require__) {
"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
__webpack_require__("4M2W");
__webpack_require__("zkX4");
__webpack_require__("Wwne");
if (global._babelPolyfill) {
throw new Error("only one instance of babel-polyfill is allowed");
}
global._babelPolyfill = true;
// ....
我们会发现这个模块在vendor.js
中定义的。
case 2: useBuiltIns: true
,在任一文件引入import "babel-polyfill"
,打包后
// EXTERNAL MODULE: ./node_modules/core-js/modules/es6.typed.array-buffer.js
var es6_typed_array_buffer = __webpack_require__("9mmO");
var es6_typed_array_buffer_default = /*#__PURE__*/__webpack_require__.n(es6_typed_array_buffer);
// EXTERNAL MODULE: ./node_modules/core-js/modules/es6.typed.int8-array.js
var es6_typed_int8_array = __webpack_require__("52Wt");
var es6_typed_int8_array_default = /*#__PURE__*/__webpack_require__.n(es6_typed_int8_array);
会发现有很多模块在此处引入,我们查找下这个被引入的模块定义,同样也存在于vendor.js
中。
useBuiltIns的作用就是决定模块是否在使用处引入。
总结
我们会发现,他们都是对于core-js
的引入,只不过引入的多少与最终造成的结果不一样。
其实很多时候,我们也可以直接使用core-js
,我们查看repo地址https://github.com/zloirock/core-js#babelpolyfill
发现对于polyfill
与 babel-runtime
有单独的解释
babel-polyfill
是对于core-js
的引用,而babel-runtime
是对于core-js-pure
的引用。
其实很多时候更适合单独使用core-js
import 'core-js/features/array/from'; // <- at the top of your entry point
import 'core-js/features/array/flat'; // <- at the top of your entry point
import 'core-js/features/set'; // <- at the top of your entry point
import 'core-js/features/promise'; // <- at the top of your entry point
参考
https://github.com/zloirock/core-js
https://www.babeljs.cn/docs/usage/polyfill/
https://babeljs.io/docs/en/next/babel-polyfill.html
https://github.com/babel/babel-preset-env
https://zhuanlan.zhihu.com/p/29058936