除了应用程序之外,webpack 还可以用于捆绑 JavaScript 库。以下指南适用于希望简化其捆绑策略的库作者。
假设我们正在编写一个小型库 webpack-numbers
,它允许用户将数字 1 到 5 从数字表示形式转换为文本表示形式,反之亦然,例如 2 到 'two'。
基本项目结构如下所示
project
+ |- webpack.config.js
+ |- package.json
+ |- /src
+ |- index.js
+ |- ref.json
使用 npm 初始化项目,然后安装 webpack
、webpack-cli
和 lodash
npm init -y
npm install --save-dev webpack webpack-cli lodash
我们将 lodash
安装为 devDependencies
而不是 dependencies
,因为我们不想将其捆绑到我们的库中,否则我们的库很容易变得臃肿。
src/ref.json
[
{
"num": 1,
"word": "One"
},
{
"num": 2,
"word": "Two"
},
{
"num": 3,
"word": "Three"
},
{
"num": 4,
"word": "Four"
},
{
"num": 5,
"word": "Five"
},
{
"num": 0,
"word": "Zero"
}
]
src/index.js
import _ from 'lodash';
import numRef from './ref.json';
export function numToWord(num) {
return _.reduce(
numRef,
(accum, ref) => {
return ref.num === num ? ref.word : accum;
},
''
);
}
export function wordToNum(word) {
return _.reduce(
numRef,
(accum, ref) => {
return ref.word === word && word.toLowerCase() ? ref.num : accum;
},
-1
);
}
让我们从这个基本的 webpack 配置开始
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
},
};
在上面的示例中,我们告诉 webpack 将 src/index.js
捆绑到 dist/webpack-numbers.js
中。
到目前为止,一切都应该与捆绑应用程序相同,这里出现了不同之处——我们需要通过 output.library
选项公开入口点的导出。
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
+ library: "webpackNumbers",
},
};
我们将入口点公开为 webpackNumbers
,以便用户可以通过脚本标签使用它
<script src="https://example.org/webpack-numbers.js"></script>
<script>
window.webpackNumbers.wordToNum('Five');
</script>
但是,它只在通过脚本标签引用时有效,它不能在其他环境中使用,例如 CommonJS、AMD、Node.js 等。
作为库作者,我们希望它在不同的环境中兼容,即用户应该能够以以下列出的多种方式使用捆绑的库
CommonJS 模块 require:
const webpackNumbers = require('webpack-numbers');
// ...
webpackNumbers.wordToNum('Two');
AMD 模块 require:
require(['webpackNumbers'], function (webpackNumbers) {
// ...
webpackNumbers.wordToNum('Two');
});
脚本标签:
<!DOCTYPE html>
<html>
...
<script src="https://example.org/webpack-numbers.js"></script>
<script>
// ...
// Global variable
webpackNumbers.wordToNum('Five');
// Property in the window object
window.webpackNumbers.wordToNum('Five');
// ...
</script>
</html>
让我们更新 output.library
选项,将其 type
设置为 'umd'
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
- library: 'webpackNumbers',
+ globalObject: 'this',
+ library: {
+ name: 'webpackNumbers',
+ type: 'umd',
+ },
},
};
现在 webpack 将捆绑一个可以与 CommonJS、AMD 和脚本标签一起工作的库。
现在,如果您运行 npx webpack
,您会发现创建了一个相当大的捆绑包。如果您检查该文件,您会发现 lodash 已与您的代码捆绑在一起。在这种情况下,我们更愿意将 lodash
视为对等依赖项。这意味着消费者应该已经安装了 lodash
。因此,您可能希望将此外部库的控制权交给您的库的消费者。
这可以通过使用 externals
配置来完成
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js',
library: {
name: "webpackNumbers",
type: "umd"
},
},
+ externals: {
+ lodash: {
+ commonjs: 'lodash',
+ commonjs2: 'lodash',
+ amd: 'lodash',
+ root: '_',
+ },
+ },
};
这意味着您的库期望在消费者的环境中提供名为lodash
的依赖项。
对于使用依赖项中多个文件的库
import A from 'library/one';
import B from 'library/two';
// ...
您将无法通过在 externals 中指定library
来将它们从捆绑包中排除。您需要逐个排除它们,或者使用正则表达式。
module.exports = {
//...
externals: [
'library/one',
'library/two',
// Everything that starts with "library/"
/^library\/.+$/,
],
};
按照生产指南中提到的步骤优化您的生产输出。让我们还将生成的捆绑包的路径添加为包的main
字段,并使用package.json
package.json
{
...
"main": "dist/webpack-numbers.js",
...
}
或者,按照本指南将其添加为标准模块
{
...
"module": "src/index.js",
...
}
键main
指的是package.json
中的标准,而module
指的是一个提案,允许 JavaScript 生态系统升级以使用 ES2015 模块,而不会破坏向后兼容性。
现在您可以将其发布为 npm 包,并在unpkg.com上找到它,以将其分发给您的用户。