webpack打包公用库

2,062 阅读4分钟

1.基础配置

1.1 library命名

如果我们打包的⽬的是⽣成⼀个供别⼈使⽤的库,那么可以使⽤ output.library 来指定库的名称,库

的名称⽀持占位符和普通字符串:

module.exports = {
    output: {
        library: 'myLib' // '[name]'
    }
};

1.2 libraryTarget 打包规范

使⽤ output.library 确定了库的名称之后,还可以使⽤ output.libraryTarget 指定库打包出来的 规范, output.libraryTarget 取值范围

为: var 、 assign 、 this 、 window 、 global 、 commonjs 、 commonjs2 、 commonjs

module 、 amd 、 umd 、 umd2 、 jsonp ,默认是 var ,下⾯通过打包后的代码不同,来看下差别。

// var config
{
    output: {
        library: 'myLib',
        filename: 'var.js',
        libraryTarget: 'var'
    }
}
// output
var myLib = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// assign config
{
    output: {
        library: 'myLib',
        filename: 'assign.js',
        libraryTarget: 'assign'
    }
}
// output: 少了个 var
myLib = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// this config{
{
    output: {
        library: 'myLib',
        filename: 'this.js',
        libraryTarget: 'this'
    }
}
// output
this["myLib"] = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// window config
{
    output: {
        library: 'myLib',
        filename: 'window.js',
        libraryTarget: 'window'
    }
}
// output
window["myLib"] = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// global config
{
    output: {
        library: 'myLib',
        filename: 'global.js',
        libraryTarget: 'global'
    }
}

// output:注意 target=node 的时候才是 global,默认 target=web下global 为 window
window["myLib"] = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// commonjs config
{
    output: {
        library: 'myLib',
        filename: 'commonjs.js',
        libraryTarget: 'commonjs'
    }
}
// output
exports["myLib"] = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// amd config
{
    output: {
        library: 'myLib',
        filename: 'amd.js',
        libraryTarget: 'amd'
    }
}
// output
define('myLib', [], function () {
    return (function (modules) { })({
        './src/index.js': function (module, exports) { }
    });
});
// ===============================================

// umd config
{
    output: {
        library: 'myLib',
        filename: 'umd.js',
        libraryTarget: 'umd'
    }
}
// output
(function webpackUniversalModuleDefinition(root, factory) {
    if (typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if (typeof define === 'function' && define.amd) define([], factory);
    else if (typeof exports === 'object') exports['myLib'] = factory();
    else root['myLib'] = factory();
})(window, function () {
    return (function (modules) { })({
        './src/index.js': function (module, exports) { }
    });
});
// ===============================================

// commonjs2 config
{
    output: {
        library: 'myLib',
        filename: 'commonjs2.js',
        libraryTarget: 'commonjs2'
    }
}
//output
module.exports = (function(modules) {})({
    './src/index.js': function(module, exports) { }
});
// ===============================================

// umd2 config
{
    output: {
        library: 'myLib',
        filename: 'umd2.js',
        libraryTarget: 'umd2'
    }
}
// output
(function webpackUniversalModuleDefinition(root, factory) {
    if (typeof exports === 'object' && typeof module === 'object')
        module.exports = factory();
    else if (typeof define === 'function' && define.amd) define([], factory);
    else if (typeof exports === 'object') exports['myLib'] = factory();
    else root['myLib'] = factory();
})(window, function () {
    return (function (modules) { })({
        './src/index.js': function (module, exports) {
        }
    });
});
// ===============================================

// commonjs-module config
{
    output: {
        library: 'myLib',
        filename: 'commonjs-module.js',
        libraryTarget: 'commonjs-module'
    }
}
// output
module.exports = (function (modules) { })({
    './src/index.js': function (module, exports) { }
});
// ===============================================

// jsonp config
{
    output: {
        library: 'myLib',
        filename: 'jsonp.js',
        libraryTarget: 'jsonp'
    }
}
// output
myLib((function (modules) { })({
    './src/index.js': function (module, exports) { }
}));
// ===============================================

image.png

1.3 target

在项⽬开发中,我们不仅仅是开发 web 应⽤,还可能开发的是 Node.js 服务应⽤、或者 electron 这类 跨平台桌⾯应⽤,这时候因为对应的宿主环境不同,所以在构建的时候需要特殊处理。webpack 中可以 通过设置 target 来指定构建的⽬标(target)。

myLib((function (modules) { })({
    './src/index.js': function (module, exports) { }
}));
module.exports = {
    target: 'web' // 默认是 web,可以省略
};
  • target 的值有两种类型:string 和 function。
  • string 类型⽀持下⾯的七种:
  • web :默认,编译为类浏览器环境⾥可⽤;
  • node :编译为类 Node.js 环境可⽤(使⽤ Node.js require 加载 chunk);
  • async - node :编译为类 Node.js 环境可⽤(使⽤ fs 和 vm 异步加载分块);
  • electron - main :编译为 Electron 主进程;
  • electron - renderer :编译为 Electron 渲染进程;
  • node - webkit :编译为 Webkit 可⽤,并且使⽤ jsonp 去加载分块。⽀持 Node.js 内置模块和
  • nw.gui 导⼊(实验性质);
  • webworker :编译成⼀个 WebWorker。

除了 string 类型,target 还⽀持 function 类型,这个函数接收⼀个 compiler 作为参数,如下⾯代 码可以⽤来增加插件:

const webpack = require('webpack');
const options = {
    target: compiler => {
        compiler.apply(new webpack.JsonpTemplatePlugin(options.output), new
            webpack.LoaderTargetPlugin('web'));
    }
};

2 实操

1.打包流程

  1. 新建⼀个library库项⽬
  2. 使用webpack打包两个版本⽂件,一个是压缩,一个是未压缩
  3. 发布到npm
  4. 项⽬引入使用

1.创建项目

// ⽬录结构

//dist 构建后文件夹

//src/index.js 库源码 
export default function add(a, b) {
  return a + b;
}

//index.js 程序main 入口
//可以根据当前不同的编译环境 导入不同的代码
if (process.env.NODE_ENV == "production") {//生产环境使用压缩后的
  module.exports = require("./dist/add-number.min.js");
} else {
  module.exports = require("./dist/add-number.js");
}

//package.json 配置信息
{
  "name": "my-test-add",
  "version": "1.1.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "terser-webpack-plugin": "^4.2.0",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12"
  }
}

//webpack.config.js 打包信息
const TerserPlugin = require("terser-webpack-plugin"); //这里不实用
module.exports = {
  entry: {
    "add-number": "./src/index.js",
    "add-number.min": "./src/index.js",
  },
  output: {
    filename: "[name].js",
    library: "addNumber",
    libraryTarget: "umd",
    libraryExport: "default", //这里需要声明,不然调用地方需要 再.default才能访问
  },
  mode: "none",
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        test: /\.min\.js$/,
      }),
    ],
  },
}; 

  • 使⽤terser来压缩 JavaScript 代码,是官方推荐的压缩代码。
  • UglifyJS 在 ES6 代码压缩上做的不够好,代码也不再维护,terser是UglifyJS的分支,一直有维护。

2.2 使用命令npm构建

 npm run build  

2.3 发布到npm

  • npm源的修改
  • npm注册 官网注册 www.npmjs.com/signup
  • npm登陆 npm login npm who am i (查看当前登陆用户)
  • npm发布 :注意发布时候,是把整个项目所有文件除了node_modules,其他都上传
#!/usr/bin/env bash 
npm config get registry # 检查仓库镜像库 
npm config set registry=http://registry.npmjs.org   # 恢复为官方的镜像 
echo '请进行登录相关操作:' 
npm login # 登陆 
echo "-------publishing-------" 
npm publish # 发布 
npm config set registry=https://registry.npm.taobao.org # 设置为淘宝镜像 
echo "发布完成" 
exit 

2.4 项⽬引入使用

由于my-test-add的 index.js 判断当前环境变量 是否 process.env.NODE_ENV == "production"

所以最终根据 当前项目 mode: "development"/"production" 引入不同的版本 add-number.js 或者 add-number.min.js

//webpack.config.js
const path = require("path")
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "./dist"),
    filename: "main.js",
  },
  mode: "development" //该变量影响实际打包使用的my-test-add库
};


//package.json
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1", 
    "webpack": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {},
  "devDependencies": {
    "jasonyang-util-add": "1.0.0",
    "webpack": "^5.10.0",
    "webpack-cli": "^4.2.0"
  }
}

//src/index.js
// //注意如果打包库 没有指定 output: { libraryExport: "default"},需要.default才能访问
//由于设置umd,import和requrie 都支持
//import 方式导入
import addNum from "my-test-add";
console.log(addNum(1, 2)); 
//requrie方式导入
const addNum = requrie("my-test-add") ;
console.log(addNum(1, 2));


//dist/main.js //这是打包编译后的文件
//dist/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src="./main.js"></script>
</body>
</html>

扩展

lerna 管理多个库