Webpack 創(chuàng)建 library

2023-05-17 16:36 更新

除了打包應(yīng)用程序,webpack 還可以用于打包 JavaScript library。以下指南適用于希望簡化打包策略的 library 作者。

創(chuàng)建一個 library

假設(shè)我們正在編寫一個名為 webpack-numbers 的小的 library,可以將數(shù)字 1 到 5 轉(zhuǎn)換為文本表示,反之亦然,例如將 2 轉(zhuǎn)換為 'two'。

基本的項(xiàng)目結(jié)構(gòu)可能如下所示:

project

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

使用 npm 初始化項(xiàng)目,然后安裝 webpack,webpack-cli 和 lodash:

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

我們將 lodash 安裝為 devDependencies 而不是 dependencies,因?yàn)槲覀儾恍枰獙⑵浯虬轿覀兊膸熘?,否則我們的庫體積很容易變大。

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 中。

Expose the Library

到目前為止,一切都應(yīng)該與打包應(yīng)用程序一樣,這里是不同的部分 - 我們需要通過 output.library 配置項(xiàng)暴露從入口導(dǎo)出的內(nèi)容。

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",
    },
  };

我們將入口起點(diǎn)公開為 webpackNumbers,這樣用戶就可以通過 script 標(biāo)簽使用它:

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

然而它只能通過被 script 標(biāo)簽引用而發(fā)揮作用,它不能運(yùn)行在 CommonJS、AMD、Node.js 等環(huán)境中。

作為一個庫作者,我們希望它能夠兼容不同的環(huán)境,也就是說,用戶應(yīng)該能夠通過以下方式使用打包后的庫:

  • CommonJS module require:
    const webpackNumbers = require('webpack-numbers');
    // ...
    webpackNumbers.wordToNum('Two');
  • AMD module require:
    require(['webpackNumbers'], function (webpackNumbers) {
      // ...
      webpackNumbers.wordToNum('Two');
    });
  • script tag:
    <!DOCTYPE html>
    <html>
      ...
      <script src="https://example.org/webpack-numbers.js" rel="external nofollow"  rel="external nofollow" ></script>
      <script>
        // ...
        // Global variable
        webpackNumbers.wordToNum('Five');
        // Property in the window object
        window.webpackNumbers.wordToNum('Five');
        // ...
      </script>
    </html>

我們更新 output.library 配置項(xiàng),將其 type 設(shè)置為 'umd':

 const path = require('path');

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

現(xiàn)在 webpack 將打包一個庫,其可以與 CommonJS、AMD 以及 script 標(biāo)簽使用。

外部化 lodash

現(xiàn)在,如果執(zhí)行 webpack,你會發(fā)現(xiàn)創(chuàng)建了一個體積相當(dāng)大的文件。如果你查看這個文件,會看到 lodash 也被打包到代碼中。在這種場景中,我們更傾向于把 lodash 當(dāng)作 peerDependency。也就是說,consumer(使用者) 應(yīng)該已經(jīng)安裝過 lodash 。因此,你就可以放棄控制此外部 library ,而是將控制權(quán)讓給使用 library 的 consumer。

這可以使用 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: '_',
+     },
+   },
  };

這意味著你的 library 需要一個名為 lodash 的依賴,這個依賴在 consumer 環(huán)境中必須存在且可用。

外部化的限制

對于想要實(shí)現(xiàn)從一個依賴中調(diào)用多個文件的那些 library:

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

// ...

無法通過在 externals 中指定整個 library 的方式,將它們從 bundle 中排除。而是需要逐個或者使用一個正則表達(dá)式,來排除它們。

module.exports = {
  //...
  externals: [
    'library/one',
    'library/two',
    // 匹配以 "library/" 開始的所有依賴
    /^library\/.+$/,
  ],
};

最終步驟

遵循 生產(chǎn)環(huán)境 指南中提到的步驟,來優(yōu)化生產(chǎn)環(huán)境下的輸出結(jié)果。那么,我們還需要將生成 bundle 的文件路徑,添加到 package.json 中的 main 字段中。

package.json

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

或者,按照這個 指南,將其添加為標(biāo)準(zhǔn)模塊:

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

這里的 key(鍵) main 是參照 package.json 標(biāo)準(zhǔn),而 module 是參照 一個提案,此提案允許 JavaScript 生態(tài)系統(tǒng)升級使用 ES2015 模塊,而不會破壞向后兼容性。

現(xiàn)在,你可以 將其發(fā)布為一個 npm package,并且在 unpkg.com 找到它,并分發(fā)給你的用戶。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號