创建 Library
webpack 是一个用来打包应用程序(application)和 library 的代码的工具。如果你是一个 JavaScript library 的作者,并且想要流水线化(streamline)你的打包逻辑,那么这篇文档将会帮助到你。
创建一个 library
假设你正在写一个名为 webpack-numbers
的 library,可以将数字 1 到 5 转换为文本表示,或者反之可以将文本表示数字。它使用 ES6 模块实现,看起来像这样:
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);
};
该 library 的使用方式如下:
import * as webpackNumbers from 'webpack-numbers';
...
webpackNumbers.wordToNum('Two') // 输出 2
...
// 使用 CommonJS 模块引入
var webpackNumbers = require('webpack-numbers');
...
webpackNumbers.numToWord(3); // 输出 Three
...
// 或者使用 script 标签引入
<html>
...
<script src="https://unpkg.com/webpack-numbers">
完整的 library 配置和相关代码请参阅 webpack library 示例。
配置 webpack
现在需要打包这个 library,同时要完成以下要求
- 不要打包 lodash,而是 require 用户加载好的 lodash。
- library 的名字是
webpack-numbers
,其变量名是webpackNumbers
。 - library 可以用两种方式来引入:
import webpackNumbers from 'webpack-numbers'
或者require('webpack-numbers')
。 - 当 library 通过
script
标签引入的时候,可以通过全局变量webpackNumbers
来使用。 - library 可以在 Node.js 中使用。
增加 webpack
增加基本的 webpack 配置。
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js'
}
};
以上代码是打包该 library 的基本配置。
增加 externals
现在,如果执行 webpack
,你会发现输出了一个非常巨大的文件。进一步观察该文件,你会发现 lodash 和你的代码被一起打包了。
然而对于你的 library 本身来说,并不需要打包 lodash
。因此你可能会想将该外部扩展(external)的控制权交给你的用户。
这一点可以通过配置 externals
来实现:
webpack.config.js
module.exports = {
...
externals: {
"lodash": {
commonjs: "lodash",
commonjs2: "lodash",
amd: "lodash",
root: "_"
}
}
...
};
这意味着你的 library 需要一个名为 lodash
的依赖,这个依赖在用户的环境中必须存在且可用。
如果你计划只是将 library 用作另一个 webpack bundle 中的依赖模块,则可以将外部扩展(external)指定为数组。
module.exports = {
...
externals: [
'react',
'react-dom'
]
...
};
请注意:对于如下,bundle 使用了一个包(package)中的多个文件
import A from 'library/A';
import B from 'library/B';
...
你无法通过在 externals 中指定 library
目录的方式,将它们从 bundle 中排除。
您将需要逐个排除它们,或使用正则表达式排除。
module.exports = {
...
externals: [
'library/A',
'library/B',
/^library\/.+$/ // everything that starts with "library/"
]
...
};
增加 libraryTarget
为了让此 library 能够被广泛使用,你需要让它兼容不同的环境,例如 CommonJS,AMD,Node.js 或者作为一个全局变量。
为了让你的代码能够被重用,需要在 webpack 配置中增加一个 library
属性。
webpack.config.js
module.exports = {
...
output: {
...
library: 'webpackNumbers'
}
...
};
这能让你的 library 被引入后,可以通过全局变量来使用。为了让 library 可以兼容其他环境,还需要在配置中增加 libraryTarget
属性。
webpack.config.js
module.exports = {
...
output: {
...
library: 'webpackNumbers',
libraryTarget: 'umd'
}
...
};
如果设置了 library
但没设置 libraryTarget
,则 libraryTarget
默认为 var
,详细说明请查看output 配置文档。查看 output.libraryTarget
,以获取所有可用选项的详细列表。
最终步骤
在 package.json
中指定主文件(main file)为你生成的文件路径。
package.json
{
"main": "dist/webpack-numbers.js",
"module": "src/index.js", // 增加标准的模块,参照:https://github.com/dherman/defense-of-dot-js/blob/master/proposal.md#typical-usage
}
键(key) main
是指 package.json
标准,以及module
是一个提案,此提案允许 JavaScript 生态系统升级使用 ES2015 模块,而不会破坏向后兼容性。
module
将指向一个含有 ES2015 模块语法的模块,但是只有在支持此语法功能的浏览器或 Node.js 版本中才可用。
现在你可以将其发布为一个 npm 包,并且在 unpkg.com 找到它并分发给你的用户。