從範例看 Webpack 加載(二):code splitting harmony

先別管靜態加載了,你聽過動態加載嗎?

Tony Pai
5 min readSep 20, 2017

本篇使用官方範例 code-splitting-harmony

建議搭配 編譯後的代碼 一同觀看

如果對webpackJsonpinstalledModulesinstalledChunks__webpack_require__ 和 還沒有概念的建議先閱讀《從範例看 Webpack 加載(一):common chunk and vendor chunk》瞭解基本的 chunk 和 module 加載之後再往下看會比較容易理解。

範例說明

可分為下列兩個項目:

  • 檔案結構
  • 代碼簡述

檔案結構

由於本範例沒有定義 webpack.config.js,所以打包行為是基於 examples/build-common.js 的設定去執行。

webpack \
--display-reasons \
--display-used-exports \
--display-provided-exports \
--display-reasons \
--display-used-exports \
--display-provided-exports \
--display-chunks \
--display-max-modules 99999 \
--display-origins \
--display-entrypoints \
--output-public-path "js/" \
./example.js js/output.js

本範例用了兩種方式去 import module,第一種是 return Promise 的方式,第二種是使用 dynamic expression 定義 module 名稱然後 import(這種做法稱為 async context),兩種方式都會額外切出 chunk。

.
`-0.output.js
`-1.output.js
`-2.output.js
`-output.js

在本範例中 import 了 a、b、c/1 和 c/2 四個 Module,c/1 和 c/2 使用 async context 的方式 import,分別被放到 1.output.js 和 0.output.js。b 則是用 return Promise 的方式 import,被獨立放到 2.output.js。a 是一般的 import,所以放在 output.js。

代碼簡述

以下為 Webpack 用來實作靜態加載和動態加載的相關代碼:

ES5 Modules: CommonJS Modules
ES6 Modules: Harmony Modules

__webpack_require__.e = function requireEnsure(chunkId)

createElement 的方式將 Chunk 以 <script> 嵌入至 <head> ,若超過 12 秒未完成加載則 timeout 並 reject error。

__webpack_require__.d(exports, name, getter)

__webpack_require__.n 中作用,為 Harmony Module 定義 getter function 並讓其符合 Spec Mode 且相容 CommonJS。

__webpack_require__.n(module)

取得 default export 並回傳。

__webpack_require__.o(object, property)

__webpack_require__.d 中作用,確認 property 是否存在於 object。

map

指定為動態加載的 Modules 會將 moduleIdchunkId 紀錄在 map 變數之中。

var map = {
`./${module_name}`: [moduleId, chunkId],
`./${module_name}.js`: [moduleId, chunkId]
};

webpackAsyncContext(req)

函數會判斷 map 中是否有 req 所請求的 Module,若有則透過 __webpack_require__.e 先將 Chunk 加載完畢後再行載入 Module,反之則 reject error。

結語

這次介紹了靜態加載與動態加載的差別,下次會介紹 Plugin 是怎麼影響打包行為的。最後,無論是在文章中有看到不合理或者可以改進的地方,都可以在下方留言交流。

參考連結

--

--