總之最近有需求所以用上了 webpack 的 code splitting,就在用爽爽以為世界為我所有的時候,碰到神秘的現象。
環境
為了稍微釐清一下關係,以下的主角分別稱為 A & B。
A - 嵌入式的工具,設計為可以嵌入各種網站使用(使用 webpack code splitting) B - 新的 project(使用 webpack),有嵌入 A 做進階使用
這天 B 需要嘗試加入 code splitting,目前只需要分成兩個 chunk,一個 chunk 代表一個 route。
簡單的 code splitting 示意寫法如下:
import dyna from '_util/createDynamicComponent';
const Main = dyna((resolve) => {
require.ensure([], require => {
resolve(require('_components/Main').default);
});
});
照常理來說,webpack 會確保 require.ensure
的 callback 裡面需要執行的東西在讀進來之後才執行;然而,此處的 require('_components/Main')
在實際執行的時候,卻時不時是空的 {}
。
設身處地的想想,這個 bug 有多難 deeeeeeeeeeeeeeee
webpack magic
在經過多方交叉測試確認不是我程式碼這邊的問題之後,所有的矛頭指向了 webpack。但 webpack 的能力太強、文件寫得不夠詳盡,對我來說 code splitting 這件事就是一個 magic,也因此還真的不知道該怎麼 de webpack 的 bug。
於是我在 google 上搜尋各種可能的 keyword
webpack chunk load failed webpack chunk doesn’t load
然後實際上很莫名的會一直搜到它的文件,以及各種 tutorial 或 opinion 文章,頓時真是覺得這個生態系是不是有什麼問題…
直到我從上面的環境中 identify 了關鍵的可能原因,重新用了這個 keyword
webpack multiple instance
搜尋結果其實看起來還是一樣沒有一矢中的的感覺,不過答案其實默默地藏在第三個結果裡。
Ref: https://github.com/webpack/docs/wiki/configuration#outputjsonpfunction
output.jsonpFunction
The JSONP function used by webpack for asnyc loading of chunks. A shorter function may reduce the filesize a bit. Use different identifier, when having multiple webpack instances on a single page.
output.jsonpFunction
有稍微 trace 一下的話,可以知道 webpack 想要載入 chunk 的時候會需要使用這個一個名為 webpackJsonp
的 global function (在 window
底下),而這個設定 output.jsonpFunction
就是用來設定這個 function name 的。
在同一個網頁上面有多個 webpack instance 的時候 (ex: A 和 B 都是 webpack,而且都有做 code split),這個 jsonpFunction
的名字相同會讓兩者其中一方的 chunk loading 陷入錯亂(似乎是編號-based,而編號會混在一起)。
所以最後只需要把 A 的 output.jsonpFunction
改成比較 unique 的就解決了。
TL;DR
條件
- 同一個頁面會用到兩個以上的 webpack instance
(一般來說就是兩個從 webpack 面來看沒有相關的 bundle) - 有需要做 chunk 載入
需要
- 透過
output.jsonpFunction
確保兩個 instance 的 jsonp function name 不同
/* file: webpack.config.js */
var config = {
...
output: {
...
jsonpFunction: 'somethingPrettyUniqueJsonp' // so important
}
};
後記
是說 multiple webpack instance 需要改 jsonp function name 這種事情這麼重要,也太難找!!!!!!