撰寫函式庫

除了應用程式之外,webpack 也可用來綑綁 JavaScript 函式庫。以下指南是針對希望簡化其綑綁策略的函式庫作者而設計。

撰寫函式庫

假設我們正在撰寫一個小型函式庫 webpack-numbers,讓使用者可以將數字 1 到 5 從數字表示轉換為文字表示,反之亦然,例如 2 轉換為「二」。

基本專案結構如下所示

專案

+  |- 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 模組需要:

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

    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\/.+$/,
  ],
};

最後步驟

依照 製作指南 中提到的步驟,最佳化您的輸出以進行製作。我們也將您產生的套件路徑新增為 package.json 中套件的 main 欄位

package.json

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

或者,依照 這份指南 將它新增為標準模組

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

main 鍵是指 package.json 中的標準,而 module 指的是 一個 提案,允許 JavaScript 生態系統升級以使用 ES2015 模組,而不會中斷向後相容性。

現在您可以將其發布為 npm 套件,並在unpkg.com上找到它,以將其分發給您的使用者。

10 貢獻者

pksjcejohnstewsimon045angelmarioaccbyzykEugeneHlushkoAnayaDesignchenxsanwizardofhogwarts