如果把工程中各個模組的依賴關係當作一棵樹,那麼入口(entry)就是這棵依賴樹的根
這些存在依賴關係的模組會在打包時被封裝為一個chunk。那chunk是什麼呢?
chunk字面的意思是程式碼區塊,在Webpack中可以理解成被抽象和包裝過後的一些模組。它就像一個裝著許多檔案的檔案袋,裡面的檔案就是各個模組,Webpack在外面加了一層包裹,從而形成了chunk:
根據具體配置不同,一個工程打包時可能會產生一個或多個chunk。
工程中可以定義多個入口,每個入口都會產生一個結果資源
例如我們工程中有兩個入口src/index.js
和src/lib.js
,在一般情況下會打包生成dist/index.js
和dist/lib.js
。
在一些特殊情況下,一個入口也可能產生多個chunk並最終產生多個bundle
參數:Entry
module.exports = { entry:'./src/index.js', //表示入口文件,即從index.js進入我們的專案};
①Entry 類型
類型 | 範例 | 意義 |
---|---|---|
string | './app/entry' | 入口模組的檔案路徑,可以是相對路徑 |
array | ['./app/entry1', './app/entry2'] | 入口模組的檔案路徑,可以是相對路徑 |
object | { a: './app/entry-a', b: ['./ app/entry-b1', './app/entry-b2']} | 配置多個入口,每個入口產生一個Chunk |
如果是array 類型,則搭配output.library 配置項使用時,只有數組裡的最後一個入口檔案的模組會被匯出
②Chunk 名稱
Webpack 會為每個產生的Chunk 取一個名稱,Chunk 的名稱和Entry 的設定有關:
③Entry 配置動態
假如項目裡有多個頁面需要為每個頁面的入口配置一個Entry ,但這些頁面的數量可能會不斷增長,則這時Entry 的配置會受到到其他因素的影響導致不能寫成靜態的值。其解決方法是把Entry 設定成一個函數去動態傳回上面所說的配置,程式碼如下:
// 同步函數entry: () => { return { a:'./pages/a', b:'./pages/b', } }; // 非同步函數entry: () => { return new Promise((resolve)=>{ resolve({ a:'./pages/a', b:'./pages/b', }); }); };
參數:context
Webpack 在尋找相對路徑的檔案時會以context 為根目錄,context 預設為執行啟動Webpack 時所在的目前工作目錄。 如果想要改變context 的預設配置,則可以在設定檔裡這樣設定它:
module.exports = { context: path.resolve(__dirname, 'app') }
注意, context 必須是一個絕對路徑的字串。 除此之外,還可以透過在啟動Webpack 時帶上參數webpack --context 來設定context
用法: entry:string|Array<string>
1.簡寫語法
webpack.config.js
//由於是單個,所以可以簡單寫成: module.exports = { entry: './main.js' };
上面的入口配置寫法其實是下面的簡寫
module.exports = { entry: { main: './main.js' } };
2、陣列語法
module.exports = { entry: { main:['./main.js','./main2.js'] } };
傳入一個陣列的作用是將多個資源預先合併,在打包時Webpack會將陣列中的最後一個元素作為實際的入口路徑
在使用字串或陣列定義單入口時,並沒有辦法更改chunk name ,只能為預設的“main”。
用法: entry: {[entryChunkName: string]: string|Array}
物件語法
module.exports = { entry: { app: './src/app.js', vendors: './src/vendors.js' } };
這會比較繁瑣。然而這是應用程式中定義入口的最可擴展的方式。
“可擴充的webpack 配置” :可重複使用並且可以與其他配置組合使用。這是一種流行的技術,用於將關注點從環境(environment)、建置目標(build target)、運行時(runtime)中分離。然後使用專門的工具(如webpack-merge)將它們合併。
1.單頁應用程式
無論是框架、函式庫,或是各頁的模組,都由app.js
單一的入口進行引用。這樣做的好處是只會產生一個JS文件,依賴關係清晰。
module.exports = { entry: './src/app.js' };
這種做法也有弊端,即所有模組都打包到一起,當應用的規模上升到一定程度之後會導致產生的資源體積過大,降低用戶的頁面渲染速度
在Webpack默認配置中,當一個bundle大於250kB時(壓縮前)會認為這個bundle已經過大了,在打包時會發生警告,如圖:
2.分離第三方函式庫(vendor)
為解決上方的問題,可以提取第三方函式庫(vender)
vendor的意思是“供應商”,在Webpack中vendor一般指的是工程所使用的函式庫、框架等第三方模組集中打包而產生的bundle
module.exports = { entry: { app: './src/app.js', vendors: ['react','react-dom','react-router'], } };
基於但也應用的例子,我們添加了一個新的chunk name為vendor
的入口,並通過數組的形式把工程所依賴的第三方模組放了進去
我們並沒有為vendor設置入口路徑,Webpack要如何打包呢?
這時我們可以使用CommonsChunkPlugin (在Webpack 4之後CommonsChunkPlugin已被廢棄,可以採用optimization.splitChunks)將app與vendor這兩個chunk中的公共模組提取出來
通過這樣的配置,app.js產生的bundle將只包含業務模組,其依賴的第三方模組將會被抽取出來產生一個新的bundle,這也就達到了我們提取vendor的目標
由於vendor僅包含第三方模組,這部分不會經常變動。因此可以有效地利用客戶端緩存,在用戶後續請求頁面時會加快整體的渲染速度。
CommonsChunkPlugin主要是用來提取第三方函式庫和公共模組,避免首屏載入的bundle檔案或按需載入的bundle檔案體積過大,從而導致載入時間過長。
3.多頁應用程式
對於多頁應用程式的場景,為了盡可能減少資源的體積,我們希望每個頁面都只載入各自必要的邏輯,而不是將所有頁面打包到同一個bundle中。因此每個頁面都需要有一個獨立的bundle ,這種情況我們使用多入口來實現。請看下面的範例:
module.exports = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js', pageThree: './src/pageThree/index.js' } };
上面的配置告訴webpack 需要3 個獨立分離的依賴圖,此時入口與頁面是一一對應的,這樣每個HTML只要引入各自的JS就可以載入其所需的模組