共计 1915 个字符,预计需要花费 5 分钟才能阅读完成。
背景
咱们在应用 taro 和 @freud/http
(公司外部我的项目,基于 axios 做的二次开发)的时候,发现构建产物中多了很多没有用的包,导致产物变大了 150kb 左右。
通过一番搜寻,发现是因为 taro 小程序不能解析 package.json 中的 browser module 等字段,而 @frued/http 因为要同时反对 web 和小程序环境,而 axios 中就有 browser 属性:
"browser": {"./lib/adapters/http.js": "./lib/adapters/xhr.js"},
所以在 taro 中引入 axios 的时候,会将 lib/adapters/http.js
也打包进来,http.js 中会有很多依赖包如 zlib 等等,就会导致上述包过大的问题。
解决思路
首先咱们能够定位到 axios 源码相干的地位:
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
替换
所以以上代码在打包之后就会变成。
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 个方向:
- 构建工具的调整优化
- 批改源码,防止多余援用
具体计划
因而对应的解决方案有:
- 将 axios 上传到公有库中,删除掉对 http.js 的相干援用
- 利用 npm 包的 patch 机制,在
@freud/http
中对 axios 源码进行批改,删除掉对 http.js 的相干援用 - 将
@freud/http
拆分成 2 个 npm 包,别离对应 web 环境,小程序环境 - 改用 webpack 对
@freud/http
进行打包 - 引入 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 配置,做到所有子包的根底构建配置雷同。