如何在 webpack v2 中实现全局承诺填充



我想更好地了解在 webpack 中实现承诺的方式之间的差异。通常,幸福的无知足以过日子,因为我主要开发应用程序,但我对如何正确开发插件/工具/库肯定有点困惑。


在创建应用程序时,以下两种方法从未引起任何问题;我想主要是因为这无关紧要

webpack.config.js - 使用 babel-polyfill 作为入口点

module.exports = {
entry: {
foo: [
'core-js/fn/promise',          <-- here
'./js/index.js'
]
},
module: {
rules: [
{
test: /.js$/,
loader: 'babel-loader'
}
]
}
}

问:在这种方法中,由于它是多填充物,它会修改全局承诺?

webpack config - 使用 webpack 提供插件的填充

module.exports = {
entry: './js/index.js',
module: {
rules: [
{
test: /.js$/,
loader: 'babel-loader'
}
]
},
plugins: [
new webpack.ProvidePlugin({
Promise: 'es6-promise'          <-- here
})
]
};

问:这是否意味着 Promise 是一个特定于 webpack 捆绑过程的模块?转译的 ES5 代码是否有本地副本或 es6-promise?它是否修补了全球承诺?


关于创建一个使用 babel 进行转译的 jquery 插件/工具/库......

webpack.config.js - 使用 babel-plugin-transform-runtime

module.exports = {
entry: {
foo: [
'./js/start.js'
]
},
module: {
rules: [
{
test: /.js$/,
loader: 'babel-loader'
}
]
}
}

.babelrc

{
"presets": [ "es2015" ],
"plugins": ["transform-runtime"]     <--here
}

开始.js

require('babel-runtime/core-js/promise').default = require('es6-promise');  <--here
require('plugin');

问:这会将 es6-promise 别名为 babel-runtime 承诺,并且不是全局的,而只是工具的本地?

webpack 条目中的填充

entry: ['core-js/fn/promise', './index.js']

这与在入口点顶部导入它的效果相同。

在这种方法中,由于它是一个填充物,它修改了全局承诺?

是的,此填充会更改全局Promise。称其为 polyfill 通常意味着它会修补全局内置,尽管这并没有严格遵守。如果他们不更改现有 API,而只提供功能,则它们有时称为 Ponyfill。

ProvidePlugin的网包填充

new webpack.ProvidePlugin({
Promise: 'es6-promise'
})

当找到相应的自由变量时,ProvidePlugin将在使用它的模块的开头导入配置的模块。自由变量是尚未在当前范围内声明的标识符。全局变量是所有局部作用域中的自由变量。

每当遇到空闲Promise时,webpack 都会在模块的开头添加以下内容:

var Promise = require('es6-promise');

这是否意味着 Promise 是一个特定于 webpack 捆绑过程的模块?

这是正确的,因为ProvidePlugin特定于 webpack 的,任何其他工具都不太可能遵循任何 webpack 设置。

转译的 ES5 代码是否有本地副本或 es6-promise?

与任何其他模块一样,它由 webpack 包含一次,所有导入都引用该模块。

它是否修补了全球承诺?

仅当导入的模块显式修改全局Promise时,它才会修改全局。默认情况下,您正在使用的es6-promise不会修补全局,如自动填充中所示。

Babel 转换运行时

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

babel-plugin-transform-runtime使用core-js来提供缺少的功能,例如Promise。您可能还记得,我说过core-js修改了全球Promise.这种情况并非如此,因为 babel 使用的版本不会污染全局命名空间,如core-js自述文件中所述,该版本core-js/library。例如:

const Promise = require('core-js/library/fn/promise');

Babel 将导入core-jsPromise 并将Promise替换为导入的变量。另请参阅babel-plugin-transform-runtime-core-js别名中的示例。这本质上与 webpack 的ProvidePlugin相同,只是 babel 没有捆绑模块,所以它只是添加导入。

这将 es6-promise 与 babel-runtime promise 别名,并且不是全局的,而只是工具的本地?

它不是全局的,因为它只是一个模块。Babel 采用您的 JavaScript 并输出一些其他 JavaScript,其中配置的功能被转换为 ES5。您将运行或捆绑生成的JavaScript,它实际上与您最初编写ES5相同。

require('babel-runtime/core-js/promise').default = require('es6-promise');

这样,您可以修改导出,因此模块将改用es6-promise。但是覆盖导出不是一个好主意,特别是因为 ES 模块的导入在规范中是不可变的。Babel 目前在这方面不符合规范。有关更多详细信息,请参阅使转译的 ES 模块更符合规范。


你应该使用哪一个?

这取决于你在做什么。除了它们是否更改全局变量的差异之外,您还可以选择您喜欢的任何一种。例如,使用 babel 的转换运行时允许您将其与任何使用 babel 的工具一起使用,而不仅仅是 webpack。

对于库

没有

将填充代码留给应用程序开发人员。但您可能会提到它取决于某个功能,当用户想要在不支持该功能的环境中使用库时,他们必须填充它。假设 Promise 得到广泛支持也是相当合理的,如果应用程序针对较旧的环境,他们很可能已经填充了它。请记住,这并不意味着您不应该转译新功能/语法。这专门用于新功能,例如PromiseString.prototype.trimLeft.

对于工具

这也取决于您对工具的定义。假设工具是开发人员使用的软件(例如 webpack、eslint 等)。在这种情况下,它与任何应用程序完全相同,归根结底,它只是另一个应用程序,但仅针对开发人员。具体来说到命令行工具,您应该决定要支持的最低 Node 版本并包含所需的任何内容,您可以在package.jsonengines字段中指定。

对于插件

插件是一个非常广泛的术语,可以是库和应用程序之间的任何内容。例如,webpack 插件或加载器应该按原样工作,而 jQuery 插件将是 Web 应用程序的一部分,您应该将其视为库(它们可能应该被称为库而不是插件)。通常,您希望匹配要扩展的任何内容的准则。看看它,看看他们的目标是什么。例如,webpack 目前支持 Node 版本>=4.3.0,所以你的插件也应该支持。

相关内容

  • 没有找到相关文章

最新更新