【webpack系列】webpack打包组件和基础库

3,096 阅读4分钟

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. 编写代码

  1. 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');
  1. 执行 npm install terser-webpack-plugin -D,安装terser-webpack-plugin

  2. 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_);
  1. 根目录下的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"
  }
}
  1. 然后执行npm run build,可以看到dist文件中有两个文件,一个压缩,一个未压缩。

5. 发布npm包

  1. 执行npm adduser,输入用户名、密码和邮箱
  2. 执行npm publish

6. 引用测试

  1. 在项目中安装包:npm install npm-large-number -S
  2. 在项目中引入
import largeNumber from 'npm-large-number';

var res = largeNumber('999', '1');
console.log(res);

关于写一个npm包的另一篇:

如何发布一个自己的npm包?