Javascript 使用 ES6 和 ES7 功能的库是否需要 babel-polyfill?

Should Javascript library which uses ES6 and ES7 features require babel-polyfill?

我正在开发一个大量使用 ES6 和 ES7 功能的库。用 Babel 编译它会产生代码,它(自然地)使用 Symbol 或 Promise 等原语。我是否应该 require('babel-polyfill') 确保这些原语确实存在?

一开始,答案似乎是 'yes' - 特别是如果我不知道有人可能会在什么运行时执行我的库。另一方面,如果每个图书馆都这样做,我们最终会一遍又一遍地要求 babel-polyfill(我不确定这是否是个好主意)。

我对此做了一些研究:

从库内部要求 babel-polyfill 看起来像 anti-pattern;这有两个原因:

1) babel-polyfill 不喜欢被要求多次,如果你尝试这样做,它会抛出错误(见下面的注释)

2) 这样做会导致库的大小显着增加,因为您必须多次捆绑 polyfill。

仅当 npm 无法删除多个 babel-polyfill 依赖项时,1) 和 2) 才相关。如果您使用旧版本的 npm 或由于依赖限制可能无法进行重复数据删除,就会发生这种情况。由于最新的不容易控制,所以我认为1)和2)都很严重。

现在,你(可能)应该怎么做:

如果您需要库中的特定功能(即 Promise),您可以 require 具体地使用它(即不是整个 polyfill,只是功能)。这种方法缓解了 1) 并部分缓解了 2).

可能最好的方法就是警告您的用户,您的库需要一些 ES6 功能,因此他们应该需要 polyfill。

第一种方法的很好的例子是

https://www.npmjs.com/package/promisify-node

这需要它自己的 A+ 兼容 Promise 版本。第二种方法的好例子是

https://github.com/ubolonton/js-csp

它使用了生成器,但没有做任何事情来确保它们确实存在(一般来说,仅仅用 Babel 编译代码是不够的,你需要一个 polyfill 来使它们工作)。

--------编辑--------

我发现,babel-plugin-transform-runtime 可以准确地用于解决这个问题:它允许您使用 ES6 / ES7 功能,而无需通过 polyfill 污染全局命名空间。这个故事的可悲部分是,这个插件有很多错误,可能是因为从根本上很难完成这项工作。例如:

Object.keys({})

转换为类似于:

var _keys=require("babel-runtime/core-js/object/keys")
_keys(obj)

但是

var aaa = Object
aaa.keys(obj)

根本不会被转换,因此会失败(如果 Object.keys 既没有被浏览器定义,也没有被 polyfill 定义)。我的建议是 - 不要将插件用于此目的。