给小程序再减重 30% 的秘密​(京喜小程序首页瘦身实践)

前言—

在 web 开发场景,减少代码体积虽然是性能优化的一个方向,还没到锱铢必较的程度。但是在小程序场景,由于代码包上传阶段限制了主包 2M 和总包 16M(近期微信官方正在内测将总包上限调整至 20M )的尺寸,超过就会面临无法发版的风险,代码包体积的优化就变得特别重要了。京喜小程序首页作为微信购物的大入口,承载大量流量,功能复杂模块众多,又要与其他核心业务和公共组件共享 2M 的主包空间,因此代码包瘦身的工作在持续不断进行,否则无法满足业务的快速增长。本文将结合以往优化策略与最近一次的瘦身实践,分享小程序代码瘦身的经验与思考。

常见的瘦身方式—

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

  1. 代码分包:将相对独立的页面和组件拆分到分包,可以解决主包体积受限问题;

  2. 依赖分析:移除未引用的页面、组件和其他文件;

  3. 避免使用本地资源:除了兜底图片,其他都尽可能使用 url 的方式,由于 base64 图本质上是将信息编码成长字符串,也会占用很多空间,不建议使用;

  4. 对所有类型的文件都进行压缩并清理注释,包括了:js、wxml、wxss、json;

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

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

标准和工具—

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

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

从信息传输角度来说,Gzip 等压缩工具可以进行很多信息化编码优化,因此一些内容重复是可以容忍的,但是由于我们的目标是为了解决小程序上传限制,就只有对代码包尺寸锱铢必较了。

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

查看代码包尺寸

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

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

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.json6500 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,} = itemresult.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化,减少的具体尺寸为:原类名-hashmodule.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/weapp-css-modules

大概思路是:

  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-modules/css-modules

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

[3] 小程序工程化探索: https://mp.weixin.qq.com/s/_NSJTQ-4-8gTnwTVK-tn0A

[4] 微信小程序 限制 2M 的瘦身技巧与方法详解: https://blog.csdn.net/wlanye/article/details/73457700

精选前端好文,伴你不断成长

我是若川欢迎关注!可点击

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/276342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

本周ASP.NET英文技术文章推荐[10/21 – 10/27]

这一篇是《本周ASP.NET英文技术文章推荐》系列的第一篇&#xff0c;在这个系列中&#xff0c;我将介绍5-10篇比较有价值的、本周发布的、与ASP.NET相关的英文技术文章&#xff0c;帮助各位朋友从良莠不齐的大量文章中挑出一些我认为非常有价值阅读的&#xff0c;在进行一段简要…

3 年前端面经和他在创业公司的成长历程

在掘金上当了几年的伸手党&#xff0c;最近也准备输出一些自己的东西。关于我首先介绍一下我自己&#xff0c;17 年毕业于一所 211 学校&#xff0c;但是由于大学四年驰骋在召唤师峡谷&#xff0c;毕业时也没有找到一份大厂的工作&#xff0c;随便找了一家创业公司签了三方就去…

Spring.NET学习笔记9——打造简易的依赖注入框架(练习篇) Level 100

我们在第三篇中学习里一个简易的IoC框架。今天我们接着上次的程序&#xff0c;实现带参数构造函数对象的实例和属性的注入 。  我们知道可以通过反射获取类的构造函数及参数(GetConstructors方法)&#xff1b;可以获取属性和属性的类型(GetProperties方法)。通过Activator的C…

android 单元测试

首先AndroidManifest.xml View Code <?xml version"1.0" encoding"utf-8"?> <manifest xmlns:android"http://schemas.android.com/apk/res/android"package"com.travelsky.test" android:versionCode"1"androi…

申万一级行业日指数_基金收评 | 指数震荡走弱,军工股成两市主线!后期行情如何?...

收评君复盘日记(2020年9月21日)三大指数集体收跌&#xff0c;北向资金全天大幅净流出近65亿元&#xff0c;军工板块表现强势。盘面回顾9月21日&#xff0c;两市全天高开低走&#xff0c;早盘指数弱势震荡&#xff0c;三大指数盘中一度翻红&#xff0c;但随后震荡走弱&#xff0…

若川的2016年度总结,毕业工作

可以点击上方的标签若川的故事、年度总结&#xff0c;查看往期文章有读者反馈说看我年度总结系列比我源码系列更有启发。所以打算把2016-2018的年度总结发布到公众号声明原创&#xff0c;希望对大家有所启发。&#xff08;虽然我的每一年都过得非常普通...&#xff09;以下是正…

jQuery之Ajax

转载链接&#xff1a;http://cargoj.iteye.com/blog/1008047 1 . jQuery帮助之Ajax请求&#xff08;一&#xff09;jQuery.ajax(options) 2 . jQuery帮助之Ajax请求&#xff08;二&#xff09;jQuery.get(url,[data],[callback] 3 . jQuery帮助之Ajax请求&#xff08;三&am…

面试官问:能否模拟实现JS的new操作符(高频考点)

可以点击上方的话题JS基础系列&#xff0c;查看往期文章这篇文章写于2018年11月05日&#xff0c;new模拟实现&#xff0c;Object.create是面试高频考点&#xff0c;之前发布在掘金有近2万人阅读&#xff0c;现在发布到公众号声明原创。1. 前言这是面试官问系列的第一篇&#xf…

跟我一起学WCF(2)——利用.NET Remoting技术开发分布式应用

一、引言 上一篇博文分享了消息队列&#xff08;MSMQ&#xff09;技术来实现分布式应用&#xff0c;在这篇博文继续分享下.NET平台下另一种分布式技术——.NET Remoting。 二、.NET Remoting 介绍 2.1 .NET Remoting简介 .NET REmoting与MSMQ不同&#xff0c;它不支持离线可得&…

二叉树的建立与遍历_51、二叉树遍历-重建二叉树JZ4

题目描述输入某二叉树的前序遍历和中序遍历的结果&#xff0c;请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建二叉树并返回。思路回顾三种经典的遍历&…

推荐关注这7个高质量的前端公众号

拓宽眼界&#xff0c;增加深度&#xff0c;在阅读的世界里&#xff0c;我们往往能找到不一样的态度&#xff0c;提升朋友圈质量&#xff0c;从关注这几个公众号开始。轻扫一下二维码就行了&#xff0c;你可以试试&#xff0c;肯定会有意外收获。大迁世界 简介&#xff1a;前端小…

Windows Live Writer 在win2003 的安装方法

下载Windows Live Writer整体安装包&#xff0c;最好是离线安装包 2.在xp系统上安装 3.查找C:\Program Files\Common Files\Windows Live\.cache目录 .cache目录是隐藏的&#xff0c;目录下面就是各个安装文件的msi安装包 4.拷贝相应的msi文件&#xff0c;到Windows 2003安装就…

decode 大于比较 小于_6 燃气输配系统6.3 压力不大于1.6Mpa的室外燃气管道城镇燃气设计规范 GB500282006(2020修订版)...

6.3 压力不大于1.6Mpa的室外燃气管道6.3.1中压和低压燃气管道宜采用聚乙烯管、机械接口球墨铸铁管、钢管或钢骨架聚乙烯塑料复合管&#xff0c;并应符合下列要求&#xff1a; 1 聚乙烯燃气管应符合现行的国家标准《燃气用埋地聚乙烯管材》GB15558.1 和《燃气用埋地聚乙烯管件…

若川的2017年度总结,一如既往

可以点击上方的标签若川的故事、年度总结&#xff0c;查看往期文章有读者反馈说看我年度总结系列比我源码系列更有启发。所以打算把2016-2018的年度总结发布到公众号声明原创&#xff0c;希望对大家有所启发。&#xff08;虽然我的每一年都过得非常普通...&#xff09;若川的20…

沟通:用故事产生共鸣

《沟通:用故事产生共鸣》(全彩) 基本信息作者&#xff1a; Nancy Duarte(南希.杜瓦特)译者&#xff1a; 冯海洋出版社&#xff1a;电子工业出版社ISBN&#xff1a;9787121195914上架时间&#xff1a;2013-4-1出版日期&#xff1a;2013 年3月开本&#xff1a;12开页码&#xff1…

若川的2018年度总结,平淡无奇

可以点击上方的标签若川的故事、年度总结&#xff0c;查看往期文章偷偷告诉你&#xff0c;公众号内回复【报告】&#xff0c;可以获取你自己的github 2020 年度报告昨晚在我的6个微信群里都发了红包&#xff0c;以这样的方式跨过了2020年。运营公众号真的挺难的&#xff0c;比如…

基于dnn的车牌识别_自然场景中文文字识别,身份证火车票都能识别

图像处理中OCR(Optical Character Recognition光学字符识别)场景非常多&#xff0c;也给大家的工作生活带来了很多便利&#xff0c;比如车牌识别就能管理停车场车辆的出入&#xff0c;快递时只需给一个带有快递信息的图就能自动解析上传发件信息和收件信息&#xff0c;再比如我…

年末的大厂前端面试总结(20届双非二本)-终入字节

关注若川视野, 回复"pdf" 领取资料&#xff0c;回复"1"&#xff0c;可加群长期交流学习自我介绍双非二本,软件工程,自学前端,今年毕业。喜欢编程,古风,日语和英语。常以冷月心之名混迹前端江湖,也曾在混迹网文圈时用冷月心做笔名签约掌阅,作品《清起风云》…

动图演示23个鲜为人知的VSCode快捷键

原文地址&#xff1a;https://dev.to/devmount/23-lesser-known-vs-code-shortcuts-as-gif-80尽管我在VS Code中经常使用许多快捷方式&#xff0c;以下快捷方式可能会派上用场&#xff0c;但我经常忘记它们的存在。我制作了一些GIF&#xff0c;以便更好地记住它们。也许这里面也…