溫馨提示×

溫馨提示×

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

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

如何配置Webpack

發(fā)布時間:2021-10-14 11:34:30 來源:億速云 閱讀:125 作者:iii 欄目:開發(fā)技術(shù)

本篇內(nèi)容主要講解“如何配置Webpack”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“如何配置Webpack”吧!

為什么出現(xiàn) webpack-chain  ?

相信大家都對業(yè)界鼎鼎有名的構(gòu)建工具Webpack并不陌生了,作為目前為止最穩(wěn)定、生產(chǎn)環(huán)境應(yīng)用最多的構(gòu)建打包工具,它固然有著很多優(yōu)勢,比如:

  • 生態(tài)豐富。在社區(qū)有大量的 loader 和 plugin,想要的基本都能找到。

  • 可插拔的插件機制?;?Tapable 實現(xiàn)的可擴展架構(gòu)。

  • 文檔成熟。有中文版,且一直在更新和維護。

  • 穩(wěn)定性高?,F(xiàn)在正式的前端項目生產(chǎn)環(huán)境下基本用 Webpack 來構(gòu)建,經(jīng)過這么多年業(yè)界的驗證,該踩的坑也都踩的差不多了。

但其實說了這么多優(yōu)勢,大家估計還是對這個東西沒什么好感,因為還有最重要的一點不容忽視,那就是開發(fā)體驗。對于構(gòu)建打包這個事情來說,本來就是工程化當中的一個細節(jié)極其復(fù)雜的環(huán)節(jié),需要輸入大量的配置信息來保證打包結(jié)果符合預(yù)期。在Webpack當中,我們?nèi)绻挥闷渌姆桨?,就只有手動地配置一個巨大的  JavaScript 對象,所有的配置信息都在這個對象當中,這樣原始的方式的確給人體驗很不好,歸納為以下幾個原因:

  1. 鴻蒙官方戰(zhàn)略合作共建——HarmonyOS技術(shù)社區(qū)

  2. 對象過于龐大,直觀上讓人看的眼花繚亂,盡管可以封裝一些邏輯,但還是避免不了深層的嵌套配置;

  3. 難以動態(tài)修改。舉個例子,如果通過腳本動態(tài)修改一些配置信息,比如刪除 babel-loader 的一個  plugin,那么需要從最頂層的配置對象,一步步找到到 babel-loader 的位置,然后遍歷插件列表,這個手動尋找和遍歷的過程比較繁瑣。

  4. 難以共享配置。如果你嘗試跨項目共享 webpack 配置對象,那后續(xù)的修改就會變的混亂不堪,因為你需要動態(tài)地修改原來的配置。

社區(qū)當中也有人發(fā)現(xiàn)了這些痛點,于是出現(xiàn)了針對Webpack的流式配置方案——webpack-chain。

webpack-chain 核心概念

其實真正學會  webpack-chain,我覺得首先不是去學習具體每個屬性的配置方法,而是理解webpack-chain核心的兩個對象——ChainedMap和ChainedSet。

什么是 ChainMap ?

比如我現(xiàn)在配置路徑別名:

config.resolve.alias   .set(key, value)   .set(key, value)   .delete(key)   .clear()

那么,現(xiàn)在的 alis  對象就是一個ChainMap。如果一個屬性在webpack-chain當中標記為ChainMap之后,它會有一些額外的方法,并且允許這些鏈式調(diào)用(如上面的示例)。

接下來就來一個個認識這些方法:

// 清空當前 Map 的所有屬性 clear() // 通過鍵值從 Map 移除單個配置. delete(key) // Map中是否存在一個配置值的特定鍵,返回真或假 has(key) // 返回 Map中已存儲的所有值的數(shù)組 values() //  提供一個對象,這個對象的屬性和值將映射進 Map。第二個參數(shù)為一個數(shù)組,表示忽略哪些屬性 merge(obj, omit) // handler: ChainedMap => ChainedMap // 一個把ChainedMap實例作為單個參數(shù)的函數(shù) batch(handler) // condition: Boolean // whenTruthy: ChainMap -> any, 條件為真時執(zhí)行 // whenFalsy: ChainSet -> any, 條件為假時執(zhí)行 when(condition, whenTruthy, whenFalsy) // 獲取 Map 中相應(yīng)鍵的值 get(key) // 先調(diào)用 get,如果找不到對應(yīng)的值, 就返回 fn 函數(shù)返回的結(jié)果 getOrCompute(key, fn) // 配置鍵值對 set(key, value)

這些方法的返回對象也都是 ChainMap,這樣可以實現(xiàn)鏈式調(diào)用,簡化操作。在 Webpack中,大部分的對象都是  ChainMap,具體大家可以去源碼當中看看,實現(xiàn)并不復(fù)雜。

ChainMap 是webpack-chain當中非常重要的一個數(shù)據(jù)結(jié)構(gòu),封裝了鏈式調(diào)用的方法,以至于后面所有 ChainMap  類型的配置都可以直接復(fù)用ChainMap本身的這些方法,非常方便。

什么是 ChainSet ?

跟 ChainMap 類似,封裝了自己的一套 API:

// 末尾增加一個值 add(value) // 在開始位置增加一個值 prepend(value) // 清空 set 內(nèi)容 clear() // 刪除某個值 delete(value) // 判斷是否有某個值 has(value) // 返回值列表 values() // 合并給定的數(shù)組到 Set 尾部。 merge(arr) // handler: ChainSet => ChainSet // 一個把 ChainSet 實例作為單個參數(shù)的函數(shù) batch(handler) // condition: Boolean // whenTruthy: ChainSet -> any, 條件為真時執(zhí)行 // whenFalsy: ChainSet -> any, 條件為假時執(zhí)行 when(condition, whenTruthy, whenFalsy)

ChainSet 的作用和ChainMap類似,也是封裝了底層鏈式調(diào)用的  API,在需要操作Webpack配置當中的數(shù)組類型的屬性時,通過調(diào)用ChainSet的方法即可完成。

速記方法

對于 ChainMap,有這樣一種簡化的寫法,官網(wǎng)稱之為速記寫法:

devServer.hot(true);  // 上述方法等效于: devServer.set('hot', true);

因此,在實際的webpack-chain配置中,可以經(jīng)??吹街苯?.屬性()這樣調(diào)用方式,是不是感覺很巧妙?源碼當中的實現(xiàn)非常簡單:

extend(methods) {   this.shorthands = methods;   methods.forEach(method => {     this[method] = value => this.set(method, value);   });   return this; }

在ChainMap初始化的時候,會調(diào)用 extend 方法,然后把屬性列表作為 methods參數(shù)直接傳入,然后通過下面一行代碼間接調(diào)用 set  方法:

this[method] = value => this.set(method, value);

這樣的設(shè)計也是值得學習的。

配置 Webpack

首先,需要創(chuàng)建一個新的配置對象:

const Config = require('webpack-chain');  const config = new Config();  // 一系列鏈式操作之后 // 得到最后的 webpack 對象 console.log(config.toConfig())

然后依次配置 resolve、entry、output、module、plugins、optimization 對象,本文關(guān)鍵還是帶大家能夠落地  webpack-chain,因此詳細介紹一下各個配置的使用方法。

entry 和 output

這里列舉一個常用的配置,由于 Webpack 在 entry 和 output 掛了太多屬性,大家參考 Webpack  官方文檔照著如下的方式去配就好了。

config.entryPoints.clear() // 會把默認的入口清空 config.entry('entry1').add('./src/index1.tsx')//新增入口 config.entry('entry2').add('./src/index2.tsx')//新增入口  config.output       .path("dist")       .filename("[name].[chunkhash].js")       .chunkFilename("chunks/[name].[chunkhash].js")       .libraryTarget("umd")

alias

對于路徑別名的配置,也是幾乎所有項目必不可少的部分,配置方式如下:

// 可以發(fā)現(xiàn) resolve.alias 其實是一個 ChainMap 對象 config.resolve.alias   .set('assets',resolve('src/assets'))   .set('components',resolve('src/components'))   .set('static',resolve('src/static'))   .delete('static') // 刪掉指定的別名

plugins

插件的配置可以說是相當重要的一個環(huán)節(jié)了,webpack-chain 當中的配置會和平時的配置有些不同,讓我們來具體看看。

1. 添加一個插件

// 先指定名字(這個名字是自定義的),然后通過 use 添加插件 config   .plugin(name)   .use(WebpackPlugin, args)

舉個例子:

const ExtractTextPlugin = require('extract-text-webpack-plugin');  // 先指定名字(這個名字可以自定義),然后通過 use 添加插件,use 的第二個參數(shù)為插件參數(shù),必須是一個數(shù)組,也可以不傳 config.plugin('extract')   .use(ExtractTextPlugin, [{     filename: 'build.min.css',     allChunks: true,   }])

2. 移除插件

移除一個插件很簡單,還記得添加插件時我們指定了每個插件的 name 嗎?現(xiàn)在通過這個 name 移除即可:

config.plugins.delete('extract')

3. 指定插件在 xx 插件之前/之后調(diào)用

比如,我現(xiàn)在需要指定 html-webpack-plugin 這個插件在剛剛寫的 extract 插件之前執(zhí)行,那么這么寫就行了:

const htmlWebpackPlugin = require('html-webpack-plugin');  config.plugin('html')   .use(htmlWebpackPlugin)   .before('extract')

通過 before 方法,傳入另一個插件的 name 即可,表示在另一個插件之前執(zhí)行。

同樣,如果需要在 extract 插件之后執(zhí)行,調(diào)用 after 方法:

config.plugin('html')   .use(htmlWebpackPlugin)   .after('extract')

4. 動態(tài)修改插件參數(shù)

我們也可以用 webpack-chain 來動態(tài)修改插件的傳參,舉個例子:

// 使用 tap 方法修改參數(shù) config   .plugin(name)   .tap(args => newArgs)

5. 修改插件初始化過程

我們也可以自定義插件的實例化的過程,比如下面這樣:

// 通過 init 方法,返回一個實例,這將代替原有的實例化過程 config   .plugin(name)   .init((Plugin, args) => new Plugin(...args));

loader

loader 是 Webpack 中必不可少的一個配置,下面我們來看看 loader 的相關(guān)操作。

1. 添加一個 loader

config.module   .rule(name)     .use(name)       .loader(loader)       .options(options)

舉個例子:

config.module   .rule('ts')   .test(/\.tsx?/)   .use('ts-loader')     .loader('ts-loader')     .options({       transpileOnly: true     })     .end()

2. 修改 loader 參數(shù)

可通過 tap 方法修改 loader 的參數(shù):

config.module   .rule('ts')   .test(/\.tsx?/)   .use('ts-loader')     .loader('ts-loader')     .tap(option => {       // 一系列       return options;     })     .end()

在所有的配置完成之后,可以通過調(diào)用config.toConfig()來拿到最后的配置對象,可以直接作為webpack的配置。

3. 移除一個 loader

// 通過 uses 對象的 delete 方法,根據(jù) loader 的 name 刪除 config.module   .rule('ts')   .test(/\.tsx?/)   .uses.delete('ts-loader')

optimization

Webpack  中的optimization也是一個比較龐大的對象,參照官方文檔:https://webpack.js.org/configuration/optimization/。

這里以其中的 splitChunks 和 minimizer 為例來配置一下:

config.optimization.splitChunks({      chunks: "async",      minChunks: 1, // 最小 chunk ,默認1      maxAsyncRequests: 5, // 最大異步請求數(shù), 默認5      maxInitialRequests : 3, // 最大初始化請求數(shù),默認3      cacheGroups:{ // 這里開始設(shè)置緩存的 chunks          priority: 0, // 緩存組優(yōu)先級          vendor: { // key 為entry中定義的 入口名稱              chunks: "initial", // 必須三選一: "initial" | "all" | "async"(默認就是async)              test: /react|vue/, // 正則規(guī)則驗證,如果符合就提取 chunk              name: "vendor", // 要緩存的 分隔出來的 chunk 名稱              minSize: 30000,              minChunks: 1,          }      } });  // 添加一個 minimizer config.optimization   .minimizer('css')   .use(OptimizeCSSAssetsPlugin, [{ cssProcessorOptions: {} }]) // 移除 minimizer config.optimization.minimizers.delete('css') // 修改 minimizer 插件參數(shù) config.optimization   .minimizer('css')   .tap(args => [...args, { cssProcessorOptions: { safe: false } }])

善用條件

配置之前提到過,對于ChainSet和ChainMap對象都有條件配置方法when,可以在某些很多場景下取代  if-else,保持配置的鏈式調(diào)用,讓代碼更加優(yōu)雅。

config.when(   process.env.NODE === 'production',   config.plugin('size').use(SizeLimitPlugin) )

到此,相信大家對“如何配置Webpack”有了更深的了解,不妨來實際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進入相關(guān)頻道進行查詢,關(guān)注我們,繼續(xù)學習!

向AI問一下細節(jié)

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

AI