上传小程序的代码时自动压缩

为了节省开发时间,咱们尽可能整合现有业务线小程序代码,减小业务改动。php

目录结构

同时为了后期计算各业务占用空间状况方便,咱们直接将各业务线小程序工程代码拷贝到各自业务线目录下,最终的目录结构以下:css

.
├── common # 通用模块/公共业务
├── home   # 首页 ├── flight # 机票 ├── train # 火车票 ├── bus # 汽车票 ├── hotel # 酒店 └── ticket # 门票

common 模块即工程的复用部分,具体业务代码都在各自目录下。整体架构以下:webpack

公共组件、API

微信小程序其实并无提供组件化开发的方式。只是提供了 template 的方式,因此咱们只提供了为数很少的页面及组件,例如:城市定位、日历组件等。可是收益倒是很是明显的,像这些页面大小都在 20KB~30KB,若是每一个业务本身整一套可能将徒增上百 KB 代码。web

公共 API 咱们提供了统一的 Watcher 监控、 Requester 请求、 Loading 加载转态、 Navigation 导航等。这些公共逻辑的抽取,为整个项目整合节省了巨大的空间,使 size 达标看起来不那么难了。typescript

工程复用上节省了很大一部分空间。可是空间是有限的,业务需求是无限的。并且,size 的大小会影响用户加载的速度,包括下载最新版本代码的速度和小程序初始化的速度,因此还须要进一步进行代码压缩。npm

打包压缩工具

微信开发者工具

咱们知道微信小程序开发者工具自己提供了『代码压缩上传』功能。小程序

可是我的以为它是个『假的压缩选项』。由于在阅读开发者工具的源码逻辑以后,发现它的压缩,只是将 JavaScript 用 uglify 进行混淆压缩。而对 WXML、WXSS 没有进行任何压缩处理。同时,对资源路径中的无用文件也没有作处理。微信小程序

小程序的构建

在小程序开发者工具的 Sources 面板,查看 JavaScript 脚本,会发现:项目中全部的 JavaScript 都会被 同步加载 ,不论是否被 require 。bash

每一个脚本都会被套上以下代码:服务器

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 脚本,可使用 js-beautity 进行格式化,以便于阅读。

// 在源码目录的 app 目录下执行
find . -type f -name '*.js' -exec js-beautify -r -s 2 -p -f '{}' \;
  • 在资源目录下: app/dist/app.js 的第 37 行 window.addEventListener("resize", function() {}) 以前,加入 nw.Window.get().showDevTools(); 。以后每次打开微信开发者工具时,会自动启动针对『开发者工具』的开发者工具,并能够经过它调试微信的开发者工具。

  • 在打印日志时,不要用 console.log ,请使用 global.contentWindow.console.log 。这样,才能输出到上面所说的开发者工具的开发者工具的控制台里。(NW.js 的 Node JS Context 和 Webkit JS Context 是分开的, JavaScript 脚本运行在 Node 的 JS Context 中,所以,打印其实打印在 Node 的输出中,并不在  Webkit 的开发者工具的控制台中。 global.contentWindow 获取的是 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 文件,经过 xmldom 解析代码记录其余被 import 的 wxml 文件。最后遍历全部 wxml 文件,删除不在 import 列表里的无用 wxml 文件。

删除无用 WXSS

相似处理 WXML。遍历分析全部路由下的 wxss 文件,经过正则 /@import\s*["']([^"']+)["']/g 分析代码记录其余被 import 的 wxss 文件。最后遍历全部 wxss 文件,删除不在 import 列表里的无用 wxss 文件。

代码级优化

除了利用工具进行压缩,在编写代码时,也能够经过一些方法来减少体积,在这里简单列几点:

  • 使用 ES6 时,尽可能不使用依赖 Runtime/Polyfill 的语法,例如 import 和 class 。
  • 图标使用 Iconfont。
  • 等等…

最终效果

通过打包工具的极限压缩处理,还有代码设计上的可复用性,目前咱们七个业务线的微信小程序整合后代码编译包大小维持在 1300KB 左右。

还剩余 730KB 的可用空间。

结语

但愿这次在微信小程序整合上作的,工程化抽取公共逻辑、规范业务代码,经过工具进行针对性的代码打包压缩的实践能给你们带来必定的帮助

相关文章
相关标签/搜索