爲了節省開發時間,咱們儘可能整合現有業務線小程序代碼,減小業務改動。php
同時爲了後期計算各業務佔用空間狀況方便,咱們直接將各業務線小程序工程代碼拷貝到各自業務線目錄下,最終的目錄結構以下:css
.
├── common # 通用模塊/公共業務
├── home # 首頁 ├── flight # 機票 ├── train # 火車票 ├── bus # 汽車票 ├── hotel # 酒店 └── ticket # 門票
common 模塊即工程的複用部分,具體業務代碼都在各自目錄下。整體架構以下:webpack
微信小程序其實並無提供組件化開發的方式。只是提供了 template
的方式,因此咱們只提供了爲數很少的頁面及組件,例如:城市定位、日曆組件等。可是收益倒是很是明顯的,像這些頁面大小都在 20KB~30KB,若是每一個業務本身整一套可能將徒增上百 KB 代碼。web
公共 API 咱們提供了統一的 Watcher
監控、 Requester
請求、 Loading
加載轉態、 Navigation
導航等。這些公共邏輯的抽取,爲整個項目整合節省了巨大的空間,使 size 達標看起來不那麼難了。typescript
工程複用上節省了很大一部分空間。可是空間是有限的,業務需求是無限的。並且,size 的大小會影響用戶加載的速度,包括下載最新版本代碼的速度和小程序初始化的速度,因此還須要進一步進行代碼壓縮。npm
咱們知道微信小程序開發者工具自己提供了『代碼壓縮上傳』功能。小程序
可是我的以爲它是個『假的壓縮選項』。由於在閱讀開發者工具的源碼邏輯以後,發現它的壓縮,只是將 JavaScript 用 uglify 進行混淆壓縮。而對 WXML、WXSS 沒有進行任何壓縮處理。同時,對資源路徑中的無用文件也沒有作處理。微信小程序
在小程序開發者工具的 Sources 面板,查看 JavaScript 腳本,會發現:項目中全部的 JavaScript 都會被 同步加載 ,不論是否被 require
。bash
每一個腳本都會被套上以下代碼:服務器
define("some.js", function(require,module){ // 本來的代碼 });
這種加載方式相似 AMD,可是跟標準的 AMD 又有些不一樣,缺乏了依賴部分的聲明。
而對於 WXSS 和 WXML 文件,則被開發者工具自動轉換爲 JavaScript 後加載,其中:
WXSS:主要處理的是 import 邏輯,而後生成的 CSS,經過腳本的形式插入頁面使用。
WXML:相似於 React Naitive 的 JSX,被編譯成 createElement
相似的形式。
在 MacOS 系統中,右鍵開發者工具『Show Contents』(顯示包內容),就能在 Resources/app.nw/
下找到相應的源碼,完成路徑以下: /Applications/wechatwebdevtools.app/Contents/Resources/app.nw/
。
源碼都是壓縮事後的 JavaScript 腳本,可使用 js-beautity 進行格式化,以便於閱讀。
// 在源碼目錄的 app 目錄下執行
find . -type f -name '*.js' -exec js-beautify -r -s 2 -p -f '{}' \;
在資源目錄下: app/dist/app.js 的第 37 行 window.addEventListener("resize", function() {})
以前,加入 nw.Window.get().showDevTools();
。以後每次打開微信開發者工具時,會自動啓動針對『開發者工具』的開發者工具,並能夠經過它調試微信的開發者工具。
在打印日誌時,不要用 console.log
,請使用 global.contentWindow.console.log
。這樣,才能輸出到上面所說的開發者工具的開發者工具的控制檯裏。(NW.js 的 Node JS Context 和 Webkit JS Context 是分開的, JavaScript 腳本運行在 Node 的 JS Context 中,所以,打印其實打印在 Node 的輸出中,並不在 Webkit 的開發者工具的控制檯中。 global.contentWindow
獲取的是 Webkit 的 JS Context 裏的 Window)
使用這兩點技巧,讀者們能夠優雅地去閱讀微信開發者工具的源碼了。
在閱讀源碼,知道微信小程序的內部加載構建方式以後,咱們能夠針對性的對 JavaScript、WXML、WXSS 等代碼文件進行打包壓縮。
因爲微信只是將 js
進行了混淆壓縮,並無打包合併成一個文件。因此咱們提供了打包壓縮工具將 js
文件合併壓縮成一個 bundle.js
文件。合併成一個文件有如下好處:
require
的長路徑沒了,腳本壓縮效率變高上文說了 JavaScript 都會被同步加載,因此不用擔憂打包成一個文件後會延長小程序加載時間。
那麼打包壓縮工具具體作了什麼工做呢?
app.js
,而每一個頁面都有本身的入口 page.js
利用 AST,將 page.js
裏頁面註冊 Page(pageOpt)
代碼改爲 global.YPage(pageName, pageIndex)(pageOpt)
pageName
頁面路由
pageIndex
是打包工具根據頁面路由內部自動維護的
// global.YPage 函數 global.YPage = (pageName, index)=> { return (pageOpt) => { // 其餘處理邏輯 global['p' + index] = ()=> { Page(pageOpt); } } }
這樣 page.js
裏實際是這樣的代碼
global['p' + index] = ()=> { Page(pageOpt); }
這樣並不會執行 Page(pageOpt)
,頁面也沒註冊啊。這就是要達到的目的,繼續日後看。
將全部這些入口 require
到一個統一的入口文件中,而後用 webpack 打包壓縮輸出到 bundle.js
。
require('app.js') require('page1.js') require('page2.js') ...
如今 page.js
裏的代碼都打包到單一文件 bundle.js
裏了。將 page.js
內容替換成 global['p' + index]()
,這樣第三步中的 Page(pageOpt)
不就能夠執行註冊頁面了。
app.js
內容爲 require('./bundle.js')
即大功告成。/<!--((.|\n|\r)*?)-->/gm
去除註釋/\"\n\s*/g
去除換行JSON.stringify(JSON.parse(...))
這裏,有些讀者會可能提出兩個疑問:
關於第一個問題,一個約 1000KB 的代碼,空白字符和換行大概有 10KB。在有上限的狀況之下,10 KB 也是要珍惜的。
關於第二個問題,我的認爲微信開發者工具的開發者以爲沒有必要去作。由於,WXML 和 WXSS 都會被轉義成 JavaScript 腳本,在此過程當中,無論 WXML 和 WXSS 是否被壓縮,它們的轉化結果是相同的。所以,壓縮與否,對於最終產物是沒有影響的(最終產物指在服務器二次打包後的結果,也是用戶真正使用的)。可是,Size 是以本地打包上傳的內容進行計算的,不進行此步壓縮,會使微信服務端斷定的 Size 增大。
工程龐大了,確定會存在不少無用的空目錄,空文件,沒有被 import
的 js
、 wxml
、 wxss
文件。
刪除這些無用文件不只能夠減少 size,還能夠提高小程序加載時間。上文說了這些文件都會被轉成 JavaScript 進行加載的,是會佔用加載時間的。
因爲經過 webpack 打包,除了 page.js
、 bundle .js
文件,其餘 js
文件均可以刪掉。
打包壓縮工具在打包時,已經記錄了全部頁面的路由。遍歷分析全部路由下的 wxml
文件,經過 xmldom 解析代碼記錄其餘被 import
的 wxml
文件。最後遍歷全部 wxml
文件,刪除不在 import
列表裏的無用 wxml
文件。
相似處理 WXML。遍歷分析全部路由下的 wxss
文件,經過正則 /@import\s*["']([^"']+)["']/g
分析代碼記錄其餘被 import
的 wxss
文件。最後遍歷全部 wxss
文件,刪除不在 import
列表裏的無用 wxss
文件。
除了利用工具進行壓縮,在編寫代碼時,也能夠經過一些方法來減少體積,在這裏簡單列幾點:
import
和 class
。通過打包工具的極限壓縮處理,還有代碼設計上的可複用性,目前咱們七個業務線的微信小程序整合後代碼編譯包大小維持在 1300KB 左右。
還剩餘 730KB 的可用空間。
但願這次在微信小程序整合上作的,工程化抽取公共邏輯、規範業務代碼,經過工具進行鍼對性的代碼打包壓縮的實踐能給你們帶來必定的幫助