乐趣区

关于javascript:京喜小程序首页瘦身实践

前言

在 web 开发场景,缩小代码体积尽管是性能优化的一个方向,还没到斤斤计较的水平。然而在小程序场景,因为代码包上传阶段限度了主包 2M 和总包 16M(近期微信官网正在内测将总包下限调整至 20M)的尺寸,超过就会面临无奈发版的危险,代码包体积的优化就变得特地重要了。
京喜小程序首页作为微信购物的大入口,承载大量流量,性能简单模块泛滥,又要与其余外围业务和公共组件共享 2M 的主包空间,因而代码包瘦身的工作在继续一直进行,否则无奈满足业务的快速增长。本文将联合以往优化策略与最近一次的瘦身实际,分享小程序代码瘦身的教训与思考。

常见的瘦身形式

京喜首页我的项目是一个优化良好的我的项目,对于常见的优化措施,曾经有过很好的实际,就让咱们咱们先回顾一下有哪些常见的优化策略吧:

  1. 代码分包:将绝对独立的页面和组件拆分到分包,能够解决主包体积受限问题;
  2. 依赖剖析:移除未援用的页面、组件和其余文件;
  3. 防止应用本地资源:除了兜底图片,其余都尽可能应用 url 的形式,因为 base64 图实质上是将信息编码成长字符串,也会占用很多空间,不倡议应用;
  4. 对所有类型的文件都进行压缩并清理正文,包含了:js、wxml、wxss、json;

此外,京喜首页团队还针对 Taro 开发场景进行了如下优化:

  1. 剖析出编译后每个文件的高频反复代码(如解决兼容性的 pollyfill 代码),拆分生成公共文件,替换原援用以实现共用。

规范和工具

在开始正式介绍瘦身实际之前,咱们先来明确一下代码包体积的衡量标准和统计形式吧。

小程序上传代码以代码包尺寸为准,所谓 2M 的限度,就是指该尺寸不能超过 2048KB。

从信息传输角度来说,Gzip 等压缩工具能够进行很多信息化编码优化,因而一些内容反复是能够容忍的,然而因为咱们的指标是为了解决小程序上传限度,就只有对代码包尺寸斤斤计较了。

在开发者工具 - 详情 - 根本信息 - 上次预览或上次上传,能够查看到最近一次的代码包体积,本文接下来所介绍的优化都是以放大这个体积为目标。

然而代码上传生成模板速度很慢,如果每次都要依据这里的数据来统计体积变动,效率太低了。

在未改变我的项目配置的状况下,咱们就能够间接以代码目录的文件体积大小作为变动参照。怎么不便的统计文件体积呢?这里我用了 tree-cli,利用它提供的参数,能够输入具备尺寸统计和排序功能的代码文件清单:

npm install -g tree-cli
// 目标目录
cd target-directory
// 输入文件为 size-analysis.md
tree -s --sort=size -o size-analysis.md 

清单内容格局如下:

.
├── [1000]  index.js
├── [500]  index.wxss
├── [500]  index.wxml
├── [500]  index.json
├── [4000]  components
│   ├── [4000]  child
│   │   ├── [1000]  index.js
│   │   ├── [1000]  index.wxml
│   │   ├── [1000]  index.wxss
└── └── └── [1000]  index.json
  
6500 bytes used in 2 directories, 8 files

瘦身实际

后面说到京喜首页优化措施都做的很好了,上面行将分享的是一些不那么常见的优化形式,优化空间有大有小,想要优化小程序代码包,倡议先尽量实现前文提到的优化计划,这样取得的收益最显著,而后再来看接下来提到的这些形式吧~

一、字体和色彩的全局共用

小程序文档内对于继承款式的阐明为:继承款式,如font,color, 会从组件外继承到组件内。

剖析我的项目现状,咱们通常会把字体定义放在公共 css 文件内,随着页面或组件引入公共 css,font 也将被反复引入,能够通过革新,把 font 的定义仅放在 app.wxss 内,勾销组件和页面的引入,能够达到缩小整体代码包体积的目标。

对于这一项首页我的项目体积缩小 1%,预估整个我的项目还有 20kb 左右的 font 定义可清理。

如果有全局的色彩定义,也能够进行相似的优化。

二、款式补全性能的应用

作为 web 开发者,对 -webkit- 这种前缀肯定不生疏,为了适配不同浏览器内核,通常咱们会在编译阶段应用 autoprefixer 进行款式的主动补全。

而小程序开发者工具也提供了款式补全的能力:详情 - 本地设置 - 能够勾选「上传代码时款式主动补全」

这个补全和咱们在编译时做的有什么不同吗?

关键在于它实现的机会:如果是本地模板上传前,那么应该和咱们编译的补全成果一样;如果是在上传模板后,兴许能够借此减掉补全内容所占的尺寸。

联合小程序代码包传递过程和款式补全机会,大略有以下 3 种状况:

阶段一补全:

阶段二:

或者是阶段三:

为了验证猜测,来做一个试验吧,比拟「我的项目编译不补全款式 + 开发者工具设置款式补全」vs「我的项目编译补全款式 + 开发者工具不设置款式补全」,模板体积统计如下:

可见前者比后者少了 58kb,这阐明,开发者工具提供的款式补全不是在阶段一做的,不然模板体积应该和咱们本人做的编译补全基本一致。

那么,就能够欢快的去掉编译补全,应用小程序开发者工具提供的能力了。

不过这样改变会呈现一个小问题,开发者工具内的款式是未经补全解决的,个别款式会有点问题,测试就发现 mask-border-source 有效,而相应真机因为已增加款式补全没有问题。为了不呈现预览误会,倡议给这种尚未反对的款式手动写上 -webkit- 前缀,保障开发和真机体现统一。

三、小心 Sass!

sass/less 等工具使得 css 的编写变得更加晦涩,函数和变量的引入也让 css 有了一点工程化的象征。然而你有没有察看过 sass 的编译实现呢?

// a.scss,作为被援用方
.banner {         // 款式定义
    color: red;
}
$COLOR = red     //  变量定义(函数定义相似)// b.scss,作为应用方
@import 'a.scss';
.banner_wrapper {
    background: white;
    color:$COLOR;
}

关注 b.sass 的编译后:

// a.scss 的援用隐没了,内容被整合到文件内

.banner {              // a.scss 内的款式定义会被拷贝进来
    color: red;
}
.banner_wrapper {
    background: white;
    color:red;           // 变量定义会被按值替换
}

这里呈现的问题是:咱们是否须要 .banner 被拷贝进来呢

为了防止多引入不须要的款式定义,有以下几个方向:

  1. 按性能拆分 a.scss 内的款式定义,按需引入。
  2. 应用 @include 语法,将 banner 的定义变成一个变量,按需引入。

而在小程序场景,wxss 语法反对 @import,实现了极弱版的模块化,使得咱们能够再加一个角度解决下面的问题:

  1. 绕过 sass 编译,应用小程序的 @import 语法,引入须要的款式定义。(对于如何绕开 sass 编译,能够思考应用正文片段,或者白名单筛选辨认)

四、多端场景的冗余代码移除

京喜首页我的项目应用 Taro 开发,须要适配 H5/ 微信小程序 /QQ 小程序等多端场景,利用 Taro 提供的环境变量能力,能够在办法外部实现多端差别解决,比方上面这段:

init(){
  if(process.env.TARO_ENV === 'weapp'{
     // 微信小程序逻辑
     this.initWeapp()}else if(process.env.TARO_ENV === 'h5'){
     // H5 页面逻辑
     this.initH5()}
}
initWeapp(){...}
initH5(){...}

小程序端打包后代码:

init(){this.initWeapp()
}
initWeapp(){...}
initH5(){...}

然而,环境变量形式没方法解决 initH5 这种办法定义,导致也被打包进来了。

因而,咱们须要更弱小的差别打包:京喜首页利用外部的 wxa-cli 工具提供的条件编译能力,通过正文段落标记,圈注出多端内容,实现了代码片段层面的差别打包,细节如下:

init(){
  if(process.env.TARO_ENV === 'weapp'{
     // 微信小程序逻辑
     this.initWeapp()}else if(process.env.TARO_ENV === 'h5'){
     // H5 页面逻辑
     this.initH5()}
}
initWeapp(){...}
/* wxa if:type=='h5' */  标记 h5 端代码开始地位
initH5(){...}
/* /wxa  */              标记正文完结地位

打包后代码:

init(){          // weapp 内
    this.initWeapp()}
initWeapp(){...}

initH5 隐没了,代码更瘦了

五、整顿 log

为了调试不便,你的我的项目内有没有打很长的 log,相似于这种:

console.log('==============xx 接口异样 ============')

通过测试,首页代码文件内有 5KB 的内容是 log 语句,能够试着优化一下:

  1. 及时移除开发调试用 log
  2. 信息类 log 约定长度更短的格局

六、良好的编码策略

有没有同样的逻辑需要,能够用更短更优雅的写法来实现呢?

对于代码剖析是个很简单的话题,临时列一个论断绝对明确的写法吧

格式化数据时数据的存取和两头变量问题

function format(list){let result = []
 list.forEach(item => {
    const {
      a,
      b,
      c: f,
      d,
      e,
    } = item

    result.push({
      a,
      b,
      f,
      d,
      e,
    })
  })

  return result

能够利用 lodash 的 pick 办法改写成:

import {pick} from 'lodash/pick'

function format(list){
 return list.map(item=>({...pick(item,'a','b','d','e'),
     f:item.c
 }))

七、款式命名编译优化

京喜首页我的项目因为 H5 端混搭老我的项目,为了防止类名抵触,采纳了形如 block-name__element--modifier 的 bem 命名规定。在开发中进一步发现,一些相似 navbar-content__item 的常见命名偶然撞车,为了防止抵触,类名就越写越长,而小程序代码包的尺寸影响也在轻轻增大。

为了解决命名抵触的问题,将类名 hash 化是个好方法,css-modules 就是个成熟的插件,能够通过配置规定,对款式名编译出「文件名 + 内容相干」的独特化 hash。

然而钻研下它的实现,会发现对代码尺寸的影响不容乐观,看一个编译后例子:

import style from './index.module.map.scss.js' //js 文件,减少一句 jsMap 的引入

<view className={style.banner}></view>  // wxml 文件,每处类名都比原类名减少了 `style.` 的援用 

.hash {xx}   // wxss 文件,类名被 hash 化,缩小的具体尺寸为: 原类名 -hash 

module.exports = {banner : hash}  // 新增了一个 map 文件,实现原名与 hash 名的映射,减少的具体尺寸为: 原类名 +hash

计算整体内容变动:

  1. js 内新增引入 map 语句:减少一句代码
  2. wxml 内:原为 n 个类名,现为 n 个「style.+ 原类名」,增量为 n 个style.
  3. map 文件 与 wxss 文件共计:map 内有 n 个原类名与 hash 映射,wxss 现为 n 个 hash,减去原来的 n 个原类名,共计增量为 2n 个 hash

可见引入 css-modules 会导致整体代码尺寸减少。

会不会感觉这个新增的 map 文件的作用特地相熟呢?

在咱们压缩 js 文件时,会有一个 sourceMap 文件,它保留了原始命名和代码地位,能够不便定位和 debug。

css-modules 实现的 map 文件,在我看来作用和 sourceMap 的命名索引差不多,对于代码逻辑来说,除了放弃原类名的援用信息,它如同也没什么用了,在尺寸敏感场景,就能够思考去掉 map 文件,还是上文的示例,如果能够实现成这样就好了:


// import style from './index.module.map.scss.js'   js 文件勾销 map 的引入

// wxml 文件
<view className="hash"></view>   // 对 style.banner 进行求值并替换  

// wxss 文件
.hash {xx}    // 这里不变

module.exports = {banner : hash}   // 删掉不要

网上遍寻没有相干的解决,只能本人造轮子开搞了。

因为以后次要目标是对小程序代码瘦身,H5 端文件解决和小程序也有一些差别,所以临时只对小程序场景造了插件,取名 weapp-css-modules,github 地址在这里:https://github.com/o2team/wea…

大略思路是:

  1. 实现小程序的 css-modules 实现
  2. 在此基础上进行 map 移除的相干简化逻辑
  3. 进一步的,思考到小程序组件内默认款式隔离的个性,对 hash 化的命名再次缩短,变成单字母编排。

如果是只开发小程序端,能够借此实现小程序款式命名相干的代码瘦身,而对于 Taro 开发的多端场景,还能够同时解决 h5 端的命名抵触问题。

还是下面的例子,上面是 weapp-css-modules 编译后成果:

// js 文件
let style = {}    // 不援用 map,退出对不标准引入 style 的兼容

// wxml 文件
<view className="a"></view>   // 对 style.banner 进行求值并替换,退出单字母编排

// wxss 文件
.a {xx}     // 因为小程序组件款式隔离,所以能够最短化类名

module.exports = {banner : hash}        // 删掉不要

京喜首页我的项目通过革新组件采纳 css-modules 写法,加上 weapp-css-modules 编译,代码绝对尺寸缩小了 10%,还是很有成果的,感兴趣的同学能够试用一下。

总结

对于代码瘦身,想提一下信息学中熵的概念:熵反映信息的无序水平,一段信息无序水平越低,它的熵值越低,可被压缩的空间越大;无序水平越高,熵值越高,可被压缩的空间越小。而数据压缩或者是代码瘦身的过程,就是通过优化信息存储形式以迫近它实在的熵值。

从这个角度来说:

  • 「字体和色彩的全局共用」和「款式补全性能的应用」是借用小程序提供的能力,信息量没变;
  • 「小心 Sass」、「多端场景的冗余代码移除」是缩小不必的信息;
  • 「整顿 log」和「款式命名编译优化」是凝练无效信息;

看起来最不好归类的是「良好的编码策略」,它是在编码阶段对信息的梳理和整合,也算凝练无效信息吧。

以上就是京喜首页我的项目这次代码瘦身的次要形式了,除此之外的删除不必文件、整合公共文件这些体力活,我就不再啰嗦了。通过以上形式,京喜首页代码在本来优化良好的根底上,实现了再次减重 30% 的指标,心愿能给小程序开发者们带来有价值的信息和思考。

参考资料

[1] CSS Modules: https://github.com/css-module…

[2] Tree-Cli: https://github.com/MrRaindrop…

[3] 小程序工程化摸索: https://mp.weixin.qq.com/s/_N…

[4] 微信小程序 限度 2M 的瘦身技巧与办法详解: https://blog.csdn.net/wlanye/…


欢送关注凹凸实验室博客:aotu.io

或者关注凹凸实验室公众号(AOTULabs),不定时推送文章。

退出移动版