使用webpack打包library

如果想要使用webpack打包一个开发库供其他人使用,需要进行相应的配置。
学习了一下,记录下来,其实主要是翻译的官方文档。

开发一个库

假设我们在写一个库,叫做webpack-numbers,长这个样子:

src/index.js

1
2
3
4
5
6
7
import _ from 'lodash';
export function numToWord(num) {
return xxx;
};
export function wordToNum(word) {
return xxx;
};

我们的目标是让这个库可以支持多种使用方式:

可以import或者require

1
2
3
4
5
6
7
8
9
10
11
12
13
import * as webpackNumbers from 'webpack-numbers';

...
webpackNumbers.wordToNum('Two') // output is 2
...

// CommonJS modules

var webpackNumbers = require('webpack-numbers');

...
webpackNumbers.numToWord(3); // output is Three
...

也可以在html直接用script引用

1
2
3
4
5
6
7
8
9
10
<html>
...
<script src="https://unpkg.com/webpack-numbers"></script>
<script>
...
/* webpackNumbers is available as a global variable */
webpackNumbers.wordToNum('Five') //output is 5
...
</script>
</html>

需求

我们期望打包具有以下特性:

  • 不会将lodash打包进去,可以由使用者自行require。
  • 库的名字叫做webpack-numbers,变量是webpackNumbers
  • 库可以使用import webpackNumbers from 'webpack-numbers'require('webpack-numbers')方式引用。
  • 当库是由script引入时,可以通过全局变量webpackNumbers访问。
  • 可以在Node.js中使用。

webpack基本配置

webpack.config.js

1
2
3
4
5
6
7
8
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'webpack-numbers.js'
}
};

externals

如果只配置基本选项,会将代码中引用的第三方库一起打包进来,比如说lodash等。

externals选项可以排除第三方库。

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
...
externals: {
"lodash": {
commonjs: "lodash",
commonjs2: "lodash",
amd: "lodash",
root: "_"
}
}
...
};

这样会将ladash设置为依赖项,需要使用者自己引入到环境。

libraryTarget

我们希望自己写的库可以适配多种使用场景,例如CommonJS, AMD, Node.js或者是作为全局变量。

webpack配置中的library项可以帮助实现这一功能。

webpack.config.js

1
2
3
4
5
6
7
8
module.exports = {
...
output: {
...
library: 'webpackNumbers'
}
...
};

library选项只是使得打包后的库在import之后作为一个全局对象使用。为了适配更多环境,需要使用libraryTarget项。

webpack.config.js

1
2
3
4
5
6
7
8
9
module.exports = {
...
output: {
...
library: 'webpackNumbers',
libraryTarget: 'umd' // Possible value - amd, commonjs, commonjs2, commonjs-module, this, var
}
...
};

如果设置了library而没有设置libraryTarget,那么libraryTarget默认为var

libraryTarget的其他配置可见https://webpack.js.org/configuration/output/#output-librarytarget

最后一步

package.json中将打包后的bundle设置为main file。

package.json

1
2
3
4
{
"main": "dist/webpack-numbers.js",
"module": "src/index.js", // To add as standard module as per https://github.com/dherman/defense-of-dot-js/blob/master/proposal.md#typical-usage
}

main字段是package.json标准中的内容:

The main field is a module ID that is the primary entry point to your program. That is, if your package is named foo, and a user installs it, and then does require(“foo”), then your main module’s exports object will be returned.

This should be a module ID relative to the root of your package folder.

For most modules, it makes the most sense to have a main script and often not much else.

module字段是a proposal,目的是使得可以向后兼容的使用ES2015的模块特性。

现在,可以 将库发布到npm上 并且在 unpkg.com上发布给用户了!

参考文献

  1. Authoring Libraries
  2. webpack-library-example