先说两种方式的原理:

babel-polyfill 使用场景

Babel 默认只转换新的 JavaScript 语法,而不转换新的 API。例如,Iterator、Generator、Set、Maps、Proxy、Reflect、Symbol、Promise 等全局对象,以及一些定义在全局对象上的方法(比如 Object.assign)都不会转译。如果想使用这些新的对象和方法,必须使用 babel-polyfill,为当前环境提供一个垫片。它不会将代码编译成低版本的ECMAScript,他的原理是当运行环境中并没有实现的一些方法,babel-polyfill中会给做兼容

babel-runtime使用场景

将es6编译成es5去运行,前端可以使用es6的语法来写,最终浏览器上运行的是es5,Babel 转译后的代码要实现源代码同样的功能需要借助一些帮助函数,例如,{ [name]: 'JavaScript' } 转译后的代码如下所示

'use strict';
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 obj = _defineProperty({}, 'name', 'JavaScript');

类似上面的帮助函数 _defineProperty 可能会重复出现在一些模块里,导致编译后的代码体积变大。Babel 为了解决这个问题,提供了单独的包 babel-runtime 供编译模块复用工具函数。

启用插件 babel-plugin-transform-runtime 后,Babel 就会使用 babel-runtime 下的工具函数,转译代码如下:

'use strict';
// 之前的 _defineProperty 函数已经作为公共模块 `babel-runtime/helpers/defineProperty` 使用
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var obj = (0, _defineProperty3.default)({}, 'name', 'JavaScript');

除此之外,babel 还为源代码的非实例方法(Object.assign,实例方法是类似这样的 "foobar".includes("foo"))和 babel-runtime/helps 下的工具函数自动引用了 polyfill。这样可以避免污染全局命名空间,非常适合于 JavaScript 库和工具包的实现。例如 const obj = {}, Object.assign(obj, { age: 30 }); 转译后的代码如下所示:

'use strict';
// 使用了 core-js 提供的 assign
var _assign = require('babel-runtime/core-js/object/assign');
var _assign2 = _interopRequireDefault(_assign);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var obj = {};
(0, _assign2.default)(obj, {
  age: 30
});

优缺点:

babel-polyfill:通过向全局对象和内置对象的prototype上添加方法来实现,比如运行环境中不支持Array-prototype.find,引入polyfill,前端就可以放心的在代码里用es6的语法来写;但是这样会造成全局空间污染。比如像Array-prototype.find就不存在了,还会引起版本之前的冲突。不过即便是引入babel-polyfill,也不能全用,代码量比较大。

babel-runtime:不会污染全局对象和内置的对象原型。比如当前运行环境不支持promise,可以通过引入babel-runtime/core-js/promise来获取promise,或者通过babel-plugin-transform-runtime自动重写你的promise。但是它不会模拟内置对象原型上的方法,比如Array-prototype.find,就没法支持了,如果运行环境不支持es6,代码里又使用了find方法,就会出错,因为es5并没有这个方法。

transform-runtime只会对es6的语法进行转换,而不会对新api进行转换。
如果需要转换新api,就要引入babel-polyfill.

思考:babel-runtime 为什么适合 JavaScript 库和工具包的实现?

  1. 避免 babel 编译的工具函数在每个模块里重复出现,减小库和工具包的体积;

  2. 在没有使用 babel-runtime 之前,库和工具包一般不会直接引入 polyfill。否则像 Promise 这样的全局对象会污染全局命名空间,这就要求库的使用者自己提供 polyfill。这些 polyfill 一般在库和工具的使用说明中会提到,比如很多库都会有要求提供 es5 的 polyfill。在使用 babel-runtime 后,库和工具只要在 package.json 中增加依赖 babel-runtime,交给 babel-runtime 去引入 polyfill 就行了;

总结:

  1. 具体项目还是需要使用 babel-polyfill,只使用 babel-runtime 的话,实例方法不能正常工作(例如 "foobar".includes("foo"));

  2. JavaScript 库和工具可以使用 babel-runtime,在实际项目中使用这些库和工具,需要该项目本身提供 polyfill;

疑问:像 antd@2.x 这样的库使用了 babel-runtime,在实际项目中使用 antd@2.x,我们需要引入 babel-polyfill。但全部 polyfill 打包压缩下来也有 80kb 左右,其中很多 polyfill 是没有用到的,如何减少体积呢?手工一个个引入使用到的 polyfill,似乎维护成本太高!

babel-runtime和babel-polyfill两者区别优缺点的更多相关文章

  1. @babel/runtime 和 @babel/plugin-transform-runtime 两个的作用是什么

    Babel 最基础的功能就是将采用 ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中. 最基础的依赖包也就是 ...

  2. Install fail! Error: [@@babel/runtime/core-js/object/keys]

    1.Install fail! Error: [@@babel/runtime/core-js/object/keys] "@babel/runtime": "7.0.0 ...

  3. Error: Cannot find module '@babel/runtime/core-js/object/keys'(npm start报错)

    1.问题描述: 在npm start启动react项目的时候,会出现Cannot find module '@babel/runtime/core-js/object/keys'的报错: 打开:项目根 ...

  4. Module not found: Error: Can't resolve '@babel/runtime/helpers/classCallCheck' and Module not found: Error: Can't resolve '@babel/runtime/helpers/defineProperty'

    These two mistakes are really just one mistake, This is because the following file @babel/runtime ca ...

  5. Babel插件:@babel/plugin-transform-runtime

    一 概述 每个Babel编译后的脚本文件,都以导入的方式使用Babel的帮助函数,而不是每个文件都复制一份帮助函数的代码. 1 优点 (1)提高代码重用性,缩小编译后的代码体积. (2)防止污染全局作 ...

  6. 【Babel】293- 初学 Babel 工作原理

    戳蓝字「前端技术优选」关注我们哦! 前言 babel Babel 对于前端开发者来说应该是很熟悉了,日常开发中基本上是离不开它的. 已经9102了,我们已经能够熟练地使用 es2015+ 的语法.但是 ...

  7. SVN和Git 介绍,区别,优缺点以及适用范围

    SVN是Subversion的简称,是一个开放源代码的版本控制系统,支持大多数常见的操作系统.作为一个开源的版本控制系统,Subversion管理着随时间改变的数据.这些数据放置在一个中央资料档案库( ...

  8. OLEDB和ODBC的区别(优缺点)

    ODBC是一种连接数据库的开放标准,OLEDB(对象链接和嵌入数据库)位于ODBC层与应用程序之间. 在你的ASP页面里,ADO是位于OLEDB之上的应用程序. 你的ADO调用先被送到OLEDB,然后 ...

  9. xml与json的原理,区别,优缺点.

    1.定义介绍 (1).XML定义扩展标记语言 (Extensible Markup Language, XML) ,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据.定义数据类型,是一种允许 ...

随机推荐

  1. BZOJ 3160: 万径人踪灭 [fft manacher]

    3160: 万径人踪灭 题意:求一个序列有多少不连续的回文子序列 一开始zz了直接用\(2^{r_i}-1\) 总-回文子串 后者用manacher处理 前者,考虑回文有两种对称形式(以元素/缝隙作为 ...

  2. BZOJ 3963: [WF2011]MachineWorks [CDQ分治 斜率优化DP]

    传送门 当然了WF的题uva hdu上也有 你的公司获得了一个厂房N天的使用权和一笔启动资金,你打算在这N天里租借机器进行生产来获得收益.可以租借的机器有M台.每台机器有四个参数D,P,R,G.你可以 ...

  3. Does Java pass by reference or pass by value?(Java是值传递还是引用传递) - 总结

    这个话题一直是Java程序员的一个热议话题,争论不断,但是不论是你百度搜也好还是去看官方的文档中所标明的也好,得到的都只有一个结论:Java只有值传递. 在这里就不贴代码细致解释了,让我们来看看一些论 ...

  4. Vue脚手架(vue-cli)安装总结

    单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序. 提供一 ...

  5. Selenium_chromedriver与chrome版本映射表(更新至v2)

    chromedriver.exe下载地址:http://chromedriver.storage.googleapis.com/index.html chromedriver版本 支持的Chrome版 ...

  6. SUSE-11 本地 zypper 配置

    配置本地 zypper 目的: 安装 SUSE-11 后想要再添加或删除软件组件将比较麻烦.通过配置本地 zypper 将可以从下载的软件仓库(repository)中安装软件包.   本地 zypp ...

  7. 常见dos命令总结

    常用的内部命令有MD.CD.RD.DIR.PATH.COPY.TYPE.EDIT.REN.DEL.CLS.VER.DATE.TIME.PROMPT. 常用的外部命令有DELTREE.FORMAT.DI ...

  8. 静态成员static

    静态成员分为静态数据成员和静态函数成员: 静态数据成员: 1.用关键字static来声明: 2.该类的所有对象维护改成员的同一份拷贝:(就是说所有的对象看到的是同一份数据) 3.必须在类外定义和初始化 ...

  9. yii2 源码分析Event类分析 (三)

    转载请注明链接:http://www.cnblogs.com/liuwanqiu/p/6739880.html Event是所有事件的基类,它继承Object类 Event类上面的注释的大致意思: * ...

  10. php详细学习1

    PHP中的引用 $a="now magic"; $b=&$a; $b="abc"; echo $b.$a; 结果:abcabc $a="now ...