關於 vite 與 webpack 的檔案分割

之前一直很好奇 nuxt 是怎麼做到分割檔案的,但一直沒有時間來好好研究。上網搜尋一下之後,得知原來就跟寫 vue-router 想要 lazy load 的時候一樣,只要不用 import xxx from 'xxx' 匯入,而是改用 import('xxx') 的方式匯入,就會被自動分割,達成在需要的時候才 import 的目的,也就是 component 的 lazy loading。

例如當我們在 vue3 裡要宣告一個 component 的時候可以用:const xxx = defineAsyncComponent(() => import('xxx'))

以下的描述是單純以 vite or webpack 來打包程式碼的情況,而非 nuxt。

因此這個 import() 就是關鍵之處。平常較為人知的 import 是只能在一個檔案的最上頭,並且是以 import xxx from 'xxx' 這樣的形式使用。不過以這種方式 import 的話,全部的 code 將都會被打包在一起,output 到你設定的路徑。

import() 與檔案開頭使用的 import 是不同東西,不要混淆了。他是以 function 的形式來使用。且會回傳一個 Promise,當我們 const test = await import('xxx') 後,test 被賦予的是一個 Module 物件,其中會有 default 或是我們 export 的其他內容。

當我們的程式碼以 import() 來載入一個 module 時,就會使 webpack or vite 依照 import('xxx') 的檔案路徑來分割檔案,並改寫檔名(例如 Comp1-sdfkjsdpg.js),與原本 import('Comp1.js') 中的檔名(例如 import('Comp1-sdfkjsdpg.js'))。

我們也可以透過一樣的 code 來比較 vite and webpack 所分割出來的檔案。結果 vite 產生的檔案大小小很多,因為 vite 預設不會管 ESM 相容性的問題,而 webpack 則會加入許多 module 相容性的 code 在其中。

另外,我們知道由 import 載入的內容一旦被修改,別處也有 import 相同內容的地方也會拿到被修改後的資料。這個部分 import() 也是相同的。

此外我還做了一個無聊的測試,就是當網頁上有兩個 script 標籤中都 import 相同檔案時,是否結果也是一樣呢?答案是一樣!當其中一個 script 標籤中 import 的內容修改過後,另一個 script 標籤內 import 的內容也會是被修改過的(因為他們就是同一個內容)。