Idea!
小程序包体积一直是困扰小程序业务扩展的重要卡点,整个⼩程序所有分包⼤⼩不超过 20M,单个分包/主包大小不能超过2M。小程序包体积优化成了老生常谈的话题。
其中对样式文件体积的压缩除了提取公共样式,样式合并简写,减少选择器层层嵌套等方法,对于经过长期迭代的小程序无效的样式类也占了很大的体积。
不知道大家有没有这样的习惯,功能更新迭代中我们更多的关注了html和js逻辑,对css样式经常是累加的过程,没有过多关注已经不用的样式类。项目经过长期迭代后无效样式在小程序包中的体积已经不可忽视了。
怎么办?刚开始我用最笨的方法,拿每个css的类名全局搜索有没有在用。一个页面几百行的css,筛选了一天后只减少了不到10kb的体积……
如果能有段脚本帮我一键删除岂不省出了摸鱼的时间!
Action!
说干就干!
小程序中主要的样式选择器我用的都是类名,第一版就只关注类名,删除wxss中无效的样式类。这里只介绍工具的原理,大家可以动手操作起来!
怎么知道wxss中哪些是无效的样式?分为两步走,首先要知道wxml中都有哪些类名,再检查wxss中类名是否存在wxml中。
一、遍历wxml筛选类名
- 考虑到子组件可能应用父组件的样式,先读取组件的json文件,获取使用到的自定义组件及组件路径构造json,key=组件名,value=组件路径;
{
applywords:'../components/applyWords/index'
barcard:'../components/barcard/barcard'
headerimgcard:'../../../components/headerimgcard/index'
}
- 考虑到组件中可能用到了template模板也应用了父组件样式,先遍历一遍wxml的每一行,出现<import>导入模板和<template name=‘template’>定义模板的,先读取模板内容筛选类名,构造json,key=模板名,value=模板类名数组;
{
WxEmoView: [
[ 'wxParse-hide' ],
[ 'WxEmojiView', 'wxParse-inline' ],
[ 'wxEmoji' ]
],
wxParse: [],
wxParseVideo: [
[ 'wrap-video-img' ],
[ 'native-video' ]
],
wxParseImg: [ [ 'wxParse' ] ]
}
- 再遍历wxml的每一行,对于有class属性的行,将这一行的class筛选出构造数组;
[ 'page-container', 'IphoneX' ]
- 将每一行的class数组push到另一个页面级的数组中,最后整个wxml页面将得到一个二维的class数组;
[
[ 'page-container', 'IphoneX' ],
[ 'list-empty-spread', 'flex' ],
...
[ 'loadMore', 'detail', 'title' ],
[ 'loadings' ],
]
- 遍历到使用组件的行,用第一步获取到的组件路径找到组件的wxml,遍历筛选每一行的类名返回一个二维数组;concat拼接到页面级的数组中;
- 遍历到使用模板的行<template is=“templateName”/>时,用第二步获取到的类名concat拼接到页面级的数组中
- 最终一个wxml页面会得到一个二维的类名数组,如第四步的示例;
二、遍历wxss的每一行,与wxml获取到的类名做比对,筛选出无效的样式类
- 将wxml获取到的二维class数组flat()拉平成一维数组的classList;
[
'page-container',
'IphoneX',
...
'loadMore',
'detail',
'title',
'loadings',
]
- 遍历wxss的每一行,遇到选择器行,判断选择器是否有效;注意选择器有选择器组的情况(.a .b, .c .d),先对选择器行现根据逗号切分成数组,再遍历数组根据空格再切分;最后得到一个二维数组;
//将
".detail-value .item-header-time,.item-header.spread-arrows, .mine-invited-tag .mine-invited-via {"
//解析为
[
[ '.detail-value', '.item-header-time' ],
[ '.item-header.spread-arrows' ],
[ '.mine-invited-tag', '.mine-invited-via' ]
]
- 遍历这个二维数组与classList对比,如果其中一个类名不存在,则选择器组就无效,删除这个选择器组,如果整行的选择器组都无效,则该样式块就无效,删除整个样式块;
- 将要删除样式模块备份;
Tips!
上面只介绍了主体的流程,其中很多要考虑的细节:
- 在json文件中"usingComponents"声明的组件名可能是驼峰式的,在使用组件时组件名可能是-分割的;
- 对于template模板,可能使用模板在前,声明模板在后,可能使用import导入的模板,声明模板内可能有引用了另外的模板;
- 代码如果没有被格式化或格式不规范,各种匹配的情况更多;
- class属性中的动态类名的情况也要取到class=“loadMore {{ test ? ‘detail’ : ‘title’ }}”,除非动态类名是变量的情况就忽略不记;
- wxml和wxss中的注释行要被忽略;
- 样式选择器还有id选择器,标签选择器,复合选择器,伪类选择器,子级选择器,兄弟选择器等情况要处理;
- 之所以要备份删除的样式类是因为对于变量定义的动态类名或修改的第三方组件的样式类因在wxml中检查不到类名会被误删,所以还需要人工检查一遍是否需要恢复。
- 我这里没有检查组件是否是样式隔离的,默认没有样式隔离。
- 最后,将整个流程封装,将一个文件夹地址传入命令行,就可以将文件夹下所有组件中无效css秒删。
Finally!
工具还有很多考虑不全待完善的地方,可能实现思路也不够简洁,欢迎大家一起探讨!有好的想法下方留言。