Fork me on GitHub

qap_包大小优化

Qianniu Application Platform(QAP)是阿里千牛官方推出的、功能丰富的开发者套件。底层weex,上层有SDK接口、rax库、以及rax的ui组件nuke

rax

nuke是一套基于 Weex 容器 与 rax 开源渲染引擎的面向电商中后台场景的 UI 组件生态

背景

2017年 由于整个技术方向切到qap平台,将原有的h5 web app 改造成以weex渲染。

demo

可以查看demo了解文件目录

包大小优化原因

qap平台应用简单来说是多页应用,每个页面之间都是无关联的,借助于weex的navigator进行跳转。对比web浏览器来说,就是多页面开发,每次跳转都是打开新的窗口页面。web浏览器是支持一个页面里面引入多个js的,但是weex现阶段只支持一个页面一个js)。

qap平台是将千牛应用的js打包成一个zip,通过后台服务上传,然后由千牛推送给用户,这就决定了我们必然要去优化这个zip包的大小。

正式环境的包

同时用户在首次下载新版本包的时候,包越大越容易导致丢包,用户无法更新到最新包,用户网络不能一直保持良好状态。

一个例子

意见反馈

页面比较简单,核心代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import {createElement, Component, render} from 'rax';
import {View,Text,Button,Link,Image,Modal,TextInput,TouchableHighlight} from 'nuke';
import st from './style.rxscss';
import QAP from 'QAP-SDK';
import WangWang from 'common/chatww';
import RCUserInfo from 'common/userInfo';

class Feedback extends Component {
constructor(props) {
super(props);
}
// 具体业务场景

render() {
return (
<View style={st.feedbackContentWrap}>
<View style={st.feedbackInputWrap}>
<TextInput
ref="myFb"
placeholder='吐槽、建议、改进、新功能统统写上来,我们会尽快联系您哒~'
multiline={true}
style={st.feedbackInput}
/>
</View>
<Button
style={st.singleSubmitBtn}
onPress={this.submit.bind(this)}
>
提交
</Button>
</View>
);
}
}

render(<Feedback/>);

这个页面依赖了rax, QAP-SDK, nuke, chatww, userInfo style.rxscss,但是阿里的qap平台已经帮我们内嵌了rax, QAP-SDK, nuke,我们在打包的时候就不需要打包了,剩下的依赖其实不算是很多,然而最终的打包之后的大小不理想。达到了38k。

再次分析

我们里面依赖了userInfo, 而userInfo依赖了fetch,fetch依赖了apiList

而apiList是啥?

apiList分析

对于前后分离项目,前端这边会有一个api映射表,用于数据请求。这里apiList是所有页面的api映射的集合。

1
2
3
4
5
6
7
var apiList = {
getUserInfo: {
server: 'rc',
url: 'https://mwdsp.superboss.cc/public/getUserInfo.rjson'
}
...
};

随着项目越来越复杂,apiList 越来越复杂,在实际项目里面apiList 达到了30k多。

而在实际项目里面有超过80个chunk,每个chunk都会打包apiList,有人会说用CommonsChunkPlugin抽离公共的js,但是现在weex还不支持一个页面多个js机制,所以就会出现80*30重复了很多。

拆分apiList

既然apiList冗余,那能不能在使用的时候,只要打包想要的呢?

方案1-更改请求写法

现有的方式

1
2
3
this.request({
api: 'XXX'
})

这种方式在原有的h5里面是可以的,全局共享apiList。

可以改成

1
2
3
import {XXX} from 'api'

XXX();

这样就能够按需加载api了,但是要大改整个请求,而且在每个页面都得更改,成本太大了。新的项目可以这样子,但是对于现有的项目改动成本大。

方案2-提前处理api

既然apiList很大,那就不用了,直接在使用的时候,把映射关系写到参数里面。

这个会带来很多问题,一个api在多个页面被使用了,一旦改动就要涉及到多个页面改动,给项目维护带来很大困难。

方案3-提前预处理api

改进方案2,还是按照之前的写法,在打包的过程中,提前把映射关系注入参数。

利用babel-plugin


1
2
3
4
5
request({
api: 'A0'
}, (result)=> {
console.log(result);
})

转成

1
2
3
4
5
6
7
8
9
request({
api: 'A0',
apio: {
server: 'rc',
url: 'https://mwdsp.superboss.cc/api/a0'
}
}, result => {
console.log(result);
});

就可以不需要引入apiList了。

查看具体详情

这样就能够抛弃apiList了,最终通过这种方式优化了25%的体积。

进一步思考

如果有80个页面,每个页面用了userInfo,按照上面的思路,是不是最终会有80个userInfo?

其实不然,每个页面会有很多组件,如果有些组件里面是单独请求userInfo,也会做一次转化。最终是>=80个。

那能不能进一步减少呢?

那就是要抽离重复代码,将userInfo封装成一个公共函数调用,最终webpack计算页面组件依赖关系的时候,只会计算出依赖userInfo这个公共函数,这样就能做到80次转化userInfo。

那能不能进一步减少呢?

这里就设计到qap平台的一些特性了,这个后面会在qap统一入口里描述,不是任何场景都适合。

问题

apiList 是动态对象,业务层存在动态调用。

在通过babel-plugin处理request的时候,是得知道真正调用的api的名字的。动态传参是无法转换的。

这里就需要手动改成静态调用。

总结

包的大小对于web应用,以及native应用一直都是难题;在业务复杂情况下,怎么做好包大小控制都是难题。

此次主要是对apiList进行优化,效果比较显著,在实际项目里包的大小降低了25%。

再次思考?

能不能计算出每个页面里面具体使用了哪些api,然后替换掉apiList,每个页面的apiList都是精简过后的,这样就不用转化了。
这个在统一入口实战里面有涉及到。

qap实践系列

  1. qap-包大小优化
  2. qap-统一入口
  3. qap-图表
  4. qap-跨页面需求
  5. qap-动态代码

本文地址 http://xiaoqiang730730.github.io/2018/03/10/qap-包大小优化/

觉得有点意思,打个赏鼓励博主继续写哈!がんばって
前端-小强 WeChat Pay

微信打赏

前端-小强 Alipay

支付宝打赏