溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

如何使用webpack構(gòu)建一個(gè)庫(kù)

發(fā)布時(shí)間:2021-10-18 13:49:01 來(lái)源:億速云 閱讀:152 作者:小新 欄目:web開發(fā)

這篇文章主要為大家展示了“如何使用webpack構(gòu)建一個(gè)庫(kù)”,內(nèi)容簡(jiǎn)而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“如何使用webpack構(gòu)建一個(gè)庫(kù)”這篇文章吧。

輸出產(chǎn)物

構(gòu)建一個(gè)庫(kù)與構(gòu)建一個(gè)一般應(yīng)用最大的不同點(diǎn)在于構(gòu)建完成后輸出的產(chǎn)物。

一般應(yīng)用構(gòu)建完成后會(huì)輸出:

  • 一個(gè) html 文件

  • 一個(gè) js 入口 chunk 、若干子 chunk

  • 若干 css 文件

  • 若干其它資源,如圖片、字體文件等

雖然輸出的資源非常多,但實(shí)際上所有的依賴、加載關(guān)系都已經(jīng)從 html 文件開始一層一層定下來(lái)了,換句話說,這個(gè) html 文件實(shí)際上就是整個(gè)應(yīng)用的入口。

一個(gè)庫(kù)構(gòu)建完成后會(huì)輸出:

  • 一個(gè) CommonJS 格式的 js 文件

  • 一個(gè)未壓縮的 UMD 格式的 js 文件

  • 一個(gè)已壓縮的 UMD 格式的 js 文件

  • 可能包括若干的 css 文件

  • 可能包括若干的其它資源文件

庫(kù)的入口分別是上面羅列的 js 文件;你可能會(huì)奇怪,一個(gè)庫(kù)怎么會(huì)有3個(gè)入口文件呢?莫急,且聽我一一道來(lái)。

CommonJS

CommonJS 是 Node.js 推行的一種模塊化規(guī)范,主要語(yǔ)法包括module.exports、require()等;而我們?cè)谑褂?webpack 引入 npm 包時(shí),實(shí)際上是處于 Node.js 環(huán)境,由此可知,這個(gè) CommonJS 格式的入口 js 文件(<庫(kù)名稱>.common.js)是供其它應(yīng)用在 Node.js 環(huán)境下引入 npm 包使用的。由于在引用 npm 包時(shí)一般不會(huì)過多考慮 npm 包的體積(在構(gòu)建自己的應(yīng)用時(shí)如有需要可自行壓縮),且為了方便調(diào)試,因此該 js 入口文件是沒有經(jīng)過壓縮的。

UMD

UMD 是一個(gè)模塊化規(guī)范大雜燴,除了兼容 CommonJS 外,它還兼容 AMD 模塊化規(guī)范,以及最傳統(tǒng)的全局變量模式。

這邊稍微介紹一下 AMD 規(guī)范, AMD 全稱 Asyncchronous Module Definition ,一般應(yīng)用在瀏覽器端(這是與 CommonJS規(guī)范最大的不同點(diǎn)),最著名的 AMD 加載器是 RequireJS 。目前由于 webpack 的流行, AMD 這一模塊化方案已逐漸退出市場(chǎng)。

全局變量模式就很好理解了,就是把庫(kù)的入口掛載在一個(gè)全局變量(如window.xxx)上,頁(yè)面上的任何位置都能隨時(shí)取用,屬于最傳統(tǒng)的 js 插件加載方案。

由上可知, UMD 格式的入口 js 文件,既可以用于引用 npm 包的場(chǎng)景(未壓縮的版本,即<庫(kù)名稱>.umd.js),也可以直接用于瀏覽器端(已壓縮的版本,即<庫(kù)名稱>.umd.min.js)。

如何構(gòu)建不同模塊化規(guī)范的庫(kù)文件

目前, webpack 不支持同時(shí)生成多份入口 js 文件,因此需要分多次來(lái)進(jìn)行構(gòu)建。

關(guān)鍵的 webpack 配置是:

  • CommonJS:output.libraryTarget: "commonjs2"

  • UMD:output.libraryTarget: "umd"

對(duì)于 UMD ,我們還需要設(shè)置全局變量名稱,即output.library: "LibraryName"。

為了壓縮構(gòu)建出來(lái)的文件,最簡(jiǎn)單的方法是在 CLI 中調(diào)用 webpack 命令時(shí)帶上 mode 參數(shù),如webpack --mode=production;這是因?yàn)楫?dāng) mode 的值為production時(shí), webpack 會(huì)自動(dòng)啟用 UglifyJsPlugin 對(duì)源碼進(jìn)行壓縮。

輸出版本信息

我在某公司工作時(shí),該公司對(duì)第三方依賴抓得很緊,所有在項(xiàng)目里使用的第三方依賴都必須申請(qǐng)且審核通過后才可使用;且申請(qǐng)時(shí)是精確到具體版本的,未申請(qǐng)的軟件版本也一概不允許使用。某些第三方依賴無(wú)論在文件內(nèi)容上,還是在文件名稱上,都沒有體現(xiàn)出版本號(hào),這就對(duì)我們識(shí)別這類第三方依賴產(chǎn)生障礙,這是我們開發(fā)自己的庫(kù)時(shí)需要引以為戒的。

在構(gòu)建庫(kù)時(shí),我們完全可以利用 webpack 把庫(kù)的信息直接輸出到文件內(nèi)容里,有了這“身份信息”,用戶使用起來(lái)也會(huì)格外安心。

輸出庫(kù)版本信息的方法是使用 webpack.BannerPlugin ,最簡(jiǎn)單的使用方法如下:

const pgk = require('./package.json');
const banner = `
${pkg.name}
${pkg.description}\n
@version v${pkg.version}
@homepage ${pkg.homepage}
@repository ${pkg.repository.url}\n
(c) 2019 Array-Huang
Released under the MIT License.
hash: [hash]
`;

/* webpack 配置 */
{
    // ...其它配置
    plugins: [
        // ...其它 plugin 配置
        new webpack.BannerPlugin(banner);
    ]
}

最終生成出來(lái)的效果是:

/*!
 * 
 * vue-directive-window
 * Vue.js directive that enhance your Modal Window, support drag, resize and maximize.
 * 
 * @version v0.7.5
 * @homepage https://github.com/Array-Huang/vue-directive-window
 * @repository git+https://github.com/Array-Huang/vue-directive-window.git
 * 
 * (c) 2019 Array-Huang
 * Released under the MIT License.
 * hash: dc6c11a1e50821f4444a
 * 
 */

source map

如果庫(kù)的用戶是直接通過在瀏覽器里加載你的庫(kù)來(lái)使用的話,那么提供一份 source map 文件是非常有必要的;這是因?yàn)槟愕膸?kù)在經(jīng)過 webpack 構(gòu)建,甚至壓縮后,與源代碼已經(jīng)大相徑庭了,用戶將難以在瀏覽器中進(jìn)行調(diào)試;但如果你能為自己的庫(kù)附上一份 source map ,瀏覽器開發(fā)者工具會(huì)調(diào)用 source map 來(lái)幫助解析,用戶的調(diào)試體驗(yàn)會(huì)更接近于調(diào)試庫(kù)的源碼。

相應(yīng)的 webpack 配置為:

// webpack 配置
{
    // ...其它配置
    devtool: 'cheap-module-source-map'
}

webpack 支持多種類型的 source map ,不同類型的 source map 在生成速度、支持功能(如 babel )、調(diào)試位置偏移等問題上均有不同表現(xiàn),我這邊只做推薦:

  • 開發(fā)環(huán)境:cheap-module-eval-source-map

  • 生產(chǎn)環(huán)境:cheap-module-source-map

關(guān)于其它類型的 source map ,請(qǐng)查看 webpack 官方文檔的 devtool 章節(jié)。

排除第三方依賴

與一般應(yīng)用不一樣,在開發(fā)庫(kù)的時(shí)候,我們應(yīng)盡量避免引入第三方庫(kù)(構(gòu)建過程中使用的工具鏈除外),因?yàn)檫@些第三方庫(kù)會(huì)讓我們寫的庫(kù)的大小猛增;很可能會(huì)出現(xiàn)這樣的情況:我們自己寫的小功能只有幾百行代碼的邏輯,構(gòu)建出來(lái)的庫(kù)卻有幾百k,那這樣的庫(kù)意義就不大了。

但我們的確也很難避免使用第三方庫(kù),那該咋辦呢?

// webpack 配置
{
    // ...其它配置
    externals: {
        lodash: {
            commonjs: 'lodash',
            commonjs2: 'lodash',
            amd: 'lodash',
            root: '_'
        }
    }
}

使用上述配置后,我們構(gòu)建出來(lái)的庫(kù)中就不會(huì)包含配置中指定的第三方庫(kù)(例子中為lodash)了,下面來(lái)一一詳解:

  • commonjscommonjs2項(xiàng)都是指明用戶在 node.js 環(huán)境下使用當(dāng)前庫(kù)時(shí),以 CommonJS 的方式來(lái)加載名為lodash的 npm 包。

  • amd項(xiàng)表示在瀏覽器中加載運(yùn)行本庫(kù)時(shí),本庫(kù)會(huì)試圖以 AMD 的方式來(lái)加載名為lodash的 AMD 模塊。

  • root項(xiàng)表示在瀏覽器中加載運(yùn)行本庫(kù)時(shí),本庫(kù)會(huì)試圖取全局變量window._(通過<script>標(biāo)簽加載lodash.js時(shí), lodash 會(huì)把自己注入到全局變量window._中)。

與一般應(yīng)用不一樣的 externals 配置

在一般應(yīng)用中,你或許會(huì)看到這樣的 externals 配置:

// webpack 配置
{
    // ...其它配置
    externals: {
        lodash: '_'
    }
}

這樣的 externals 配置方式意味著:無(wú)論在什么環(huán)境,都要取_這個(gè)全局變量;如果當(dāng)前是在一般應(yīng)用且確定已經(jīng)使用<script>來(lái)加載指定的第三方庫(kù)(比如 jQuery、 Vue 等核心庫(kù),的確很常以這種方式來(lái)加載),當(dāng)然大可直接這樣用;但我們作為庫(kù)的作者,應(yīng)提供更寬松更靈活的使用方式。

完整的 webpack 配置示例

由于構(gòu)建不同模塊化規(guī)范的庫(kù)需要不同的 webpack 配置(其實(shí)也只是稍有不同)來(lái)進(jìn)行多次構(gòu)建,因此本文只針對(duì)構(gòu)建 UMD 格式且已壓縮這一場(chǎng)景來(lái)展示最簡(jiǎn)單的 webpack 配置示例;如果想知道如何更有效率地拼接 webpack 配置,請(qǐng)看 micro-schema-validator 項(xiàng)目的 webpack 配置文件:

// webpack.config.js
const webpack = require('webpack');
const pkg = require('./package.json'); // 把 package.json 作為信息源
const banner = `
${pkg.name}
${pkg.description}\n
@version v${pkg.version}
@homepage ${pkg.homepage}
@repository ${pkg.repository.url}\n
(c) 2019 Array-Huang
Released under the MIT License.
hash: [hash]
`;

module.exports = {
  entry: `${__dirname}/index.js`,
  devtool: 'cheap-module-source-map',
  output: {
    path: `${__dirname}/dist`, // 定義輸出的目錄
    filename: 'micro-schema-validator.min.js', // 定義輸出文件名
    library: 'MicroSchemaValidator', // 定義暴露到瀏覽器環(huán)境的全局變量名稱
    libraryTarget: 'umd', // 指定遵循的模塊化規(guī)范
  },
  /* 排除第三方依賴 */
  externals: {
    lodash: {
      commonjs: 'lodash',
      commonjs2: 'lodash',
      amd: 'lodash',
      root: '_'
    }
  },
  module: {
    rules: [
      {
        test: /(\.jsx|\.js)$/,
        loader: 'babel-loader',
        exclude: /(node_modules|bower_components)/
      },
      {
        test: /(\.jsx|\.js)$/,
        loader: 'eslint-loader',
        exclude: /(node_modules|bower_components)/
      }
    ]
  },
  plugins: [
    new webpack.BannerPlugin(banner) // 輸出項(xiàng)目信息
  ]
};

利用 vue-cli 定制并管理 webpack 配置

對(duì)于 Vue 生態(tài)的庫(kù),如 Vue 組件、Vue 自定義指令等,可以使用 vue-cli (本文特指 vue-cli 3.0 后的版本)根據(jù)你的需求來(lái)定制 webpack 配置,可定制內(nèi)容包括:

  • 是否啟用 Babel

  • 是否接入 TypeScript 語(yǔ)法

  • 是否支持 PWA

  • 是否使用 Vue-Router 和 Vuex

  • 是否使用 CSS 預(yù)處理器,并可選擇具體的 CSS 預(yù)處理器,包括 Sass / Less / Stylus

  • 是否使用 ESLint 和 Prettier

  • 是否接入單元測(cè)試和端對(duì)端測(cè)試(E2E)

定制完成后, vue-cli 將生成一個(gè)種子項(xiàng)目,該項(xiàng)目可執(zhí)行(包括本地開發(fā)和構(gòu)建生產(chǎn)環(huán)境的包)但沒有實(shí)際內(nèi)容(實(shí)際內(nèi)容不還得由你來(lái)寫嘛哈哈)。與一般的腳手架工具相比, vue-cli 除了可以生成 webpack 配置外,還將持續(xù)對(duì)其進(jìn)行管理和維護(hù),如:

  • 提供一個(gè)統(tǒng)一的自定義配置的入口;過往,我們?yōu)榱诉_(dá)到自定義配置的目的,往往會(huì)直接在腳手架工具生成出來(lái)的 webpack 配置上直接進(jìn)行修改,這樣會(huì)導(dǎo)致修改點(diǎn)非常分散,難以讓自定義的 webpack 配置在其它項(xiàng)目復(fù)用;而使用 vue-cli 后,所有對(duì) webpack 配置的修改點(diǎn)都被集中管理起來(lái)了,需要復(fù)用的話,直接把這自定義配置文件(vue.config.js)遷移到別的項(xiàng)目即可。

  • 提供持續(xù)更新 webpack 配置的機(jī)制;假如現(xiàn)在有一個(gè)開源庫(kù),我為了達(dá)到自己的目的,肆意在庫(kù)源碼上修改,那么當(dāng)我需要升級(jí)該開源庫(kù)的時(shí)候可就犯難了,因?yàn)檫@會(huì)把我之前做的修改都覆蓋掉;同理可得,vue-cli 由于統(tǒng)一了自定義配置的入口,并且是在每次運(yùn)行項(xiàng)目(運(yùn)行項(xiàng)目也是通過執(zhí)行 vue-cli 的命令而非 webpack)時(shí)動(dòng)態(tài)渲染 webpack 配置的,因此項(xiàng)目的 webpack 配置可以隨著 vue-cli 的升級(jí)而不斷升級(jí)了。

  • 提供持續(xù)更新 webpack 工具鏈的機(jī)制;眾所周知, webpack 工具鏈中包含了大量的第三方開源庫(kù),如 Babel 、ESLint 等,這些開源庫(kù)也都是在不斷更新當(dāng)中,在這個(gè)過程中,必然會(huì)不斷產(chǎn)生 Breaking Change ,所幸 vue-cli 通過自身升級(jí)——不斷修改 webpack 配置來(lái)達(dá)到適配最新版第三方開源庫(kù)的目的,而我們的項(xiàng)目也可以以極小的代價(jià)(升級(jí) vue-cli 本身)來(lái)獲取 webpack 工具鏈的不斷更新。

vue-cli 自定義配置示例

摘自 vue-directive-window 項(xiàng)目的  vue.config.js 文件:

const webpack = require('webpack');
const pkg = require('./package.json');

const banner = `
${pkg.name}
${pkg.description}\n
@version v${pkg.version}
@homepage ${pkg.homepage}
@repository ${pkg.repository.url}\n
(c) 2019 Array-Huang
Released under the MIT License.
hash: [hash]
`;

module.exports = {
  chainWebpack: config => {
    config.output.libraryExport('default');
    config.plugin('banner').use(webpack.BannerPlugin, [
      {
        banner,
        entryOnly: true,
      },
    ]);
  },
};

看起來(lái)是不是比上文中最基礎(chǔ)的 webpack 配置還要簡(jiǎn)潔呢?當(dāng)項(xiàng)目的架構(gòu)逐漸豐富起來(lái)后,這個(gè)差距將不斷拉大。

以上是“如何使用webpack構(gòu)建一個(gè)庫(kù)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI