本文提供了按需加載了幾種思路,並給出了相應實踐。原文地址
爲了探究按需加載的本質,選擇了對先前造的輪子 diana 進行實驗。
實驗一:全量引用
import * as _ from 'diana'
打包體積結果如下:
測試的是 diana 0.4.1
實驗二:部分引用
import { equal } from 'diana'
打包體積結果如下:
經過測試,發現兩種方式打包後的體積都爲 21 k,第二種方式仍然將整個包
引入項目中了。可是 lodash 就是這麼玩的呀,這和說好的不一樣呀,難道是忽視了什麼細節麼。
下文就來揭開面紗,並動手改造項目,最終目標是用第二種寫法實現按需加載,減小打包體積。
按需加載的方案
按需加載的效果是最終打包的代碼裏沒有未引入的模塊,從而優化項目體積。下面給出 3 種可以按需加載的方案。
給每個函數單獨發佈 npm 模塊
按需加載的方案一是將每個函數都單獨發佈一個包,可以在 npm 上查閱 lodash,這種引用方式如下:
import { isEqual } from 'lodash.isequal'
每一個函數都作爲一個單一的模塊導出
按需加載的方案二是將每一個函數都作爲一個單一的模塊導出,參照這種思路將 diana 的每個函數暴露在 lib 目錄下,部分截圖如下:
這時候再來測試下打包體積:
import equal from 'diana/lib/equal'
打包體積結果如下:
可以看到打包體積減小約爲原來的 1/7 了,但是這種方案在寫法上過於冗長,那要不借助下 babel ?
方案二 + babel
方案三是在方案二的基礎上藉助 babel 插件後,寫法可以如下:
import { equal } from 'diana'
在 .babelrc
裏進行如下配置:
// .babelrc
{
"plugins": [
["on-demand-loading", {"library": "diana"}]
]
}
此時打包體積如下:
實際上,babel 插件 的作用是將 import { equal } from 'diana'
編譯成 import equal from 'diana/lib/equal'
。
babel 插件執行機制
babel 執行三部曲如下:
- 解析
使用 babel-parse 將 JS 代碼解析成 AST 樹
- 轉換
配合 babel-traverse 進行 AST 樹的遍歷,同時使用 babel-core 對外暴露的 transform
來調用相應插件來轉化 AST 樹
babal.transform(code, {
plugins: { pluginA, pluginB }
})
- 生成
使用 babel-generator 將 AST 樹轉換回 JS 代碼
值得閱讀的文章
- babel 中文官網
- 剖析 Babel —— Babel 總覽,這篇文章講得比較透徹
- babel-handbook,babel 手冊,推薦
- Babel 插件開發一些示例,這篇文章 bug 比較多,可以作爲上面文章的補充
- AST explore,可以在這個網站上看到 JS 代碼對應的 AST