上传⼩程序的代码时⾃动压缩
为了节省开发时间,我们尽量整合现有业务线⼩程序代码,减少业务改动。
⽬录结构
同时为了后期计算各业务占⽤空间情况⽅便,我们直接将各业务线⼩程序⼯程代码拷贝到各⾃业务线⽬录下,最终的⽬录结构如下:
.
├── common # 通⽤模块/公共业务
├── home  # ⾸页
├── flight # 机票
├── train  # ⽕车票
├── bus    # 汽车票
├── hotel  # 酒店
└── ticket # 门票
common 模块即⼯程的复⽤部分,具体业务代码都在各⾃⽬录下。总体架构如下:
公共组件、API
⼩程序其实并没有提供组件化开发的⽅式。只是提供了template的⽅式,所以我们只提供了为数不多的页⾯及组件,例如:城市定位、⽇历组件等。但是收益却是⾮常明显的,像这些页⾯⼤⼩都在 20KB~30KB,如果每个业务⾃⼰整⼀套可能将徒增上百 KB 代码。
公共 API 我们提供了统⼀的Watcher监控、Requester请求、Loading加载转态、Navigation导航等。这些公共逻辑的抽取,为整个项⽬整合节省了巨⼤的空间,使 size 达标看起来不那么难了。
⼯程复⽤上节省了很⼤⼀部分空间。但是空间是有限的,业务需求是⽆限的。⽽且,size 的⼤⼩会影响⽤户加载的速度,包括下载最新版本代码的速度和⼩程序初始化的速度,所以还需要进⼀步进⾏代码压缩。
打包压缩⼯具
开发者⼯具
我们知道⼩程序开发者⼯具本⾝提供了『代码压缩上传』功能。
但是个⼈觉得它是个『假的压缩选项』。因为在阅读开发者⼯具的源码逻辑之后,发现它的压缩,只是将 JavaScript ⽤进⾏混淆压缩。⽽对 WXML、WXSS 没有进⾏任何压缩处理。同时,对资源路径中的⽆⽤⽂件也没有做处理。
⼩程序的构建
在⼩程序开发者⼯具的 Sources ⾯板,查看 JavaScript 脚本,会发现:项⽬中所有的 JavaScript 都会被同步加载,不管是否被require。
每个脚本都会被套上如下代码:
define("some.js", function(require,module){
// 原本的代码
});
这种加载⽅式类似 AMD,但是跟标准的 AMD ⼜有些不同,缺少了依赖部分的声明。
⽽对于 WXSS 和 WXML ⽂件,则被开发者⼯具⾃动转换为 JavaScript 后加载,其中:
WXSS:主要处理的是 import 逻辑,然后⽣成的 CSS,通过脚本的形式插⼊页⾯使⽤。
WXML:类似于 React Naitive 的 JSX,被编译成createElement类似的形式。
⼀些技巧
在 MacOS 系统中,右键开发者⼯具『Show Contents』(显⽰包内容),就能在Resources/app.nw/下到相应的源码,完成路径如
下:/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/。
源码都是压缩过后的 JavaScript 脚本,可以使⽤进⾏格式化,以便于阅读。
// 在源码⽬录的 app ⽬录下执⾏
find . -type f -name '*.js' -exec js-beautify -r -s 2 -p -f '{}' \;
在资源⽬录下: app/dist/app.js 的第 37 ⾏window.addEventListener("resize", function() {})之前,加⼊().showDevTools();。之后每次打开开发者⼯具时,会⾃动启动针对『开发者⼯具』的开发者⼯具,并可以通过它调试的开发者⼯具。
在打印⽇志时,不要⽤console.log,请使⽤sole.log。这样,才能输出到上⾯所说的开发者⼯具的开发者⼯具的控制台⾥。(NW.js 的 Node JS Context 和 Webkit JS Context 是分开的, JavaScript 脚本运⾏在 Node 的 JS Context 中,因此,打印其实打印在 Node 的输出中,并不在  Webkit 的开发者⼯具的控制台中。tWindow获取的是 Webkit 的 JS Context ⾥的Window)
使⽤这两点技巧,读者们可以优雅地去阅读开发者⼯具的源码了。
在阅读源码,知道⼩程序的内部加载构建⽅式之后,我们可以针对性的对 JavaScript、WXML、WXSS 等代码⽂件进⾏打包压缩。
压缩 JavaScript
由于只是将js进⾏了混淆压缩,并没有打包合并成⼀个⽂件。所以我们提供了打包压缩⼯具将js⽂件合并压缩成⼀个bundle.js⽂件。合并成⼀个⽂件有以下好处:
require的长路径没了,脚本压缩效率变⾼
代码合并在⼀起,混淆性越⼤
⽂件合并,减少了 IO 次数,提升了加载效率
上⽂说了 JavaScript 都会被同步加载,所以不⽤担⼼打包成⼀个⽂件后会延长⼩程序加载时间。
那么打包压缩⼯具具体做了什么⼯作呢?
1. ⼩程序有⼀个统⼀的⼊⼝是app.js,⽽每个页⾯都有⾃⼰的⼊⼝page.js
2. 利⽤ AST,将page.js⾥页⾯注册Page(pageOpt)代码改成global.YPage(pageName, pageIndex)(pageOpt)
pageName页⾯路由
pageIndex是打包⼯具根据页⾯路由内部⾃动维护的
// global.YPage 函数
global.YPage = (pageName, index)=> {
return (pageOpt) => {
// 其他处理逻辑
global['p' + index] = ()=> {
Page(pageOpt);
}
}
}
这样page.js⾥实际是这样的代码
global['p' + index] = ()=> {
Page(pageOpt);
}
这样并不会执⾏Page(pageOpt),页⾯也没注册啊。这就是要达到的⽬的,继续往后看。
3. 将所有这些⼊⼝require到⼀个统⼀的⼊⼝⽂件中,然后⽤ webpack 打包压缩输出到bundle.js。
require('app.js')
require('page1.js')
require('page2.js')
...
4. 现在page.js⾥的代码都打包到单⼀⽂件bundle.js⾥了。将page.js内容替换成global['p' + index](),这样第三步中的Page(pageOpt)不就可以
执⾏注册页⾯了。
5. 最后⼀步,替换app.js内容为require('./bundle.js')即⼤功告成。
压缩 WXML、WXSS、JSON
WXML
/<!--((.|\n|\r)*?)-->/gm去除注释
/\"\n\s*/g去除换⾏
WXSS
直接⽤
JSON
直接JSON.stringify(JSON.parse(...))
这⾥,有些读者会可能提出两个疑问:
1. 空⽩字符、换⾏能有多少,减不了多少吧?
2. 开发者⼯具为什么不做对这些⽂件的压缩?
代码转换关于第⼀个问题,⼀个约 1000KB 的代码,空⽩字符和换⾏⼤概有 10KB。在有上限的情况之下,10 KB 也是要珍惜的。
关于第⼆个问题,个⼈认为开发者⼯具的开发者觉得没有必要去做。因为,WXML 和 WXSS 都会被转义成 JavaScript 脚本,在此过程中,不管 WXML 和 WXSS 是否被压缩,它们的转化结果是相同的。因此,压缩与否,对于最终产物是没有影响的(最终产物指在服务器⼆次打包后的结果,也是⽤户真正使⽤的)。但是,Size 是以本地打包上传的内容进⾏计算的,不进⾏此步压缩,会使服务端判定的Size 增⼤。
删除⽆⽤⽂件
⼯程庞⼤了,肯定会存在很多⽆⽤的空⽬录,空⽂件,没有被import的js、wxml、wxss⽂件。
删除这些⽆⽤⽂件不仅可以减⼩ size,还可以提升⼩程序加载时间。上⽂说了这些⽂件都会被转成 JavaScript 进⾏加载的,是会占⽤加载时间的。
删除⽆⽤ JavaScript
由于通过 webpack 打包,除了page.js、bundle .js⽂件,其他js⽂件都可以删掉。
删除⽆⽤ WXML
打包压缩⼯具在打包时,已经记录了所有页⾯的路由。遍历分析所有路由下的wxml⽂件,通过解析代码记录其他被import的wxml⽂件。最后遍历所有wxml⽂件,删除不在import列表⾥的⽆⽤wxml⽂件。
删除⽆⽤ WXSS
类似处理 WXML。遍历分析所有路由下的wxss⽂件,通过正则/@import\s*["']([^"']+)["']/g分析代码记录其他被import的wxss⽂件。最后遍历所有wxss⽂件,删除不在import列表⾥的⽆⽤wxss⽂件。
代码级优化
除了利⽤⼯具进⾏压缩,在编写代码时,也可以通过⼀些⽅法来减⼩体积,在这⾥简单列⼏点:
使⽤ ES6 时,尽量不使⽤依赖 Runtime/Polyfill 的语法,例如import和class。
图标使⽤ Iconfont。
等等…
最终效果
经过打包⼯具的极限压缩处理,还有代码设计上的可复⽤性,⽬前我们七个业务线的⼩程序整合后代码编译包⼤⼩维持在 1300KB 左右。
还剩余 730KB 的可⽤空间。
结语
希望此次在⼩程序整合上做的,⼯程化抽取公共逻辑、规范业务代码,通过⼯具进⾏针对性的代码打包压缩的实践能给⼤家带来⼀定的帮助

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。