babel6和babel7中关 polyfill和preset-env和babel-plugin-transform-runtime等总结

记录自己零散的收获,随笔。

一些基础

  1. babel的作用是转换JS新的特性代码为大部分浏览器能运行的代码。

  2. babel转码又分为两部分,一个是语法转换,一个是新API转换。

  3. 对于API的转换又分为两部分,一个是可私有的API,一个全局对象的实例(Array.prototype.includes之类的方法)和Object.assign之类的静态方法。

  4. babel代码转换依赖plugin,没有plugin的情况下babel做的事情只是 code => code

  5. plugin 有很多,一个个导入又特别麻烦,这时候我们又知道了preset。

preset是很多plugin的集合,配置如下:

.babelrc文件

{
  "presets": ["env"]
}

如果preset-env是有配置项的:

{
  "presets": [
    [
      "env",
      {
        // 这里就是配置项
      }
    ]
  ]
}

可以观察出如果某个preset需要配置可以将字符串换成一个数组,第一项是preset的name,第二项就是opetions。plugin同preset。

注:preset是从右往左执行,plugin是从左往右执行,并且plugin先于preset执行。

扫描二维码关注公众号,回复: 10542621 查看本文章

babel6到babel7的升级是具有破坏性的,主要总结下polyfill的用法和在babel6和babel7中的不同。

babel-polyfill

上面说到babel主要做两件事,一个是转换语法,一个是兼容新的API。

babel-polyfill 的作用是兼容新的API。

babel6

据我所知,在babel6中使用polyfill有四种方法:

  1. 直接引入(影响全局,一劳永逸)

    在入口文件中 import 'babel-polyfill' / require('babel-polyfill')。使用webpack的话也可以在entry中添加 entry: ['babel-polyfill', 'src/index.js']

    优点:
    一次引入,全局使用。
    会转换实例方法和静态方法,比较全面。

    缺点:
    影响全局作用域。
    打出来的包比较大,不管用没用到都打进去了。

    使用场景:
    开发业务项目,比较全面,不会漏了从而出问题,比如Object.assign这样的方法在ios8上面还是需要polyfill的。

  2. 在babel-runtime中单独引入

    和直接在入口引入polyfill不同,该插件引入的polyfill是模块私有的。
    对于需要的polyfill需要手动引入,import Promise from 'babel-runtime/core-js/promise'

    优点:
    该模块私有,不会影响到全局作用域。
    打出来的包因为按需引入包不会很大。

    缺点:
    因为不影响全局作用域,所以不会转实例和静态方法这样的API。
    手动引入所需,搞不好会漏掉。

    使用场景:
    开发库,框架之类可以使用,因为别人用你的东西然后不知情的情况下你改了别人的全局环境,然后出错了就尴尬了。

  3. 使用babel-plugin-transform-runtime按需引入

    这个插件可不简单,有好几个功能:

    1. 和插件babel-runtime一样引入的polyfill是私有的,不会影响全局作用域。并且是自动按需引 入需要的polyfill,不需要想babel-runtime一样一个一个手动引入。
    2. 可以提取语法转换时候每个模块都生成的各种helper,成一个引用。
    3. 自动转换generators/async。

    优点:
    该模块私有,不会影响到全局作用域。
    打出来的包因为按需引入包不会很大。
    自动按需引入,不需要手动,防止遗漏。
    提取helper,大大减少冗余代码。

    缺点:
    因为不影响全局作用域,所以不会转实例和静态方法这样的API。

    使用场景:
    同babel-runtime。

    注:该插件依赖babel-runtime。

  4. 在babel-preset-env中设置配置项

{
   "presets": [
   	[
   		"env", 
   		{
   			"useBuiltIns": boolean
   		}
   	]
   ]
}

useBuiltIns 选项是为了分割入口的 import 'babel-polyfill' / require(babel-polyfill)成按环境引入polyfill。该方式同第一中引入polyfill的方式,但是会按照配置的环境去按需引入,稍微好点。

小结:
1. babel6的核心有 babel-core babel-cli babel-node babel-register babel-polyfill,这些在babel7会有所修改。
2. polyfill 是依赖core-js的
3. babel7.4放弃了@babel/polyfill直接依赖core-js@2或者3。

babel-plugin-transform-runtime的配置项

{
  "helpers": false, // defaults to true
  "polyfill": false, // defaults to true
  "regenerator": true, // defaults to true
  "moduleName": "babel-runtime" // defaults to "babel-runtime"
}

对于polyfill的自动处理和helper的提取都是依赖babel-runtime完成的,所以该插件依赖babel-runtime。

polyfill例子

input:

var promise = new Promise;

output:

var _promise = require("babel-runtime/core-js/promise");  // 注意这里,根本是从core-js里面引入的
 
var _promise2 = _interopRequireDefault(_promise);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var promise = new _promise2.default();

helper的例子:

input:

class Person {}

usually turns into:

"use strict";
 // 这就是helper函数,每个模块都会被实现一遍,十分浪费,冗余。
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
var Person = function Person() {
  _classCallCheck(this, Person);
};

通过runtime转一下:

"use strict";
 
var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); // 从runtime中引入,没有再实现一遍
 
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
 
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
var Person = function Person() {
  (0, _classCallCheck3.default)(this, Person);
};

generator同样是 require("babel-runtime/regenerator");引入的。

babel7

babel7进行了较大的改动,废弃了 stage-x的preset,还增加了命名空间区分官方插件和非官方插件,@babel/core,@babel/cli等。

建议使用@babel/preset-env 。

@babel/plugin-transform-runtime

该插件的引入主要有两个作用

在babel7中,原先的插件babel-plugin-transform-runtime也做了修改 -> @babel/plugin-transform-runtime。并且在功能上也变强大了。

移除了polyfill的配置项添,加了corejs配置项(默认情况是polyfill)。

.babelrc配置:

{
  plugins: [
    ["@babel/plugin-transform-runtime", {
      "absoluteRuntime": false, // 不是很清除干啥的
      "corejs": false, // 下面详解
      "helpers": true, // 助手函数是否提取,同babel-plugin-transform
      "regenerator": true, // 同babel-plugin-transform
      "useESModules": false
    }]
  ]
}

对于配置项 corejs: false | 2 | 3

false 依赖 @babel/runtime,其实和配置Polyfill一样,是默认选项。
2 依赖@babel/runtime-corejs2
3 依赖@babel/runtime-corejs3

corejs2和corejs3还是有很大区别的。corejs2只转换全局变量(Object)和静态方法(Object.assign),并不转换原型上的方法(Array.prototype.includes),corejs3会转换原型上的方法。

注意transform-runtime这个插件添加的polyfill都是私有的,不会影响到全局环境,而且还是按需引入,非常nice。

小结:
@babel/plugin-transform-runtime主要有三个作用:
- 当使用 generators/async的时候自动引入 @babel/runtime/regenerator
- 为新特性的API添加实现。
- 提取每个模块内联的helper们问引用。

@babel/preset-env

除了上面说的 @babel/plugin-transform-runtime插件,还想记录下 @babel/preset-env关于polyfill的改变。

这个preset在babel6的时候就承担了很多功能,本文只记录和polyfill相关的配置,useBuiltInscorejs

useBuiltIns

在babel-preset-env的配置项中是一个boolean值,在@babel/preset-env的时候则扩展了几个选项 "useage""entry"

默认值是false,表示不会自动引入polyfills,并且不会处理 import “@babel/polyfill” 和 import “corejs”。

注:babel7.4会放弃 @babel/polyfill,所以建议直接使用 corejs

entry

和babel-preset-env的选项true一样会自动按环境需求分割引入polyfill。注意只能在入口引入一次,多次会报错。

需要在入口文件有 import "core-js/stable"import "regenerator-runtime/runtime"

usage

按需引入,会造成全局污染。在我的理解中这个选项只是entry的一种增强,不需要在入口手动引入一次,并且可以按照使用特性多少按需引入。

corejs

值:2, 3 或者 { version: 2 | 3, proposals: boolean }, 默认是 2.

这是新加的一个配置项。该选项只会在 useBuiltIns选项为 usage或者 entry并且 @babel/preset-env正确导入对应的corejs版本的情况下起作用。

默认情况下只会注入稳定功能的 ECMAScript 特性。有三个特性可以修改:

  • 当时用配置 useBuiltIns: "entry"可以直接导入提案 import "core-js/proposals/string-replace-all"
  • 当时用 useBuiltIns: usage 的时候又有两个可选:
    • 将shippedProposals(@babel/preset-env的另一个配置项)选项设置为true。这将启用已在浏览器中提供一段时间的提议的polyfill和转换。
    • 使用 corejs: {version:3,proposal:true}。这样可以实现对core-js支持的每个提案的填充。

参考

babel官网@babel/plugin-transform-runtime
npm->babel-plugin-transform-runtime
babel到底该如何配置?
babel手册
Babel是一个JavaScript编译器
babel7简单升级

发布了48 篇原创文章 · 获赞 52 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/letterTiger/article/details/100717666