簡單說一下 Webpack分包

最近在看有關webpack分包的知識,搜索了很多資料,感覺這一塊很是迷惑,網上的資料講的也迷迷糊糊,這里簡單總結分享一下,也當個筆記。 如有錯誤請指出。

為什么需要分包

我們知道,webpack的作用,是將各種類型的資源,統一轉換成瀏覽器可以直接識別的 Js Css Html 圖片 等等,正如其官網圖描述的一樣

在這個過程中,webpack需要兼容各種模塊化標準 (CommonJs & ESModule),將各種模塊化標準實現的各個模塊,統一打包成一個bundle.js文件,這個文件可以直接被script標簽引用, 被瀏覽器直接識別。

?如果你了解webpack的實現原理,就可以知道,其打包結果本質上是一個自執行函數。 各個模塊被封裝成一個 路徑 => 代碼 的Map,通過入參傳入。 自執行函數內部,有一套邏輯可以讀取,執行這些模塊代碼,并且兼容統一了各種模塊化標準。

說了這么多,webpack給我們的印象是一個 多 歸 一 的構建工具,無論我們有多少的模塊,最后輸出的結果只有bundle.js一個。這就帶來一個問題,如果我們的模塊體積很大,其中可能還包含了圖片等信息,那么從服務端將其下載到本地就需要很大的開銷,可能導致用戶瀏覽器出現長時間白屏的現象。我們需要將邏輯上一個大的bundle.js拆散,根據用戶的需求,動態的下載,保證用戶的體驗。

完成這個拆分工作,就需要用到分包相關的技術。

分包的工作,通常由SplitChunksPlugin完成,其是webpack內部提供的一個插件,我們不需要額外的從NPM上下載這個插件,只需要在 optimization中配置splitChunks屬性即可。

我們可以看到,SplitChunksPlugin是在optimize階段通過鉤入 optimizeChunks鉤子實現分包的

chunks屬性

很多介紹splitchunks的文章都是從 chunks開始介紹的,說這個屬性有三個值

?async(默認)| initial | all?

分別對應,拆分異步模塊,拆分同步模塊,拆分同步和異步模塊

由于默認值是 async 所以通過 import() 動態導入的模塊會被單獨拆分!

現象如此,但是這個理解完全是錯誤的!

webpack默認行為

首先你需要知道,webpack對異步模塊的拆分是webpack的默認行為,和splitChunks無關

?我們很容易驗證,設置splitChunk: false 關閉拆包,對于如下例子:

webpack.config.js// 單一入口entry: {main: "./src/main.js",},main.js
// 通過 import動態導入add模塊 
import("@utils/add").then((module) => {console.log(module.add(100, 200));
});add.js
// 導出一個簡單的 add 函數
export function add(x,y){return x + y
}

入口main.js動態引入了一個 add函數,由于關閉了拆包優化,最后應該只有一個js文件被輸出,但是最終的結果為:

可以觀察到,無論開不開分包優化,webpack對于異步導入的模塊,都會將其單獨作為一個chunk拆分出去,這樣也確保了請求資源的時候不把異步模塊同主模塊一同加載進來,這個是默認行為

add.js
import './commonUtils'
export function add(x,y){return x + y
}

我們改動一下,在add.js中同步引入 commonUtils模塊,打包結果如下:

可以發現,commonUtils模塊被打入了 add.js一起。

對于webpack來說,被異步模塊引入的模塊,如果這個模塊沒有被同步模塊引用過,那么在異步模塊中無論如何被引用,都是異步模塊。

如果我們在 main.js中同步引入 commonUtils

main.js
import '@utils/commonUtils'
import("@utils/add").then((module) => {console.log(module.add(100, 200));
});

可以看到,最終的打包結果中,commonUtils被和main這個同步模塊打包到一起了,如下:

?其實這也好理解,如果一個模塊都已經被同步載入過了,那么就沒必要再費網絡資源去異步請求了,直接復用即可。

雖然同步模塊和異步模塊在默認狀態下可以直接復用,但是這種復用僅僅存在于 同一入口的情況下,看下面例子: 我們增加一個app模塊,在app中異步引入commonUtils模塊,在main中同步引入commonUtils模塊?

webpack.config.jsentry: {app: "./src/app.js",main: "./src/main.js",},app.js
import("@utils/commonUtils").then((module) => {console.log(module);
});main.js
import '@utils/commonUtils'

可以看到,在多入口的情況下,commonUtils被打包了兩次?

為什么多入口之間不能復用,因為webpack要保證每一個入口都是獨立可用的,對于main.js 其單獨使用的時候如果要獲取commonUtils.js 需要將整個main.js完整下載下來,無法保證每個入口的獨立性,所以會單獨打包一份出來。

我們把main.js中的同步引入commonUtils也改成異步,可以發現最終結果中只有一個commonUtils模塊,也就是說異步模塊在不同入口之間是可以復用的

這也符合邏輯,對于每個入口,由于對于commonUtils的載入都是異步的,在一開始載入的時候都不需要同步載入commonUtils,所以自然使用一個獨立模塊即可。?

?說完了這些,我們做個小總結 避免混亂

首先,這些都是在不進行任何分包優化下的情況,一定要明確前提

  1. webpack在默認情況下,會 并且 僅僅會對異步載入的模塊進行獨立分包處理
  2. 對于同步的模塊,webpack默認情況下都會打入主包中同步引入,不會獨立拆包
  3. 異步模塊中無論同步,還是異步的模塊引入 都算成是異步引入?
  4. 在相同入口的情況下,同步引入和異步引入會共享同步引入的模塊,不會單獨異步拆包
  5. 在不同入口下,同步和異步引入相對獨立,無法共用,會打兩份,但是異步模塊之間可以互相共用。

我認為,了解webpack默認行為會對后面的學習減少很多的"彎路",在理解分包現象的時候需要理解到底是splitChunk的優化結果,還是webpack的默認行為。

比方說chunks: async雖然是默認值,但是造成分包的并不是這個屬性的作用,屬于webpack的默認行為!

chunks屬性的真正含義

chunks屬性的真正含義如下

  • async: 僅僅對異步導入的模塊進行splitChunks優化,同步導入的模塊會被忽略,也是chunks的默認值 (默認情況下,splitChunks只對webpack默認拆分出來的異步模塊生效)
  • initial: initial即初始化的意思,瀏覽器初始化加載模塊的時候,會將引用的所有同步模塊都載入,所以initial的含義是,對于同步導入的模塊(即 初始化階段會被載入的模塊) 進行splitChunks優化,對于異步導入的模塊,會被忽略。 我們知道webpack的默認狀態下不會對同步模塊單獨拆包,所以initial就是用來增強其處理同步模塊的功能

瀏覽器初始化的時候,會將同步模塊一口氣都載入,那么分包的意義何在呢?

其實主要目的是對于打包多入口時,在默認情況下,如果兩個如果都引用了某個同步模塊, 為了保證兩個入口的獨立性,這個模塊會被重復兩次打包。initial的作用就是可以把這個共同引用的同步模塊拆分出來,減小打包文件的總體積。

  • all: 對于同步,異步引入的模塊,都會進行splitChunks的優化,這個也是被官方推薦的方式。

很多教程中,說把chunks設置為 all 的作用是除了拆分async 還能拆分第三方vendor(即 node_modules)模塊 這個也是不對的,只是all很強大,開啟之后可以達到拆分第三方模塊的效果,但是絕對不是其作用就是為了拆分第三方模塊。 具體實現原理下面會說

我們看一些例子,如下,我們簡單的設置splitChunks的chunks: async 為了不影響我們觀察打包結果,我們先將minSize minChunks分別設置為 0 和 1 也就是讓拆包大小和引用chunks數不影響chunks本身的效果。

// webpack.config.jsentry: {app1: "./src/app1.js",app: "./src/app.js",main: "./src/main.js",},splitChunks: {chunks: "async",minSize: 0,minChunks: 1,}// app1.js
import"@utils/commonUtils"// app.js
import("@utils/commonUtils").then((module) => {console.log(module);
});// main.js
import"@utils/commonUtils"

未開啟splitChunks優化

開啟 chunks: async? 優化異步模塊

可以看到,打包結果和不設置 splitChunk沒什么兩樣,但是這并不代表其未生效,我們來分析一下

首先,在進行拆包優化之前,由于在三個入口分別同步和異步引入了 commonUtils模塊。 由于在兩個不同入口中,同步異步引用無法復用,webpack的默認行為會把異步的commonUtils拆分出來,并且把同步引入的commonUtils合并到主包中。

優化開始,由于chunks: async 此時只對拆分出來的commonUtils進行拆分,忽略同步的commonUtils 所以此時沒什么可優化拆分的,splitChunks不會對打包結果有什么改變。

我們把chunks改成 initial 即 只對同步模塊進行優化, 可以看到,此時,兩個commonUtils被拆分出來了,由于有兩個入口同步引用了commonUtils,initial模式下,會把這個同步模塊單獨拆分進行復用。但是由于initial模式會忽略異步模塊,所以會導致異步的commonUtils和同步的commonUtils無法復用。

為了解決同步異步的commonUtils不能復用的問題,我們把chunks設置為 all 即 對同步引入和異步引入的模塊都開啟分包優化,此時的打包結果如下:

可以看到,由于對于同步異步的模塊splitChunk都會識別處理,所以commonUtils會被單獨拆分成一個chunk,供同步和異步的引入使用,這樣就達到了對commonUtils的最小化拆分。

再看一個例子,我們引入兩個入口,其中:

app1.js引入一個node_modules下的 lodash模塊
main中引入我們自己定義的 utils/commonUtils.js模塊

webpack.config.js
entry: {app1: "./src/app1.js",main: "./src/main.js",},chunks: all// app1.js
import "lodash";// main.js
import"@utils/commonUtils"

打包結果如下:

你會發現,同樣是被一個入口引用1次,為什么lodash就被單獨拆分了,我們自己定義的包就沒被拆分,而我們已經設置了minSize: 0 也就是模塊大小不會影響拆包,那么為什么第三方模塊就被拆分了,我們自定義的模塊就不會? 這個就要引入我們下面要說的 cacheGroup 緩存組的概念了??

cacheGroups緩存組

緩存組用來定義哪些模塊被拆分成一組,拆分成一組的模塊可以被瀏覽器單獨的緩存,不用在每次更新的時候重新從服務器獲取。

cacheGroups需要配置一個對象,key未緩存組的名稱,value為一個配置對象,其中使用 test屬性匹配模塊的名稱,我們舉個例子:

  splitChunks: {chunks: "all",minSize: 0,minChunks: 1,cacheGroups: {MyUtils: {test: /\/utils\//,minSize: 0,minChunks: 1,name: 'MyUtils'}}
}

上述例子,我們設置一個MyUtils緩存組,其中test匹配路徑中包含 utils的模塊,并且設置其單獨分包名稱為 MyUtils。 其含義是,需要webpack對路徑中包含 utils的模塊單獨拆出來并且合并到一個包里,這個包的名稱為 MyUtils.

可以看到,這時我們自己定義的 utils/commonUtils.js被單獨打包了。

那么回到上面的問題,為什么node_modules的模塊就會被單獨拆分,我們自己寫的模塊就需要我們自定義一個緩存組才能實現拆分? 這是因為webpack內置了兩個 defaultVendors和default兩個緩存組 如下:
?

module.exports = {//...optimization: {splitChunks: {chunks: 'async', // 代碼分割的初始塊類型,默認為異步加載的模塊minSize: 20000, // 生成 chunk 的最小體積(以字節為單位)minRemainingSize: 0, // Webpack 5 新增,確保拆分后剩余的最小大小maxSize: 0, // 嘗試將大于 maxSize 字節的 chunk 拆分為較小的部分minChunks: 1, // 共享該模塊的最小 chunks 數maxAsyncRequests: 30, // 按需加載時的最大并行請求數maxInitialRequests: 30, // 入口點的最大并行請求數automaticNameDelimiter: '~', // 生成名稱時使用的分隔符enforceSizeThreshold: 50000, // Webpack 5 新增,強制執行拆分的體積閾值cacheGroups: { // 緩存組配置defaultVendors: {test: /[\\/]node_modules[\\/]/, // 匹配 node_modules 中的模塊priority: -10, // 優先級reuseExistingChunk: true // 如果當前 chunk 包含已從主 bundle 中拆分出的模塊,則重用該模塊},default: {minChunks: 2, // 被至少兩個 chunks 共享的模塊priority: -20, // 優先級低于 vendorsreuseExistingChunk: true // 重用已存在的 chunk}}}}
};

可以看到,對于路徑包含 /node_modules/的模塊,splitChunks插件會默認將其分到一個緩存組中去,而對于default緩存組,其沒有設置test屬性,意味著沒有匹配到任何緩存組的模塊都會被default緩存組匹配,其優先級priority: -20 低于defaultVendors的-10 為最低優先級的緩存組,可以被當成是一組兜底的緩存策略。

這也就解釋了為什么我們自己定義的commonUtils模塊沒有被單獨拆包,雖然其匹配到了默認的default緩存組,但是由于其內部配置了 minChunks: 2 也就是說當前模塊必須被至少兩個chunk匹配到,才會單獨拆包,而上述例子commUtils只被引用了一次,所以沒有被單獨劃分。

你也許會問? lodash也只被匹配了一次啊? 為什么也被單獨拆包了? 這時因為defaultVendors緩存組沒有配置minChunks,那么會直接使用頂層的minChunks配置,也就是minChunks:1 任何模塊只要被一個chunk引用,就會被單獨拆包 (注意這里是chunks 不是 modules)

注意,cacheGroups這個名字很容易誤導人,其并不是把test匹配到的模塊都合并到一個chunk,還要考慮其中的 minSize minChunks name等等屬性的作用

你可以將其理解為 緩存規則組 把一組決定模塊是否緩存 如何緩存的規則 放到一個組里面,test匹配到某個group就使用這個group的規則。

?cacheGroups的作用原理 & 如何禁用cacheGroups

?回憶一下我們上面的例子,當我們設置cacheGroups時,如果cacheGroups的名稱和默認的 defaultVendors / default 不重復,那么不會覆蓋默認的cacheGroups配置

  splitChunks: {chunks: "all",minSize: 0,minChunks: 1,cacheGroups: {MyUtils: {test: /\/utils\//,minSize: 0,minChunks: 1,name: 'MyUtils'}}
}等價于 splitChunks: {chunks: "all",minSize: 0,minChunks: 1,cacheGroups: {MyUtils: {test: /\/utils\//,minSize: 0,minChunks: 1,name: 'MyUtils'},defaultVendors: {test: /[\\/]node_modules[\\/]/,priority: -10,reuseExistingChunk: true },default: {minChunks: 2, priority: -20, reuseExistingChunk: true }}
}

所以,如果我們不想使用默認配置,不能直接 cacheGroups: {} 而是需要

// 關閉默認cacheGroupscacheGroups: {default: false,defaultVendors: false}

禁用緩存組之后,我們再來看分包結果

可以看到,lodash和commonUtils都沒有被拆分。你也許會疑問了? 即便什么緩存組都沒匹配到 那頂層的默認配置不是還寫著 minChunks:1 呢么?

?

你可以簡單的理解為,cacheGroups是拆包的 “引擎” 只有匹配到了cacheGroups才會啟動分包流程,如果任何的緩存組都沒匹配到,光有頂層的那些配置是沒有任何意義的。

所以你需要記住,在沒有匹配到任何緩存組的情況下,splitChunk不會對模塊進行拆包優化!

所以,回到前面的問題,有些博客說,把chunks設置為all就開啟了對第三方模塊的分包優化 這是不嚴謹的,很可能讓人誤認為拆分第三方模塊是chunks all的效果,但是其實不是的。

由于我們引用第三方模塊大多是同步引入,而chunks默認值為 async,所以默認情況下,我們不會對同步引入的第三方模塊進行分包優化。

當開啟了all的時候,第三方模塊也會被納入分包優化的范圍,而splitChunks又內置了defaultVendors的緩存組,并且沒有設置其minChunks

所以才會拆分出第三方內容,設置chunks: all僅僅是整個拆分流程中的一個環節而已。

minSize

設置chunk的最小尺寸,單位字節(Byte),只有在模塊尺寸大于這個屬性值的時候,才會拆包

commonUtils的尺寸約為40B 當設置頂層minSize: 40 / 50 時,拆分結果如圖

?同時,我們還可以在緩存組的內部設置minSize,其會覆蓋頂層的minSize配置

minChunks?

minChunks限制了模塊的最小chunks引用數,也就是模塊被至少 minChunks 個chunk引用,才會被分割出去。

這里的chunk計數,取決于chunks的配置,如果chunks配置為 async 那么只有異步模塊會進來匹配這個minChunks 如果是inital 那么只有同步模塊會被計算進chunks 如果是all則都被計算。我們看例子

webpack.config.jssplitChunks: {chunks: "initial",minSize: 0,minChunks: 1,cacheGroups: {// 關閉默認緩存組defaultVendors: false,default: false,utils: {test: /\/utils\/commonUtils.js/,minChunks: 3,name: 'MY_UTILS'}}
}entry: {app1: "./src/app1.js",app: "./src/app.js",main: "./src/main.js",},// main.js
import"@utils/commonUtils"//app.js
import("@utils/commonUtils").then((module) => {console.log(module);
});// app1.js
import"@utils/commonUtils"

main和app1 同步引用了commonUtils模塊,app異步引入commonUtils

我們設置commonUtils的緩存組minChunks: 3 chunks: initial 此時打包如下

可以看到 commonUtils被打包了3份 為什么?

1. webpack默認情況下,會把異步app.js中的common模塊單獨拆分

2. 由于chunks為initial 所以只會統計同步引入common模塊的chunks數 只有app和main兩個,所以不滿足minChunks: 3的配置,不分包,會對app1 main 兩個chunk都生成一份commonUtils

當我們設置minChunks: 2

可以看到,main和app1中的common模塊被抽取出來了,但是由于chunks為initial 沒有app中異步分離出來的commonUtils復用。 由于異步模塊會被忽略,splitChunks不知道有一份可以被復用的commonUtils已經被生成了。

為了解決,我們設置chunks為all,并且設置minChunks:3 如下:

    splitChunks: {chunks: "all",minSize: 0,minChunks: 1,cacheGroups: {defaultVendors: false,default: false,utils: {test: /\/utils\/commonUtils.js/,minChunks: 3,},},}

此時,只有一份common被抽取,如下:

其過程為
1. webpack默認抽取app中的異步common模塊

2. 分包優化的時候 由于同步異步模塊都會被記入minChunks統計,滿足minChunks: 3的條件 所以commonUtils會被單獨拆包,但是發現webpack默認已經拆了一份common出來 就直接復用即可。

而對于chunks initial的情況下,由于忽略了異步的common模塊,所以無法對已經拆出來的模塊進行復用。

enforce 強制拆分

enforce通常用在緩存組內,如果某個緩存組內設置了enforce: true 那么這個緩存組會忽略全局的 minSize minChunks等等這些限制,僅以緩存組內部的配置為準
?

需要注意的是 enforce是用來忽略全局的配置的,無法忽略緩存組內部的配置

看以下例子

// webpack.config.jssplitChunks: {chunks: "all",minSize: 999999,minChunks: 999999,cacheGroups: {defaultVendors: false,default: false,utils: {test: /\/utils\/commonUtils.js/,},},
}// 入口
import"@utils/commonUtils"

由于外層的 minChunks minSize設置的非常大,所以打包出來的結果是不進行任何拆分?

此時,如果我們設置了enforce: true 如下

   splitChunks: {chunks: "all",minSize: 999999,minChunks: 999999999,cacheGroups: {defaultVendors: false,default: false,utils: {test: /\/utils\/commonUtils.js/,enforce: true,},},

?外層的配置將會被直接忽略,可以看到 common模塊還是被正常分離出來了。這就是enforce直接忽略了外層的配置。?

但是,如果我們對緩存組內部設置minChunks: 2 此時enforce就無法對內部的限制產生效果了。

所以,當你想忽略掉頂層配置強制拆分某個模塊的時候,可以嘗試使用enforce屬性!?

maxInitialRequests

maxInitialRequest代表最大同步并發數量,也就是限制了單個entry下加載的最大initial chunk數量

需要注意 maxInitialRequests 默認包含入口chunk,當對某個緩存組做更精細化的配置時,要減去1

在看例子之前,需要先將全局的 enforceSizeThreshold設置為0,即沒有強制尺寸分包上限,方便我們觀察
?

webpack.config.jssplitChunks: {chunks: "all",minSize: 0,minChunks: 1,maxInitialRequests: 1,enforceSizeThreshold: 0,cacheGroups: {defaultVendors: false,default: false,react: {test: /react/,minSize: 0,minChunks: 1,}}// 入口 
import react from 'react'

maxInitialRequest默認包含了入口chunk,所以在某個緩存組內分析時要先減去入口chunk?
比如對于react緩存組,其沒設置maxInitialRequests 所以繼承全局的為 1 也就是說,對于react緩存組,其最多可以分出 maxInitialRequest - 入口chunk(1) = 0 個chunk,也就是說react不能被單獨分包,哪怕滿足minSize minChunks這些, 最終分包結果如下:

可以看到,react收到maxInitialRequests的限制,被合并到了入口chunk中。

若修改react緩存組內的maxInitialRequests: 2 那么其會覆蓋全局的配置,將react單獨分包 如下:
?

如果無法滿足 maxInitialRequest的要求,那么會盡可能把大的模塊拆分出來,小的合并,看下面例子
?

// webpack.config.jssplitChunks: {chunks: "all",minSize: 0,minChunks: 1,maxInitialRequests: 2,enforceSizeThreshold: 0,
}entry: {app1: "./src/app1.js",app: "./src/app.js",main: "./src/main.js",
}// app.js
import 'lodash'// app1.js
import 'lodash'
import 'react'//main.js
import"react"

其引用關系如下圖:

可以看到,app1模塊的initialRequest為 = app1入口chunk + lodash + react = 3 不滿足 maxInitialRequest = 2


webpack會把其中更大的lodash模塊拆分出來,更小的react模塊合并到入口chunk內, 如下
可以看到,對于 app 和 main 由于只引用了一個模塊 滿足maxInitialRequest: 2
但是對于 app1 更大的lodash被拆出來共用 ,更小的react被合并進app入口了。

?

注意!在 webpack 中,runtimeChunk: true不包含在 maxInitialRequests 的限制內。?

maxAsyncRequest

maxAsyncRequest和maxInitialRequest類似,區別在于,其限制的是 對于每個 import() 動態導入 最大并發的可以下載的模塊數, 其中 import() 本身算一個并行請求

有點繞,舉個例子
我們在入口動態引入一個 testModule.js 其中同步引入add sub兩個模塊 如下

// main.js
import ('@utils/testModule')// testModule.js
import "./add";
import "./sub";// add.js
export function add(x,y){return x + y
}//sub.js
export function sub(x,y){return x - y
}

其依賴圖為

我們設置緩存組,讓各個模塊之間都相互獨立

    splitChunks: {chunks: "all",minSize: 0,minChunks: 1,enforceSizeThreshold: 0,cacheGroups: {utils: {test: /\/utils\//,minChunks: 1,minSize: 0,priority: 10,name: ()=>'UTILS'+Math.random()},},

?打包結果如下

全局設置?maxAsyncRequests: 1? 結果如下:

為什么三個模塊被打包到一起了? 因為在main中動態引入testModule 由于需要滿足maxAsyncRequest 此時 如果把add sub單獨拆分,那么asyncRequest = 動態導入testModule + add + sub? = 3 不滿足限制。

maxAsyncRequest設置為 2 可以看到打包結果為

add和sub被單獨拆分,和testModule分離,此時的asyncRequest剛好為 2
設置maxAsyncRequests = 3 可以看到三個模塊都被獨立分割了

??

我們修改 testModule 動態引入add 并且設置maxAsyncRequests為1

// testModule.js
import("./add");
import "./sub";splitChunks: {chunks: "all",minSize: 0,minChunks: 1,maxAsyncRequests: 1,enforceSizeThreshold: 0,cacheGroups: {utils: {test: /\/utils\//,minChunks: 1,minSize: 0,priority: 10,name: ()=>'UTILS'+Math.random()},},

此時可以看到,結果為

為什么add被單獨拆分了? 這是不是不滿足maxAsyncRequest: 1 的限制了? 其實不是

我們前面說了,splitChunks無法改變webpack的默認行為,由于add模塊屬于異步引入,對其拆分成一個單獨的模塊屬于webpack的默認行為,所以splitChunks只能在add被拆分的基礎上進行限制。

但是請你仔細考慮,maxAsyncRequests本身是不是就不包括異步引入的模塊呢?

對于一個import動態引入的模塊 其形式為?

import SyncModuleA. // 預解析
import SyncModuleB // 預解析
import (AsyncModuleC) // 運行時

對于同步引入的SyncModuleA & B 在整個模塊被import的時候就會同步的下載這兩個模塊,但是對于動態引入的ModuleC 只有在運行到此的時候才會真正去加載,由此可見,異步引入模塊是不包含在maxAsyncRequest中的 其本意是 在動態引入一個模塊時,同步加載進來的模塊數量,而其中的異步模塊,并不屬于 "同步加載進來的"??

我們繼續修改maxAsyncRequest = 2 你可以猜到打包結果了

?其中,add.js是webpack默認行為拆分的,不包含在maxAsyncRequests的計算中,所以maxAsyncRequests = import(TestModule) + import 'add.js' = 2 滿足約束

優化建議maxSize

maxSize表示,拆分的chunk最大值,當拆分出的chunk超過這個值的時候,webpack會嘗試將其拆分成更小的chunks

maxSize是個 "建議性質"的限制,也就是webpack如果沒有找到合適的切分點,maxSize將不起作用, 官方描述如下

maxSize的優先級 高于maxAsyncRequest / maxInitialRequest
看一個例子,

// main.js
import'react'//webpack.config.js
optimization: {runtimeChunk: true,// splitChunks: false,splitChunks: {chunks: "all",minSize: 0,minChunks: 1,maxInitialRequests: 1,maxSize: 200,enforceSizeThreshold: 0,
}}

此時,react依舊會被拆分成小塊,即便不滿足maxInitialRequests,如下:

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/80569.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/80569.shtml
英文地址,請注明出處:http://en.pswp.cn/web/80569.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用Python和FastAPI構建網站爬蟲:Oncolo醫療文章抓取實戰

使用Python和FastAPI構建網站爬蟲:Oncolo醫療文章抓取實戰 前言項目概述技術棧代碼分析1. 導入必要的庫2. 初始化FastAPI應用3. 定義請求模型4. 核心爬蟲功能4.1 URL驗證和準備4.2 設置HTTP請求4.3 發送請求和解析HTML4.4 提取文章內容4.5 保存結果和返回數據 5. AP…

YoloV8改進策略:卷積篇|風車卷積|即插即用

文章目錄 論文信息論文翻譯摘要引言相關研究紅外搜索與跟蹤檢測和分割網絡紅外搜索與跟蹤數據集的損失函數紅外搜索與跟蹤數據集方法風車形卷積(PConv)基于尺度的動態損失SIRST - UAVB數據集實驗實驗設置與其他方法的比較多模型上的消融實驗結論致謝代碼改進方法測試結果總結…

【NLP】36. 從指令微調到人類偏好:構建更有用的大語言模型

從指令微調到人類偏好:構建更有用的大語言模型 大語言模型(LLMs)已經成為現代自然語言處理系統的核心,但單純依賴傳統語言建模目標,往往難以滿足實際應用的“人類意圖”。從 Instruction Tuning(指令微調&…

基于Transformers與深度學習的微博評論情感分析及AI自動回復系統

前言 這個項目存在cookie沒有自動更新問題,后續可能會發出來解決教程,還有微博網頁版的話最多看到300條評論,而且回復別人信息的話最多回復15條就要休息5分鐘左右才能評論 1. 項目概述 本項目實現了一個微博評論自動化處理系統&#xff0c…

詳解 Zephyr RTOS:架構、功能與開發指南

目錄 Zephyr RTOS 的核心特性 1. 輕量級和可擴展性 2. 實時性能 3. 多平臺支持 4. 安全性 5. 社區和生態系統 Zephyr 的架構 1. 內核 2. 驅動模型 3. 網絡棧 4. 文件系統 開發環境和工具鏈 安裝和配置 開發流程 1. 應用程序開發 2. 調試和測試 3. 部署 實際應…

人工智能重塑醫療健康:從輔助診斷到個性化治療的全方位變革

人工智能正在以前所未有的速度改變著醫療健康領域,從影像診斷到藥物研發,從醫院管理到遠程醫療,AI 技術已滲透到醫療服務的各個環節。本文將深入探討人工智能如何賦能醫療健康產業,分析其在醫學影像、臨床決策、藥物研發、個性化醫…

Linux筆記---內核態與用戶態

用戶態(User Mode) 權限級別:較低,限制應用程序直接訪問硬件或關鍵系統資源。 適用場景:普通應用程序的運行環境。 限制:無法執行特權指令(如操作I/O端口、修改內存管理單元配置等&#xff09…

Spring 代理與 Redis 分布式鎖沖突:一次鎖釋放異常的分析與解決

Spring 代理與 Redis 分布式鎖沖突:一次鎖釋放異常的分析與解決 Spring 代理與 Redis 分布式鎖沖突:一次鎖釋放異常的分析與解決1. 問題現象與初步分析2 . 原因探究:代理機制對分布式鎖生命周期的干擾3. 問題復現偽代碼4. 解決方案&#xff1…

SQL:多列匹配(Multiple-column Matching)

目錄 基礎概念 應用場景詳解 1. 多列等值匹配 2. 多列 IN 匹配(集合匹配) 3. 多列 JOIN 匹配(復合鍵連接) 4. 多列匹配 子查詢 5. 多列匹配 EXISTS 6. 多列匹配 UNION(組合數據源) 7. 多列匹配…

基于DeepSeek的智能客服系統實踐與創新

引言:AI大模型重塑客戶服務新范式 近年來,AI大模型技術的突破性進展正在深刻改變傳統客戶服務模式。作為國內領先的AI企業,DeepSeek憑借其創新的算法架構(如MoE混合專家模型、動態學習率調度器)和極致的成本效益(僅為同類模型成本的1/20),在自然語言理解、情感分析、多…

SGLang和vllm比有什么優勢?

環境: SGLang vllm 問題描述: SGLang和vllm比有什么優勢? 解決方案: SGLang和vLLM都是在大語言模型(LLM)推理和部署領域的開源項目或框架,它們各自有不同的設計目標和優勢。下面我綜合目前…

三、Hive DDL數據庫操作

在 Apache Hive 中,數據庫 (Database),有時也被稱為模式 (Schema),是組織和管理 表及其他對象的基本命名空間單元。熟練掌握數據庫層面的數據定義語言 (DDL) 操作,是構建清晰、有序的 Hive 數據倉庫的第一步。本篇筆記將詳細梳理 …

Redis(2):Redis + Lua為什么可以實現原子性

Redis 作為一款高性能的鍵值對存儲數據庫,與 Lua 腳本相結合,為實現原子性操作提供了強大的解決方案,本文將深入探討 Redis Lua 實現原子性的相關知識 原子性概念的厘清 在探討 Redis Lua 的原子性之前,我們需要明確原子性的概念…

科普:極簡的AI亂戰江湖

本文無圖。 大模型 ?2022年2月,?文生圖應用的鼻祖Midjourney上線。 ?2022年8月,?開源版的Midjourney,也就是Stable Diffusion上線。 2022年11月30日?,OpenAI正式發布ChatGPT-3.5。 此后,不斷有【大模型】面世&…

CSS- 4.5 css + div 布局 簡易網易云音樂 官網布置實例

本系列可作為前端學習系列的筆記,代碼的運行環境是在HBuilder中,小編會將代碼復制下來,大家復制下來就可以練習了,方便大家學習。 HTML系列文章 已經收錄在前端專欄,有需要的寶寶們可以點擊前端專欄查看! 點…

【滑動窗口】LeetCode 1004題解 | 最大連續1的個數 Ⅲ

最大連續1的個數 Ⅲ 一、題目鏈接二、題目三、題目解析四、算法原理解法一:暴力枚舉 zero計數器解法二:滑動窗口 五、編寫代碼六、時空復雜度 一、題目鏈接 最大連續1的個數 Ⅲ 二、題目 三、題目解析 注意題目中說的是最多k次,在一個數組…

PyTorch音頻處理技術及應用研究:從特征提取到相似度分析

文章目錄 音頻處理技術及應用音頻處理技術音視頻摘要技術音頻識別及應用 梅爾頻率倒譜系數音頻特征爾頻率倒譜系數簡介及參數提取過程音頻處理快速傅里葉變換(FFT)能量譜處理離散余弦轉換 練習案例:音頻建模加載音頻數據源波形變換的類型繪制波形頻譜圖波形Mu-Law 編…

鴻蒙OSUniApp 實現的語音輸入與語音識別功能#三方框架 #Uniapp

UniApp 實現的語音輸入與語音識別功能 最近在開發跨平臺應用時,客戶要求添加語音輸入功能以提升用戶體驗。經過一番調研和實踐,我成功在UniApp項目中實現了語音輸入與識別功能,現將過程和方法分享出來,希望對有類似需求的開發者有…

2025年衛星遙感行業最新發展趨勢深度分析

一、國內發展趨勢:政策引領與技術突破雙輪驅動 (一)政策體系持續完善,頂層設計深化行業發展 國家級戰略與標準體系構建 中國政府將衛星遙感產業納入“十四五”規劃核心戰略,明確構建“通導遙”一體化空間基礎設施。20…

SIP協議棧--osip源碼梳理

文章目錄 osiposip主體結構體code main函數 狀態機轉化結構體code狀態轉換 sip事務結構體code osip_dialog結構體code 創建并發送200 OK響應 osip_message結構體code osip_eventcode 打印接收到的SIP消息 osip OSIP(Open Source Implementation of SIP)…