微信小程序借助微信庞大的用户流量优势,吸引了众多第三方开发者。几乎每个公司都想通过小程序吸引新的用户群体。于是,他们把小程序整合到小程序中。但问题就是空间不够,当时微信小程序占用空间为(现已升级到2M),各业务线的小程序都不小,公交票APP更是比这个还要大,如何整合压缩才能满足大小要求,成为了最大的挑战。
经过深思熟虑,我们计划从两个方面进行整合和压缩,一是通过工程化的方式实现代码复用——抽取通用的业务逻辑、通用的组件;二是利用工具对定制化的代码进行打包和压缩。
1.工程规范制定
为了节省开发时间,我们尽量整合现有业务线的小程序代码,减少业务改动。
1.1 目录结构
同时为了方便后期计算各个业务占用的空间,我们直接把各个业务线小程序的工程代码复制到各个业务线的目录中,最终的目录结构如下:
1
2
3
4
5
6
7
8
.
├── common
├── home
├── flight
├── train
├── bus
├── hotel
└── ticket
模块是项目中可复用的部分,具体业务代码都在各自的目录中。整体架构如下:
1.2 公共组件和API
微信小程序其实并没有提供组件化的开发方式,我们只是提供了一些页面和组件,比如城市位置,日历组件等等,但是这样做的好处也是非常明显的,比如这些页面的大小在20KB到30KB之间,如果每个业务都自己做一套页面的话,可能会增加几百KB的代码。
公共API我们提供统一的监听、请求、加载转场、导航等,这些公共逻辑的提取,为整个项目的集成节省了大量的空间,使得满足大小要求的难度降低。
项目复用节省了很大一部分空间,但空间是有限的,业务需求是无限的,而且大小会影响用户的加载速度,包括下载最新版本代码的速度、小程序初始化的速度,所以需要进一步进行代码压缩。
2 打包压缩工具 2.1 微信开发者工具
我们知道,微信小程序开发者工具本身提供了“代码压缩上传”功能。
但我个人认为它是一个“假压缩选项”,看了开发者工具的源码逻辑后发现,它的压缩只是对用户进行了混淆,并没有对 WXML 和 WXSS 进行任何压缩,同时,也没有对资源进行任何压缩,路径中无用的文件不做任何处理。
2.1.1 小程序建设
在小程序开发者工具的面板中,查看脚本会发现项目中的所有脚本无论是否加载都会被同步加载。
每个脚本都将用以下代码包装:
1
2
3
define("some.js", function(require, module){
// 原本的代码
});
这种加载方式和AMD类似,但是和标准AMD稍有不同,缺少依赖部分的声明。
对于 WXSS 和 WXML 文件,它们会被开发者工具自动转换为后加载,其中:
WXSS:主要进行逻辑处理然后生成CSS,以脚本的形式插入到页面中。
WXML:与JSX类似,编译成类似的形式。
2.1.2 一些提示
在系统中右键点击开发者工具“Show”(显示包内容),可以在/app.nw/下找到对应的源代码,填入的路径如下://.app///app.nw/。
源代码都是压缩脚本,可以使用js-格式化,方便阅读。
1
2
// 在源码目录的 app 目录下执行
find . -type f -name '*.js' -exec js-beautify -r -s 2 -p -f '{}' \;
利用这两个技巧,读者可以优雅地阅读微信开发者工具的源代码。
在阅读了源码,知道了小程序内部的加载和构造方法之后,我们可以对WXML,WXSS等代码文件进行打包压缩。
2.2 压缩
由于微信只对 js 文件进行了混淆压缩,并没有打包成一个文件,所以我们提供了打包压缩工具,将 js 文件合并压缩成一个 .js 文件。合并成一个文件有以下好处:
就像上面说的,它们都会同步加载,所以不用担心打包成一个文件会延长小程序的加载时间。
那么打包压缩工具到底起什么作用呢?

小程序有统一的入口点app.js,各个页面有自己的入口点page.js
使用 AST,将 page.js 中的页面注册 Page() 代码更改为 .(, )()
页面路由
由打包工具根据页面路由自动维护
1
2
3
4
5
6
7
8
9
// global.YPage 函数
global.YPage = (pageName, index) => {
return (pageOpt) => {
// 其他处理逻辑
global['p' + index] = () => {
Page(pageOpt);
}
}
}
所以page.js中的实际代码如下
1
2
3
global['p' + index] = () => {
Page(pageOpt);
}
这不会执行 Page(),并且页面不会注册。这正是我们想要实现的,所以请继续阅读。
把这些入口点全部放到一个统一的入口文件中,然后使用压缩并输出为.js。
1
2
3
4
require('app.js')
require('page1.js')
require('page2.js')
...
现在page.js中的所有代码都打包成一个.js文件了,将page.js的内容替换成['p' + ](),这样第3步中的Page()就可以执行注册页面了。
最后一步是用('./.js')替换app.js的内容就完成了。
2.3 压缩 WXML、WXSS、.3.1 .3.2 .3.3 JSON
说到这里,有的读者可能会提出两个疑问:
空格和换行符可以有多少个?不能减少太多,对吧?
为什么开发工具不压缩这些文件?
关于第一个问题,一段代码,包括空格和换行,大概10KB,如果有上限的话,10KB还是要珍惜的。
关于第二个问题,我个人认为微信开发者工具的开发者认为没有必要这么做。因为 WXML 和 WXSS 都会被转义成脚本,在这个过程中,无论 WXML 和 WXSS 是否经过压缩,它们的转换结果都是一致的,所以压缩与否对最终的成品没有影响(最终成品是指在服务端经过二次打包之后的结果,也是用户实际使用到的)。但是大小是根据本地打包上传的内容来计算的,如果不进行这个压缩,微信服务端判定的 Size 会变大。
2.4 删除无用文件
项目庞大,肯定会有大量的无用的空目录,空文件,以及没有使用的js,wxml,wxss文件。
删除这些无用的文件,不仅可以减小体积,还可以提高小程序的加载时间,上面提到了这些文件在加载时会被转换,占用加载时间。
2.4.1 删除无用
由于打包的原因,除了page.js和.js文件外,其他js文件都可以删除。
2.4.2 删除无用的WXML
压缩工具在打包的时候已经记录了所有页面的路由,会遍历分析所有路由下的wxml文件,并通过解析代码的方式记录下其他wxml文件,最后遍历所有的wxml文件,删除不在列表中的无用wxml文件。
2.4.3 删除无用的WXSS
和处理WXML类似,遍历分析所有路由下的所有wxss文件,使用正则表达式/@\s*["']([^"']+)["']/g来分析代码,记录下其他wxss文件。最后遍历所有wxss文件,删除不在列表中的无用wxss文件。
2.5 代码级优化
除了使用工具进行压缩之外,在编写代码时也有一些方法可以减少体积。这里简单说几点:
3 最终效果
经过打包工具的极限压缩处理以及代码设计的可复用性,目前我们整合七条业务线的小程序后编译后的代码包大小维持在 左右。
仍有剩余空间。
4。结论
希望在小程序集成中对公共逻辑进行工程化提取、业务代码标准化、通过工具进行有针对性的代码封装压缩的实践能给大家带来一些帮助。