编写库

除了应用程序之外,webpack 还可以用于捆绑 JavaScript 库。以下指南适用于希望简化其捆绑策略的库作者。

编写库

假设我们正在编写一个小型库 webpack-numbers,它允许用户将数字 1 到 5 从数字表示形式转换为文本表示形式,反之亦然,例如 2 到 'two'。

基本项目结构如下所示

project

+  |- webpack.config.js
+  |- package.json
+  |- /src
+    |- index.js
+    |- ref.json

使用 npm 初始化项目,然后安装 webpackwebpack-clilodash

npm init -y
npm install --save-dev webpack webpack-cli lodash

我们将 lodash 安装为 devDependencies 而不是 dependencies,因为我们不想将其捆绑到我们的库中,否则我们的库很容易变得臃肿。

src/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"
  }
]

src/index.js

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

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

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

Webpack 配置

让我们从这个基本的 webpack 配置开始

webpack.config.js

const path = require('path');

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

在上面的示例中,我们告诉 webpack 将 src/index.js 捆绑到 dist/webpack-numbers.js 中。

公开库

到目前为止,一切都应该与捆绑应用程序相同,这里出现了不同之处——我们需要通过 output.library 选项公开入口点的导出。

webpack.config.js

  const path = require('path');

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

我们将入口点公开为 webpackNumbers,以便用户可以通过脚本标签使用它

<script src="https://example.org/webpack-numbers.js"></script>
<script>
  window.webpackNumbers.wordToNum('Five');
</script>

但是,它只在通过脚本标签引用时有效,它不能在其他环境中使用,例如 CommonJS、AMD、Node.js 等。

作为库作者,我们希望它在不同的环境中兼容,即用户应该能够以以下列出的多种方式使用捆绑的库

  • CommonJS 模块 require:

    const webpackNumbers = require('webpack-numbers');
    // ...
    webpackNumbers.wordToNum('Two');
  • AMD 模块 require:

    require(['webpackNumbers'], function (webpackNumbers) {
      // ...
      webpackNumbers.wordToNum('Two');
    });
  • 脚本标签:

    <!DOCTYPE html>
    <html>
      ...
      <script src="https://example.org/webpack-numbers.js"></script>
      <script>
        // ...
        // Global variable
        webpackNumbers.wordToNum('Five');
        // Property in the window object
        window.webpackNumbers.wordToNum('Five');
        // ...
      </script>
    </html>

让我们更新 output.library 选项,将其 type 设置为 'umd'

 const path = require('path');

 module.exports = {
   entry: './src/index.js',
   output: {
     path: path.resolve(__dirname, 'dist'),
     filename: 'webpack-numbers.js',
-    library: 'webpackNumbers',
+    globalObject: 'this',
+    library: {
+      name: 'webpackNumbers',
+      type: 'umd',
+    },
   },
 };

现在 webpack 将捆绑一个可以与 CommonJS、AMD 和脚本标签一起工作的库。

外部化 Lodash

现在,如果您运行 npx webpack,您会发现创建了一个相当大的捆绑包。如果您检查该文件,您会发现 lodash 已与您的代码捆绑在一起。在这种情况下,我们更愿意将 lodash 视为对等依赖项。这意味着消费者应该已经安装了 lodash。因此,您可能希望将此外部库的控制权交给您的库的消费者。

这可以通过使用 externals 配置来完成

webpack.config.js

  const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'webpack-numbers.js',
      library: {
        name: "webpackNumbers",
        type: "umd"
      },
    },
+   externals: {
+     lodash: {
+       commonjs: 'lodash',
+       commonjs2: 'lodash',
+       amd: 'lodash',
+       root: '_',
+     },
+   },
  };

这意味着您的库期望在消费者的环境中提供名为lodash的依赖项。

外部限制

对于使用依赖项中多个文件的库

import A from 'library/one';
import B from 'library/two';

// ...

您将无法通过在 externals 中指定library来将它们从捆绑包中排除。您需要逐个排除它们,或者使用正则表达式。

module.exports = {
  //...
  externals: [
    'library/one',
    'library/two',
    // Everything that starts with "library/"
    /^library\/.+$/,
  ],
};

最后步骤

按照生产指南中提到的步骤优化您的生产输出。让我们还将生成的捆绑包的路径添加为包的main字段,并使用package.json

package.json

{
  ...
  "main": "dist/webpack-numbers.js",
  ...
}

或者,按照本指南将其添加为标准模块

{
  ...
  "module": "src/index.js",
  ...
}

main指的是package.json中的标准,而module指的是一个提案,允许 JavaScript 生态系统升级以使用 ES2015 模块,而不会破坏向后兼容性。

现在您可以将其发布为 npm 包,并在unpkg.com上找到它,以将其分发给您的用户。

10 位贡献者

pksjcejohnstewsimon045angelmarioaccbyzykEugeneHlushkoAnayaDesignchenxsanwizardofhogwarts