从零到一学会webpack 06-创建一个 library

331 阅读2分钟

除了打包应用程序,webpack 还可以用于打包 JavaScript library

我们跟随官方指南的例子(对一些必要依赖做了升级处理) 编写一个名为 webpack-numbers 的小的 library,可以将数字 1 到 5 转换为文本表示,反之亦然,例如将 2 转换为 'two'。 项目结构为

├── .babelrc
├── .eslintrc.json
├── index.js
├── package.json
├── ref.json
├── webpack.config.js
└── yarn.lock

.babelrc

{
  "presets": [
    "@babel/env",
    "@babel/preset-react"
  ]
}

.eslintrc.json

{
    "env": {
        "browser": true,
        "commonjs": true,
        "es6": true,
        "node": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "sourceType": "module"
    },
    "rules": {
        "indent": [
            "error",
            4
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ]
    }
}

上面两个是esLint相关的配置文件

index.js

import _ from 'lodash';
import numRef from './ref.json';

function createTransalator() {
    return {
        numtoword: (num) => {
            return num < 0 || num > 5 ? 'This is a failure' : converttoword(num);
        },
        wordtonum: (word) => {
            const num = converttonum(word);
            return num === -1 ? 'This is a failure' : num;
        }
    };
}

const converttoword = (num) => {
    return _.reduce(numRef, (accum, ref) => {
        return ref.num === num ? ref.word : accum;
    }, '');
};

const converttonum = (word) => {
    return _.reduce(numRef, (accum, ref) => {
        return ref.word === word && word.toLowerCase() ? ref.num : accum;
    }, -1);
};

export default createTransalator();

ref.json

[{
    "num": 1,
    "word": "One"
},{
    "num": 2,
    "word": "Two"
},{
    "num": 3,
    "word": "Three"
},{
    "num": 4,
    "word": "Four"
},{
    "num": 5,
    "word": "Five"
},{
    "num": 0,
    "word": "Zero"
}]

package.json

{
  "name": "y",
  "version": "1.0.0",
  "description": "An example of how to author libraries using webpack",
  "main": "dist/webpack-numbers.js",
  "scripts": {
    "build": "webpack",
  },
  "keywords": [
    "webpack",
    "webpack-library",
    "bundling",
    "library"
  ],
  "author": "pksjce",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.13.1",
    "@babel/preset-env": "^7.13.5",
    "@babel/preset-react": "^7.12.13",
    "babel-loader": "^8.2.2",
    "babel-plugin-add-module-exports": "^0.2.1",
    "eslint": "^7.21.0",
    "eslint-loader": "^4.0.2",
    "lodash": "^4.17.21",
    "webpack": "^5.4.0",
    "webpack-cli": "^4.2.0"
  }
}

接下来我们写基本的webpack文件

webpack.cofig.js

const path = require('path');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'webpack-numbers.js',
  },
};

  1. 我们的模块需要lodash依赖,但是我们期望library的使用者已经安装了lodash依赖,否则我们需要将lodash打包入文件,在这种场景中,我们更倾向于把 lodash 当作 peerDependency。也就是说,consumer(使用者) 应该已经安装过 lodash

  2. 我们期望我们的library可以通过多种方式被引入使用:

  • CommonJS
const webpackNumbers = require('webpack-numbers');
  • AMD
require(['webpackNumbers'], function (webpackNumbers) {
  // ...
  webpackNumbers.wordToNum('Two');
});
  • Node.js
<!DOCTYPE html>
<html>
  ...
  <script src="https://unpkg.com/webpack-numbers"></script>
  <script>
    // ...
    // 全局变量
    webpackNumbers.wordToNum('Five');
    // window 对象中的属性
    window.webpackNumbers.wordToNum('Five');
    // ...
  </script>
</html>

  • 或者作为一个全局变量

修改配置

const path = require('path');


module.exports = {
    entry: './index.js',
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: 'webpack-numbers.js',
        libraryTarget: 'umd',
        globalObject: 'this',
        // libraryExport: 'default',
        library: 'webpackNumbers'
    },
    externals: {
        'lodash': {
            commonjs: 'lodash',
            commonjs2: 'lodash',
            amd: 'lodash',
            root: '_'
        }
    },
    module: {
        rules: [
            {
                test: /\.(js)$/,
                exclude: /(node_modules|bower_components)/,
                use: 'babel-loader'
            }
        ]
    },
};

关于library,这个字段配合libraryTarget一起使用,libraryTarget默认值为'var',意味着,该依赖引入后返回的值为你设置的library(这里为webpack-numbers.js)’,我们这里设置libraryTarget: 'umd';因为我们期望我们的库可以通过多种方式引入 参考文档:libraryTarget

globalObject:意味着我们当全局引入该依赖时我们从哪个变量来读取,这里我们写的this,以为这我们可以从this下面读取webpackNumbers

externals:我们不将lodash打包进入我们的library,这意味着你的 library 需要一个名为 lodash 的依赖,这个依赖在 consumer 环境中必须存在且可用。

最后,执行 yarn build