解决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配置,做到所有子包的基础构建配置相同。