lmk123/blog

transform-runtime 会自动应用 polyfill,即便没有使用 babel-polyfill

lmk123 opened this issue · 13 comments

先简述一下 babel-polyfilltransform-runtime 是做什么的。

目前浏览器对 ES2015 语法的支持都不太好,所以当我们需要使用 PromiseSetMap 等功能时就需要 babel-polyfill 来提供。

在转换 ES2015 语法为 ECMAScript 5 的语法时,babel 会需要一些辅助函数,例如 _extend。babel 默认会将这些辅助函数内联到每一个 js 文件里,这样文件多的时候,项目就会很大。

所以 babel 提供了 transform-runtime 来将这些辅助函数“搬”到一个单独的模块 babel-runtime 中,这样做能减小项目文件的大小。

今天我在写一个针对 Chrome 浏览器的项目的时候,使用了 transform-runtime,但没有用 babel-polyfill,因为很多 ES2015 的功能(比如 Promise)Chrome 都已经支持了。可是文件经过 babel 转换之后,文件大小陡增,仔细一看,发现 babel 把 Promise 的 polyfill 给注入进来了。

因为我没有使用 babel-polyfill,所以我本来认为,babel 应该是不会给我注入任何 polyfill 的,但事与愿违。我查看了一下 babel-runtime,发现除了包含 babel 转换时需要用到的辅助函数外,它还包含了 corejs 与 regenerator——而 babel-polyfill 也包含了这两个模块。

当我查阅 transform-runtime 的文档时,才发现 transform-runtime 是可以配置的:

// with options
{
  "plugins": [
    ["transform-runtime", {
      "polyfill": false,
      "regenerator": true
    }]
  ]
}

由此可见,当我们在配置里直接使用 "plugins": ["transform-runtime"] 时,其实就相当于引入了 babel-polyfill。

这可能并不是我们想要的。

奇怪的是已使用transform-runtime 但是Array.find 是undefined

@yoyeung 我刚才试了一下,不用 babel-polyfill 只用 transform-runtime 的话,Array.prototype.find 确实是 undefined

也许在没有 babel-polyfill 的情况下,transform-runtime 只会把 built-ins(比如 PromiseSymbol)给加进去吧,等我有空了就验证一下。

謝謝。。。。這個問題有點困擾
我的解決方法是人工加入

@yoyeung 刚好路过,也遇到过这个问题,这其实是配置不对,官方推荐的用法是:

// with options
{
  "plugins": [
    ["transform-runtime", {
      "polyfill": false,
      "regenerator": true
    }]
  ]
}

这样是不会自动polyfill各种ES6/7方法的,只要把polyfill改成true即可,babel会自动识别代码里用到了哪些对象方法(只要不是特别奇葩的用法比如Object['assign']),并自动polyfill这些方法。而这其实是默认开启的,所以可以简写成:

// with options
{
  "plugins": [
    "transform-runtime"
  ]
}

@conanliu 不是这样吧! 当使用 transform-runtime 配置为
"plugins": [
["transform-runtime", {
"polyfill": true,
"regenerator": true
}]
]
Array.prototype.findIndex 是undefined
只有当使用babel-polyfill 时能找到Array.prototype.findeIndex
$export($export.P + $export.F * forced, 'Array', { findIndex: function findIndex(callbackfn/*, that = undefined */){ return $find(this, callbackfn, arguments.length > 1 ? arguments[1] : undefined); } });

从别的文章中我得到这么一段话:
transform-runtime 只能对语法进行解析如 await、async 等 但对Api不能够进行polyfill.
Ps: 到现在我都没能确切的理解transform-runtime到底能不能完全polyfill,以至于我们现在的解决方案是项目中使用到的新特性都会先用corejs先处理我们项目中用到了的语法和Api

你最上面说的这一句话:

在转换 ES2015 语法为 ECMAScript 5 的语法时,babel 会需要一些辅助函数,例如 _extend。babel 默认会将这些辅助函数内联到每一个 js 文件里,这样文件多的时候,项目就会很大。

其中的辅助函数指的是babel因为设置了babel-preset-2015转换语法而生成的,还是通过单独的一个es6的API转换插件比如babel-plugin-transform-object-assign转换生成的,还是怎么生成的?

@lmk123

transform-runtime默认配置polyfill为true。

"plugins": [
["transform-runtime"]
]

亲测,会转换如文档所说的构建Promise,Set,Map等实例的语法文档地址
我也试了下如Array.find等API方法,不加babel-polyfill,transform-runtime默认配置也会转换es6的API为 es5

在转换 ES2015 语法为 ECMAScript 5 的语法时??

总结:

  • 第一个目的避免重复引用工具类好理解
  • 第二个目的是提供运行时的helper,polyfill与regenerator支持。babel-polyfill是全局污染的,babel-runtime则是直接重写的方法来让你使用。

那么接下来的问题是,babel-runtime到底polyfill了哪些?
引用这篇文章

它不模拟实例方法,即内置对象原型上的方法,所以类似Array.prototype.find,你通过babel-runtime是无法使用的。

但我无从考证。官方文档上如是说:

这意味着你可以无缝的使用这些原生内置的和静态方法,且无需担心它们的来源。
注意: 例如 "foobar".includes("foo") 等实例方法将不会正常工作。

@kangaoxiaoshi 只启用 transform-runtime ,Array.prototype.findIndex 已经注入了,是你版本问题?

env:

  • babel-plugin-transform-runtime@6.23.0

大家要区分Array.from还是Array.prototype.findIndex。 前者是类的方法,后者是内置对象原型上的方法。 transform-runtime和babel-runtime无法polyfill对象原型上的方法~ 但能polyfill Array.from.

关于transform-runtime解决的问题,我这里有一篇比较啰嗦的实验性文章 从零搭建webpack前端类库脚手架[3]-强悍的babel

Array.prototype.findIndex

请问你是怎么用的?