webpack除了可以用来打包应用,也可以用来打包js库。
下面我们用一个例子,来演示一下如何用webpack来打包一个js库。
我们的目标是: 实现一个大整数加法库的打包。
- 需要打包压缩版和非压缩版
- 支持AMD/Commonjs/ES6 Module模块引入。
- 支持直接使用script标签引入
1. 创建项目目录
// 在终端输入
mkdir npm-large-number
cd npm-large-number
npm init -y
2. 安装webpack & webpack-cli
npm i webpack webpack-cli -D
3. 打开项目,创建文件/文件夹,形成以下目录结构
4. 编写代码
- src文件夹下的index.js写入一个大整数相加的方法:
// src/index.js
export default function add (a, b) {
let i = a.length - 1;
let j = b.length - 1;
let res = ''; // 结果
let carray = 0; // 进位值
while (i >= 0 || j >= 0) {
let x = 0;
let y = 0;
let sum;
if (i >= 0) {
x = a[i] - '0'; // 转换为数字
i --;
}
if (j >= 0) {
y = b[j] - '0'; // 转换为数字
j --;
}
sum = x + y + carray;
if (sum >= 10) {
carray = 1;
sum -= 10;
} else {
carray = 0;
}
res = sum + res;
}
if (carray > 0) {
res = carray + res;
}
return res;
}
// add('1', '999');
// add('999', '1');
// add('123', '456');
-
执行 npm install terser-webpack-plugin -D,安装terser-webpack-plugin
-
webpack.config.js的配置如下:
// webpack.config.js
// 压缩插件,压缩ES6的语法不会报错,uglifyjs会报错(3.0版本支持)
const TerserWebpackPlugin = require('terser-webpack-plugin');
module.exports = {
mode: "none",
entry: {
'large-number': './src/index.js',
'large-number.min': './src/index.js'
},
output: {
filename: '[name].js',
library: 'largeNumber', // 指定库的名称,及库的全局变量
libraryTarget: 'umd', // 支持库引入的方式
libraryExport: 'default'
},
optimization: {
minimize: true,
minimizer: [
new TerserWebpackPlugin({
include: /\.min\.js$/
})
]
}
};
关于library和libraryTarget
library的值被如何使用,会根据libraryTarget的取值不同而不同。libraryTarget配置的作用是控制 webpack 打包的内容是如何暴露的。我们的例子中,library的值是 largeNumber。我们用_entry_return_ 表示入口点返回的值。
libraryTarget的值有以下几个值:
- var:默认值,使用这个配置,会把打包返回的值绑定到一个由library指定的变量上,无论包是被如何引用
var largeNumber = _entry_return_;
// 使用方式
largeNumber();
- assign:使用这个设置,会把库返回值分配给一个没使用var声明的变量中,如果这个变量没有在引入作用域中提前声明过,那么将会挂载在全局作用域中。(注意,这个行为有可能会覆盖全局作用域中的已有变量)
largeNumber = _entry_return_;
- this:将库的返回值分配给this对象的由library指定的属性。其中this的意义由用户决定。
this["largeNumber"] = _entry_return_;
// 使用方式
this.largeNumber();
- window:将库的返回值分配给window对象的由library指定的属性。
window["largeNumber"] = _entry_return_;
// 使用方式
window.largeNumber.doSomething();
- global:将库的返回值分配给global对象的由library指定的属性。
global["largeNumber"] = _entry_return_;
// 使用方式
global.largeNumber.doSomething();
- commonjs:将库的返回值分配给exports对象的由library指定的属性。正如名字所指,这个选项可以使用在 CommonJS 环境。
exports["largeNumber"] = _entry_return_;
// 使用方式
require("largeNumber").doSomething();
- commonjs2:将库的返回值分配给module.exports。注意,在这个情况下output.library不是必须的,因为此时output.library选项将会被忽略。
module.exports = _entry_return_;
// 使用方式
const largeNumber = require("largeNumber");
largeNumber();
- amd:这个选项会把库作为 AMD 模块导出。
define("largeNumber", [], function() {
return _entry_return_;
});
// 使用方式
require(['largeNumber'], function(largeNumber) {
// Do something with the library...
largeNumber();
});
- umd:这个选项会尝试把库暴露给当前使用的模块定义系统,这使其和CommonJS、AMD兼容或者暴露为全局变量。
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else {
var a = factory();
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
})(this, function() {
return _entry_return_;
});
- jsonp:这个方法会使用 jsonp 的方式把结果包裹起来 从 webpack 3.10.0 版本开始,我们可以通过把 library 定义为对象来控制不同目标环境的输出值。
largeNumber(_entry_return_);
- 根目录下的index.js用来根据环境引入相应的js文件
// index.js
if (process.env.NODE_ENV === "production") {
module.exports = require('./dist/large-number.min.js');
} else {
module.exports = require('./dist/large-number.js');
}
package.json添加打包命令
{
"name": "npm-large-number",
"version": "1.0.0",
"description": "大整数加法npm包",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "rimraf ./dist && webpack",
"prepublish": "npm run build"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"terser-webpack-plugin": "^4.1.0",
"webpack": "^4.44.1",
"webpack-cli": "^3.3.12"
}
}
- 然后执行npm run build,可以看到dist文件中有两个文件,一个压缩,一个未压缩。
5. 发布npm包
- 执行npm adduser,输入用户名、密码和邮箱
- 执行npm publish
6. 引用测试
- 在项目中安装包:npm install npm-large-number -S
- 在项目中引入
import largeNumber from 'npm-large-number';
var res = largeNumber('999', '1');
console.log(res);
关于写一个npm包的另一篇: