我想更好地了解在 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-js
Promise 并将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 得到广泛支持也是相当合理的,如果应用程序针对较旧的环境,他们很可能已经填充了它。请记住,这并不意味着您不应该转译新功能/语法。这专门用于新功能,例如Promise
或String.prototype.trimLeft
.
对于工具
这也取决于您对工具的定义。假设工具是开发人员使用的软件(例如 webpack、eslint 等)。在这种情况下,它与任何应用程序完全相同,归根结底,它只是另一个应用程序,但仅针对开发人员。具体来说到命令行工具,您应该决定要支持的最低 Node 版本并包含所需的任何内容,您可以在package.json
的engines
字段中指定。
对于插件
插件是一个非常广泛的术语,可以是库和应用程序之间的任何内容。例如,webpack 插件或加载器应该按原样工作,而 jQuery 插件将是 Web 应用程序的一部分,您应该将其视为库(它们可能应该被称为库而不是插件)。通常,您希望匹配要扩展的任何内容的准则。看看它,看看他们的目标是什么。例如,webpack 目前支持 Node 版本>=4.3.0,所以你的插件也应该支持。