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

今天就跟大家聊聊有關(guān)如何使用webpack構(gòu)建一個(gè)js庫(kù),可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。

公司主營(yíng)業(yè)務(wù):成都網(wǎng)站制作、網(wǎng)站建設(shè)、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競(jìng)爭(zhēng)能力。創(chuàng)新互聯(lián)是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對(duì)我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)推出息烽免費(fèi)做網(wǎng)站回饋大家。

前言

在前文中,我說過本系列文章的受眾是在現(xiàn)代前端體系下能夠熟練編寫業(yè)務(wù)代碼的同學(xué),因此本文在介紹 webpack 配置時(shí),僅提及構(gòu)建一個(gè)庫(kù)所特有的配置,其余配置請(qǐng)參考 webpack 官方文檔。

輸出產(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 文件開始一層一層定下來了,換句話說,這個(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è)入口文件呢?莫急,且聽我一一道來。

CommonJS

CommonJS是 Node.js 推行的一種模塊化規(guī)范,主要語法包括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)上,頁面上的任何位置都能隨時(shí)取用,屬于最傳統(tǒng)的 js 插件加載方案。

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

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

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

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

  • CommonJS:output.libraryTarget: "commonjs2"
  • UMD:output.libraryTarget: "umd"

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

為了壓縮構(gòu)建出來的文件,最簡(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)的軟件版本也一概不允許使用。某些第三方依賴無論在文件內(nèi)容上,還是在文件名稱上,都沒有體現(xiàn)出版本號(hào),這就對(duì)我們識(shí)別這類第三方依賴產(chǎn)生障礙,這是我們開發(fā)自己的庫(kù)時(shí)需要引以為戒的。

在構(gòu)建庫(kù)時(shí),我們完全可以利用 webpack 把庫(kù)的信息直接輸出到文件內(nè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);
    ]
}

最終生成出來的效果是:

/*!
 * 
 * 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ù)來使用的話,那么提供一份 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 來幫助解析,用戶的調(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)建出來的庫(kù)卻有幾百k,那這樣的庫(kù)意義就不大了。

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

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

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

  • commonjscommonjs2項(xiàng)都是指明用戶在 node.js 環(huán)境下使用當(dāng)前庫(kù)時(shí),以 CommonJS的方式來加載名為lodash的 npm 包。
  • amd項(xiàng)表示在瀏覽器中加載運(yùn)行本庫(kù)時(shí),本庫(kù)會(huì)試圖以 AMD的方式來加載名為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 配置方式意味著:無論在什么環(huán)境,都要取_這個(gè)全局變量;如果當(dāng)前是在一般應(yīng)用且確定已經(jīng)使用<script>來加載指定的第三方庫(kù)(比如 jQuery、 Vue 等核心庫(kù),的確很常以這種方式來加載),當(dāng)然大可直接這樣用;但我們作為庫(kù)的作者,應(yīng)提供更寬松更靈活的使用方式。

完整的 webpack 配置示例

由于構(gòu)建不同模塊化規(guī)范的庫(kù)需要不同的 webpack 配置(其實(shí)也只是稍有不同)來進(jìn)行多次構(gòu)建,因此本文只針對(duì)構(gòu)建 UMD 格式且已壓縮這一場(chǎng)景來展示最簡(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ù)你的需求來定制 webpack 配置,可定制內(nèi)容包括:

  • 是否啟用 Babel
  • 是否接入 TypeScript 語法
  • 是否支持 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)容不還得由你來寫嘛哈哈)。與一般的腳手架工具相比, vue-cli 除了可以生成 webpack 配置外,還將持續(xù)對(duì)其進(jìn)行管理和維護(hù),如:

  • 提供一個(gè)統(tǒng)一的自定義配置的入口;過往,我們?yōu)榱诉_(dá)到自定義配置的目的,往往會(huì)直接在腳手架工具生成出來的 webpack 配置上直接進(jìn)行修改,這樣會(huì)導(dǎo)致修改點(diǎn)非常分散,難以讓自定義的 webpack 配置在其它項(xiàng)目復(fù)用;而使用 vue-cli 后,所有對(duì) webpack 配置的修改點(diǎn)都被集中管理起來了,需要復(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 配置來達(dá)到適配最新版第三方開源庫(kù)的目的,而我們的項(xiàng)目也可以以極小的代價(jià)(升級(jí) vue-cli 本身)來獲取 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,
      },
    ]);
  },
};

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

實(shí)例項(xiàng)目代碼介紹

在我的工作生涯中,我寫的絕大部分庫(kù)都是為公司的項(xiàng)目寫的,很可惜無法帶出來,但我會(huì)以我最近寫的兩個(gè)開源庫(kù):javascript-library-boilerplate 和  vue-directive-window 來作為實(shí)例項(xiàng)目代碼來輔助介紹。

javascript-library-boilerplate

javascript-library-boilerplate是一個(gè)現(xiàn)代前端生態(tài)下快速構(gòu)建 javascript 庫(kù)的腳手架(或稱種子項(xiàng)目,或稱示例代碼,看你理解了),本庫(kù)支持 GitHub 的 repository templates 功能,你可以直接在項(xiàng)目首頁點(diǎn)擊 Use this template來直接套用本腳手架的代碼來創(chuàng)建你自己的 javascript 庫(kù)。

vue-directive-window

vue-directive-window是一個(gè)可以快速讓模態(tài)框(modal)支持類窗口操作的增強(qiáng)庫(kù);類窗口操作主要包括三大類:拖拽移動(dòng)、拖拽調(diào)整窗口尺寸、窗口最大化; vue-directive-window 支持以 Vue 自定義指令或是一般 js 類的方式來調(diào)用。

vue-directive-window 相對(duì)于 javascript-library-boilerplate 來說,更貼近 Vue 生態(tài)圈,如果你最近想為 Vue 生態(tài)圈添磚加瓦,不妨參考一下本項(xiàng)目。

實(shí)例項(xiàng)目代碼介紹

我會(huì)以我最近寫的兩個(gè)開源庫(kù):javascript-library-boilerplate 和  vue-directive-window 來作為實(shí)例項(xiàng)目代碼來輔助介紹。

javascript-library-boilerplate

javascript-library-boilerplate是一個(gè)現(xiàn)代前端生態(tài)下快速構(gòu)建 javascript 庫(kù)的腳手架(或稱種子項(xiàng)目,或稱示例代碼,看你理解了),本庫(kù)支持 GitHub 的 repository templates 功能,你可以直接在項(xiàng)目首頁點(diǎn)擊 Use this template來直接套用本腳手架的代碼來創(chuàng)建你自己的 javascript 庫(kù)。

vue-directive-window

vue-directive-window是一個(gè)可以快速讓模態(tài)框(modal)支持類窗口操作的增強(qiáng)庫(kù);類窗口操作主要包括三大類:拖拽移動(dòng)、拖拽調(diào)整窗口尺寸、窗口最大化; vue-directive-window 支持以 Vue 自定義指令或是一般 js 類的方式來調(diào)用。

vue-directive-window 相對(duì)于 javascript-library-boilerplate 來說,更貼近 Vue 生態(tài)圈,如果你最近想為 Vue 生態(tài)圈添磚加瓦,不妨參考一下本項(xiàng)目。

看完上述內(nèi)容,你們對(duì)如何使用webpack構(gòu)建一個(gè)js庫(kù)有進(jìn)一步的了解嗎?如果還想了解更多知識(shí)或者相關(guān)內(nèi)容,請(qǐng)關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。

文章標(biāo)題:如何使用webpack構(gòu)建一個(gè)js庫(kù)
新聞來源:http://bm7419.com/article42/psdihc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供域名注冊(cè)、虛擬主機(jī)、企業(yè)網(wǎng)站制作、定制開發(fā)、全網(wǎng)營(yíng)銷推廣、網(wǎng)站導(dǎo)航

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

網(wǎng)站托管運(yùn)營(yíng)