解決taro小程式中引入axios包過大的問題
解決taro小程式中引入axios包過大的問題
背景
我們在使用taro 和 @freud/http
(公司內部專案,基於axios做的二次開發) 的時候,發現構建產物中多了很多沒有用的包,導致產物變大了150kb左右。
經過一番搜尋,發現是因為taro小程式不能解析package.json中的browser module等欄位,而@frued/http 因為要同時支援web和小程式環境,而axios中就有browser屬性:
json
"browser": {
"./lib/adapters/http.js": "./lib/adapters/xhr.js"
},
所以在taro中引入axios的時候,會將 lib/adapters/http.js
也打包進來,http.js中會有很多依賴包如zlib等等,就會導致上述包過大的問題。
解決思路
首先我們可以定位到axios原始碼相關的位置:
js
if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/http');
}
正常情況下,在web環境中,./lib/adapters/http.js
會被 ./lib/adapters/xhr.js
替換
所以以上程式碼在打包之後就會變成。
js
if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
} else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/xhr');
}
我們在知道了正常情況下,構建產物應該長什麼樣子之後,再來看我們目前的構建產物。
因為@frued/http 是基於rollup做的構建,所以產物如下圖:
index.js中保留對axios的引用 var axios = require('axios')
,而axios的對應lib/default.js
中,依然在引用 adapter/http
圖一
圖二
至此,我們大致有了解決問題的2個方向: 1. 構建工具的調整優化 2. 修改原始碼,避免多餘引用
�具體方案
因此對應的解決方案有:
1. 將axios上傳到私有庫中,刪除掉對http.js的相關引用
2. 利用npm包的patch機制,在@freud/http
中對axios原始碼進行修改,刪除掉對http.js的相關引用
3. 將@freud/http
拆分成2個npm包,分別對應web環境,小程式環境
4. 改用webpack 對@freud/http
進行打包
5. 引入rollup外掛
1-3 很簡單,不用細講。先講一講第四點,為什麼使用webpack就可以解決這個問題。
rollup中為了更好地做tree shaking,因此只保留著對依賴的引用,而不是直接將依賴的程式碼打包到index.js中(見圖一)。所以@freud/http
引入axios時,axios的程式碼依然保留著對http.js的引用,只有到實際web專案執行時,browser欄位生效,則http.js被xhr.js替換。
但是webpack構建時,會自動解析模組內容,將所有模組打包後的內容和id以key value的形式存在於構建產物的一個數組中,此時http.js就會被xhr.js替換。
故由於對依賴包的處理方式不同,webpack構建即可解決此問題。
第五點,尚在研究中,有基於rollup做二次封裝的構建工具bili 解決了這個問題。
結尾
因為 @freud/http
為monorepo專案,統一使用rollup構建。若所有包都改用webpack構建,則成本太大。基於此,我選擇了在subpage中新增webpack做二次構建的方式,即在rollup將@freud專案中的子包構建完之後,再執行@freud/http
中的webpack構建命令,將rollup的構建產物lib/index.js 用webpack再構建一次。這樣能夠避免在子專案中再寫一遍babel配置,做到所有子包的基礎構建配置相同。