<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          給小程序再減重 30% 的秘密?

          共 7388字,需瀏覽 15分鐘

           ·

          2021-04-19 19:34

          前言

          在 web 開發(fā)場(chǎng)景,減少代碼體積雖然是性能優(yōu)化的一個(gè)方向,還沒到錙銖必較的程度。但是在小程序場(chǎng)景,由于代碼包上傳階段限制了主包 2M 和總包 16M(近期微信官方正在內(nèi)測(cè)將總包上限調(diào)整至 20M )的尺寸,超過就會(huì)面臨無法發(fā)版的風(fēng)險(xiǎn),代碼包體積的優(yōu)化就變得特別重要了。京喜小程序首頁作為微信購物的大入口,承載大量流量,功能復(fù)雜模塊眾多,又要與其他核心業(yè)務(wù)和公共組件共享 2M 的主包空間,因此代碼包瘦身的工作在持續(xù)不斷進(jìn)行,否則無法滿足業(yè)務(wù)的快速增長(zhǎng)。本文將結(jié)合以往優(yōu)化策略與最近一次的瘦身實(shí)踐,分享小程序代碼瘦身的經(jīng)驗(yàn)與思考。

          常見的瘦身方式

          京喜首頁項(xiàng)目是一個(gè)優(yōu)化良好的項(xiàng)目,對(duì)于常見的優(yōu)化措施,已經(jīng)有過很好的實(shí)踐,就讓我們我們先回顧一下有哪些常見的優(yōu)化策略吧:

          1. 代碼分包:將相對(duì)獨(dú)立的頁面和組件拆分到分包,可以解決主包體積受限問題;

          2. 依賴分析:移除未引用的頁面、組件和其他文件;

          3. 避免使用本地資源:除了兜底圖片,其他都盡可能使用 url 的方式,由于 base64 圖本質(zhì)上是將信息編碼成長(zhǎng)字符串,也會(huì)占用很多空間,不建議使用;

          4. 對(duì)所有類型的文件都進(jìn)行壓縮并清理注釋,包括了:js、wxml、wxss、json;

          此外,京喜首頁團(tuán)隊(duì)還針對(duì) Taro 開發(fā)場(chǎng)景進(jìn)行了如下優(yōu)化:

          1. 分析出編譯后每個(gè)文件的高頻重復(fù)代碼(如處理兼容性的 pollyfill 代碼),拆分生成公共文件,替換原引用以實(shí)現(xiàn)共用。

          標(biāo)準(zhǔn)和工具

          在開始正式介紹瘦身實(shí)踐之前,我們先來明確一下代碼包體積的衡量標(biāo)準(zhǔn)和統(tǒng)計(jì)方式吧。

          小程序上傳代碼以代碼包尺寸為準(zhǔn),所謂 2M 的限制,就是指該尺寸不能超過 2048KB。

          從信息傳輸角度來說,Gzip 等壓縮工具可以進(jìn)行很多信息化編碼優(yōu)化,因此一些內(nèi)容重復(fù)是可以容忍的,但是由于我們的目標(biāo)是為了解決小程序上傳限制,就只有對(duì)代碼包尺寸錙銖必較了。

          在開發(fā)者工具-詳情-基本信息-上次預(yù)覽或上次上傳,可以查看到最近一次的代碼包體積,本文接下來所介紹的優(yōu)化都是以縮小這個(gè)體積為目的。

          查看代碼包尺寸

          但是代碼上傳生成模板速度很慢,如果每次都要根據(jù)這里的數(shù)據(jù)來統(tǒng)計(jì)體積變化,效率太低了。

          在未改動(dòng)項(xiàng)目配置的情況下,我們就可以間接以代碼目錄的文件體積大小作為變化參照。怎么方便的統(tǒng)計(jì)文件體積呢?這里我用了tree-cli[1],利用它提供的參數(shù),可以輸出具備尺寸統(tǒng)計(jì)和排序功能的代碼文件清單:

          npm install -g tree-cli
          // 目標(biāo)目錄
          cd target-directory
          // 輸出文件為 size-analysis.md
          tree -s --sort=size -o size-analysis.md

          清單內(nèi)容格式如下:

          .
          ├── [ 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

          瘦身實(shí)踐

          前面說到京喜首頁優(yōu)化措施都做的很好了,下面即將分享的是一些不那么常見的優(yōu)化方式,優(yōu)化空間有大有小,想要優(yōu)化小程序代碼包,建議先盡量完成前文提到的優(yōu)化方案,這樣獲得的收益最明顯,然后再來看接下來提到的這些方式吧~

          一、字體和顏色的全局共用

          小程序文檔內(nèi)關(guān)于繼承樣式的說明為:繼承樣式,如font,color, 會(huì)從組件外繼承到組件內(nèi)。

          分析項(xiàng)目現(xiàn)狀,我們通常會(huì)把字體定義放在公共 css 文件內(nèi),隨著頁面或組件引入公共 css,font 也將被重復(fù)引入,可以通過改造,把 font 的定義僅放在 app.wxss 內(nèi),取消組件和頁面的引入,可以達(dá)到減少整體代碼包體積的目的。

          關(guān)于這一項(xiàng)首頁項(xiàng)目體積減少 1%,預(yù)估整個(gè)項(xiàng)目還有 20kb 左右的 font 定義可清理。

          如果有全局的顏色定義,也可以進(jìn)行類似的優(yōu)化。

          二、樣式補(bǔ)全功能的使用

          作為 web 開發(fā)者,對(duì) -webkit- 這種前綴一定不陌生,為了適配不同瀏覽器內(nèi)核,通常我們會(huì)在編譯階段使用 autoprefixer 進(jìn)行樣式的自動(dòng)補(bǔ)全。

          而小程序開發(fā)者工具也提供了樣式補(bǔ)全的能力:詳情-本地設(shè)置-可以勾選「上傳代碼時(shí)樣式自動(dòng)補(bǔ)全」

          這個(gè)補(bǔ)全和我們?cè)诰幾g時(shí)做的有什么不同嗎?

          關(guān)鍵在于它實(shí)現(xiàn)的時(shí)機(jī):如果是本地模板上傳前,那么應(yīng)該和我們編譯的補(bǔ)全效果一樣;如果是在上傳模板后,也許可以借此減掉補(bǔ)全內(nèi)容所占的尺寸。

          結(jié)合小程序代碼包傳遞過程和樣式補(bǔ)全時(shí)機(jī),大概有以下 3 種情況:

          階段一補(bǔ)全:

          階段一

          階段二:

          階段二

          或者是階段三:

          階段三

          為了驗(yàn)證猜想,來做一個(gè)實(shí)驗(yàn)吧,比較「 項(xiàng)目編譯不補(bǔ)全樣式+開發(fā)者工具設(shè)置樣式補(bǔ)全」 vs「 項(xiàng)目編譯補(bǔ)全樣式+開發(fā)者工具不設(shè)置樣式補(bǔ)全」,模板體積統(tǒng)計(jì)如下:

          開發(fā)者工具提供樣式補(bǔ)全
          編譯提供樣式補(bǔ)全

          可見前者比后者少了 58kb,這說明,開發(fā)者工具提供的樣式補(bǔ)全不是在階段一做的,不然模板體積應(yīng)該和我們自己做的編譯補(bǔ)全基本一致。

          那么,就可以愉快的去掉編譯補(bǔ)全,使用小程序開發(fā)者工具提供的能力了。

          不過這樣改動(dòng)會(huì)出現(xiàn)一個(gè)小問題,開發(fā)者工具內(nèi)的樣式是未經(jīng)補(bǔ)全處理的,個(gè)別樣式會(huì)有點(diǎn)問題,測(cè)試就發(fā)現(xiàn) mask-border-source 無效,而相應(yīng)真機(jī)因?yàn)橐烟砑訕邮窖a(bǔ)全沒有問題。為了不出現(xiàn)預(yù)覽誤會(huì),建議給這種尚未支持的樣式手動(dòng)寫上 -webkit- 前綴,保證開發(fā)和真機(jī)表現(xiàn)一致。

          三、小心 Sass!

          sass/less 等工具使得 css 的編寫變得更加流暢,函數(shù)和變量的引入也讓 css 有了一點(diǎn)工程化的意味。但是你有沒有觀察過 sass 的編譯實(shí)現(xiàn)呢?

          // a.scss,作為被引用方
          .banner { // 樣式定義
          color: red;
          }
          $COLOR = red // 變量定義(函數(shù)定義類似)

          // b.scss,作為使用方
          @import 'a.scss';
          .banner_wrapper {
          background: white;
          color:$COLOR;
          }

          關(guān)注 b.sass 的編譯后:

          // a.scss的引用消失了,內(nèi)容被整合到文件內(nèi)

          .banner { // a.scss內(nèi)的樣式定義會(huì)被拷貝進(jìn)來
          color: red;
          }
          .banner_wrapper {
          background: white;
          color:red; //變量定義會(huì)被按值替換
          }

          這里出現(xiàn)的問題是:我們是否需要.banner被拷貝進(jìn)來呢

          為了避免多引入不需要的樣式定義,有以下幾個(gè)方向:

          1. 按功能拆分 a.scss 內(nèi)的樣式定義,按需引入。

          2. 使用 @include 語法,將 banner 的定義變成一個(gè)變量,按需引入。

          而在小程序場(chǎng)景,wxss 語法支持 @import,實(shí)現(xiàn)了極弱版的模塊化,使得我們可以再加一個(gè)角度解決上面的問題:

          1. 繞過 sass 編譯,使用小程序的 @import 語法,引入需要的樣式定義。(關(guān)于如何繞開 sass 編譯,可以考慮使用注釋片段,或者白名單篩選識(shí)別)

          四、多端場(chǎng)景的冗余代碼移除

          京喜首頁項(xiàng)目使用 Taro 開發(fā),需要適配 H5/微信小程序/QQ 小程序等多端場(chǎng)景,利用 Taro 提供的環(huán)境變量能力,可以在方法內(nèi)部實(shí)現(xiàn)多端差異處理,比如下面這段:

          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(){...}

          但是,環(huán)境變量方式?jīng)]辦法處理 initH5 這種方法定義,導(dǎo)致也被打包進(jìn)來了。

          因此,我們需要更強(qiáng)大的差異打包:京喜首頁利用內(nèi)部的 wxa-cli 工具提供的條件編譯能力,通過注釋段落標(biāo)記,圈注出多端內(nèi)容,實(shí)現(xiàn)了代碼片段層面的差異打包,細(xì)節(jié)如下:

          init(){
          if(process.env.TARO_ENV === 'weapp'{
          // 微信小程序邏輯
          this.initWeapp()
          }else if(process.env.TARO_ENV === 'h5'){
          // H5頁面邏輯
          this.initH5()
          }
          }
          initWeapp(){...}
          /* wxa if:type=='h5' */ 標(biāo)記h5端代碼開始位置
          initH5(){...}
          /* /wxa */ 標(biāo)記注釋結(jié)束位置

          打包后代碼:

          init(){          // weapp內(nèi)
          this.initWeapp()
          }
          initWeapp(){...}

          initH5 消失了,代碼更瘦了

          五、整理 log

          為了調(diào)試方便,你的項(xiàng)目?jī)?nèi)有沒有打很長(zhǎng)的 log,類似于這種:

          console.log('==============xx接口異常============')

          經(jīng)過測(cè)試,首頁代碼文件內(nèi)有 5KB 的內(nèi)容是 log 語句,可以試著優(yōu)化一下:

          1. 及時(shí)移除開發(fā)調(diào)試用 log

          2. 信息類 log 約定長(zhǎng)度更短的格式

          六、良好的編碼策略

          有沒有同樣的邏輯需求,可以用更短更優(yōu)雅的寫法來實(shí)現(xiàn)呢?

          關(guān)于代碼分析是個(gè)很復(fù)雜的話題,暫時(shí)列一個(gè)結(jié)論相對(duì)明確的寫法吧

          格式化數(shù)據(jù)時(shí)數(shù)據(jù)的存取和中間變量問題

          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
          }))

          七、樣式命名編譯優(yōu)化

          京喜首頁項(xiàng)目由于 H5 端混搭老項(xiàng)目,為了避免類名沖突,采用了形如block-name__element--modifier的 bem 命名規(guī)則。在開發(fā)中進(jìn)一步發(fā)現(xiàn),一些類似 navbar-content__item 的常見命名偶爾撞車,為了避免沖突,類名就越寫越長(zhǎng),而小程序代碼包的尺寸影響也在悄悄增大。

          為了解決命名沖突的問題,將類名 hash 化是個(gè)好辦法,css-modules 就是個(gè)成熟的插件,可以通過配置規(guī)則,對(duì)樣式名編譯出「文件名+內(nèi)容相關(guān)」的獨(dú)特化 hash。

          但是研究下它的實(shí)現(xiàn),會(huì)發(fā)現(xiàn)對(duì)代碼尺寸的影響不容樂觀,看一個(gè)編譯后例子:

          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 } // 新增了一個(gè)map文件,實(shí)現(xiàn)原名與hash名的映射,增加的具體尺寸為:原類名+hash

          計(jì)算整體內(nèi)容變化:

          1. js 內(nèi)新增引入 map 語句:增加一句代碼

          2. wxml 內(nèi):原為 n 個(gè)類名,現(xiàn)為 n 個(gè)「style.+原類名」,增量為 n 個(gè)style.

          3. map 文件 與 wxss 文件合計(jì):map 內(nèi)有 n 個(gè)原類名與 hash 映射, wxss 現(xiàn)為 n 個(gè) hash , 減去原來的 n 個(gè)原類名 ,合計(jì)增量為 2n 個(gè) hash

          可見引入 css-modules 會(huì)導(dǎo)致整體代碼尺寸增加。

          會(huì)不會(huì)覺得這個(gè)新增的 map 文件的作用特別熟悉呢?

          在我們壓縮 js 文件時(shí),會(huì)有一個(gè) sourceMap 文件,它保留了原始命名和代碼位置,可以方便定位和 debug。

          css-modules 實(shí)現(xiàn)的 map 文件,在我看來作用和 sourceMap 的命名索引差不多,對(duì)于代碼邏輯來說,除了保持原類名的引用信息,它好像也沒什么用了,在尺寸敏感場(chǎng)景,就可以考慮去掉 map 文件,還是上文的示例,如果可以實(shí)現(xiàn)成這樣就好了:


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

          // wxml文件
          <view className="hash"></view> // 對(duì)style.banner進(jìn)行求值并替換

          // wxss文件
          .hash { xx } // 這里不變

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

          網(wǎng)上遍尋沒有相關(guān)的處理,只能自己造輪子開搞了。

          由于當(dāng)前主要目的是對(duì)小程序代碼瘦身,H5 端文件處理和小程序也有一些差異,所以暫時(shí)只對(duì)小程序場(chǎng)景造了插件,取名 weapp-css-modules ,github 地址在這里:https://github.com/o2team/weapp-css-modules

          大概思路是:

          1. 完成小程序的 css-modules 實(shí)現(xiàn)

          2. 在此基礎(chǔ)上進(jìn)行 map 移除的相關(guān)簡(jiǎn)化邏輯

          3. 進(jìn)一步的,考慮到小程序組件內(nèi)默認(rèn)樣式隔離的特性,對(duì) hash 化的命名再次縮短,變成單字母編排。

          如果是只開發(fā)小程序端,可以借此實(shí)現(xiàn)小程序樣式命名相關(guān)的代碼瘦身,而對(duì)于 Taro 開發(fā)的多端場(chǎng)景,還可以同時(shí)解決 h5 端的命名沖突問題。

          還是上面的例子,下面是 weapp-css-modules 編譯后效果:

          // js文件
          let style = {} // 不引用map,加入對(duì)不規(guī)范引入style的兼容

          // wxml文件
          <view className="a"></view> // 對(duì)style.banner進(jìn)行求值并替換,加入單字母編排

          // wxss文件
          .a { xx } // 因?yàn)樾〕绦蚪M件樣式隔離,所以可以最短化類名

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

          京喜首頁項(xiàng)目通過改造組件采用 css-modules 寫法,加上 weapp-css-modules 編譯,代碼相對(duì)尺寸減少了 10%,還是很有效果的,感興趣的同學(xué)可以試用一下。

          總結(jié)

          關(guān)于代碼瘦身,想提一下信息學(xué)中熵的概念:熵反映信息的無序程度,一段信息無序程度越低,它的熵值越低,可被壓縮的空間越大;無序程度越高,熵值越高,可被壓縮的空間越小。而數(shù)據(jù)壓縮或者是代碼瘦身的過程,就是通過優(yōu)化信息存儲(chǔ)方式以逼近它真實(shí)的熵值。

          從這個(gè)角度來說:

          • 「字體和顏色的全局共用」和「樣式補(bǔ)全功能的使用」是借用小程序提供的能力,信息量沒變;

          • 「小心 Sass」、「多端場(chǎng)景的冗余代碼移除」是減少不用的信息;

          • 「整理 log」和「樣式命名編譯優(yōu)化」是凝練有效信息;

          看起來最不好歸類的是「良好的編碼策略」,它是在編碼階段對(duì)信息的梳理和整合,也算凝練有效信息吧。

          以上就是京喜首頁項(xiàng)目這次代碼瘦身的主要方式了,除此之外的刪除不用文件、整合公共文件這些體力活,我就不再啰嗦了。通過以上方式,京喜首頁代碼在原本優(yōu)化良好的基礎(chǔ)上,實(shí)現(xiàn)了再次減重 30%的目標(biāo),希望能給小程序開發(fā)者們帶來有價(jià)值的信息和思考。

          參考資料

          [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

          最后





          如果你覺得這篇內(nèi)容對(duì)你挺有啟發(fā),我想邀請(qǐng)你幫我三個(gè)小忙:

          1. 點(diǎn)個(gè)「在看」,讓更多的人也能看到這篇內(nèi)容(喜歡不點(diǎn)在看,都是耍流氓 -_-)

          2. 歡迎加我微信「huab119」拉你進(jìn)技術(shù)群,長(zhǎng)期交流學(xué)習(xí)...

          3. 關(guān)注公眾號(hào)「前端勸退師」,持續(xù)為你推送精選好文,也可以加我為好友,隨時(shí)聊騷。



          點(diǎn)個(gè)在看支持我吧,轉(zhuǎn)發(fā)就更好了



          瀏覽 74
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧日成人网站 | 九哥操逼网91 | 超碰99在线免费观看 | 大鸡巴伊人网 | 婷婷精品免费久久 |