給小程序再減重 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.pswp.cn/news/276342.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/276342.shtml
英文地址,請注明出處:http://en.pswp.cn/news/276342.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

rfc mail content-type

轉載鏈接&#xff1a;http://www.w3.org/Protocols/rfc1341/0_TableOfContents.html RFC 郵件正文類型列表&#xff1a; Note: this is a hypertext versionof RFC1341 which has been obsoletedby RFC1521, of which no hypertextversion currently exists. Text …

Coolite Toolkit入門指南

Coolite Toolkit 簡介 Coolite Toolkit 是一個支持ASP.NET AJAX的Web控件Coolite Toolkit是基于跨瀏覽器的ExtJS 庫開發而來的&#xff0c;并且簡化了開發步驟&#xff0c;包含有豐富的Ajax運用Coolite Toolkit和ExtJS 都是開源的可能通過SVN直接獲取Coolite 的代碼簡單的說,就…

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

這一篇是《本周ASP.NET英文技術文章推薦》系列的第一篇&#xff0c;在這個系列中&#xff0c;我將介紹5-10篇比較有價值的、本周發布的、與ASP.NET相關的英文技術文章&#xff0c;幫助各位朋友從良莠不齊的大量文章中挑出一些我認為非常有價值閱讀的&#xff0c;在進行一段簡要…

vim 離線安裝_VIM學習筆記 插件列表(Plugin)

由于zhihu的垃圾編輯器不支持表格&#xff0c;請查看以下完整格式&#xff1a;http://yyq123.github.io/learn-vim/learn-vim-plugin.html說明&#xff1a;本列表完全基于作者的主觀體驗&#xff0c;既不客觀也不完整&#xff1b;建議使用vim-plug或Vundle等插件管理器&#xf…

3 年前端面經和他在創業公司的成長歷程

在掘金上當了幾年的伸手黨&#xff0c;最近也準備輸出一些自己的東西。關于我首先介紹一下我自己&#xff0c;17 年畢業于一所 211 學校&#xff0c;但是由于大學四年馳騁在召喚師峽谷&#xff0c;畢業時也沒有找到一份大廠的工作&#xff0c;隨便找了一家創業公司簽了三方就去…

Spring.NET學習筆記9——打造簡易的依賴注入框架(練習篇) Level 100

我們在第三篇中學習里一個簡易的IoC框架。今天我們接著上次的程序&#xff0c;實現帶參數構造函數對象的實例和屬性的注入 。  我們知道可以通過反射獲取類的構造函數及參數(GetConstructors方法)&#xff1b;可以獲取屬性和屬性的類型(GetProperties方法)。通過Activator的C…

PHP 利用Mail_MimeDecode類提取郵件正文

參考鏈接&#xff1a;http://blog.csdn.net/dmtnewtons_blog/article/details/18765289 rfc mail content-type&#xff1a; 參考鏈接&#xff1a;http://blog.csdn.net/dmtnewtons_blog/article/details/19327105 根據主流的郵件解析類Mail_MimeDecode&#xff0c;提取郵件正…

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…

深入淺出之正則表達式(二)

深入淺出之正則表達式&#xff08;二&#xff09; http://dragon.cnblogs.com/archive/2006/05/09/394923.html 前言&#xff1a; 本文是前一片文章《深入淺出之正則表達式&#xff08;一&#xff09;》的續篇&#xff0c;在本文中講述了正則表達式中的組與向后引用&…

MVC(溫習深入)

MVC&#xff08;Model-View-Controller&#xff0c;模型—視圖—控制器模式&#xff09;是軟件工程中的一種軟件架構模式。它把軟件系統分為三個基本部分&#xff1a;模型&#xff08;Model&#xff09;&#xff0c;視圖&#xff08;View&#xff09;和控制器&#xff08;Contr…

面試官問:能否模擬實現JS的new操作符(高頻考點)

可以點擊上方的話題JS基礎系列&#xff0c;查看往期文章這篇文章寫于2018年11月05日&#xff0c;new模擬實現&#xff0c;Object.create是面試高頻考點&#xff0c;之前發布在掘金有近2萬人閱讀&#xff0c;現在發布到公眾號聲明原創。1. 前言這是面試官問系列的第一篇&#xf…

Linux環境下設置IPDNSGateway

轉載鏈接&#xff1a;http://www.myhack58.com/Article/sort099/sort0102/2011/29291.htm 在Linux中不管你是做服務器還是只是平常使用&#xff0c;上網肯定都是最重要和不可缺少的一個因素之一&#xff0c;所以就涉及到它的ip gateway dns等network配置和使用。但是設置Linux…

跟我一起學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;則重建二叉樹并返回。思路回顧三種經典的遍歷&…

越來越覺得現在的工作很枯燥

很不想這么說&#xff0c;但又不想欺騙自己&#xff0c;真的是很枯燥&#xff0c;不過這種感覺早在一年在在上一間公司時就很強烈的有過這種感覺了&#xff0c;只不過現在是又一次有感觸罷了。話說說我這種性質的工作枯燥很多人都講過&#xff0c;如果哪個人說不枯燥估計腦袋進…

推薦關注這7個高質量的前端公眾號

拓寬眼界&#xff0c;增加深度&#xff0c;在閱讀的世界里&#xff0c;我們往往能找到不一樣的態度&#xff0c;提升朋友圈質量&#xff0c;從關注這幾個公眾號開始。輕掃一下二維碼就行了&#xff0c;你可以試試&#xff0c;肯定會有意外收獲。大遷世界 簡介&#xff1a;前端小…

MySQL 實用語句集合

MySQL 實用語句集合 參考鏈接[用戶]&#xff1a;http://blog.csdn.net/dmtnewtons_blog/article/details/9136339 參考鏈接[屬性]&#xff1a;http://stackoverflow.com/questions/15821532/get-current-auto-increment-value-for-any-table 參考鏈接[索引]&#xff1a;htt…