《微信小程式七日談》- 第六天:小程式devtool隱藏的祕密
《微信小程式七日談》系列文章:
- 第一天:人生若只如初見;
- 第二天:你可能要拋棄原來的響應式開發思維;
- 第三天:玩轉Page元件的生命週期;
- 第四天:頁面路徑最多五層?導航可以這麼玩;
- 第五天:你可能要在登入功能上花費大力氣;
- 第六天:小程式devtool隱藏的祕密
本系列的文章並非初學教程,而是筆者在具體開發過程中遇到的問題以及部分解決方案。
筆者參與的小程式專案開發也進入尾聲了,坑也踩得七七八八,對於哪些沒有涵蓋和深入使用的功能筆者就不班門弄斧了。
前幾篇文章講了那麼多細節也好,策略也好,都是應用層面的東西。自微信小程式公佈以來就有先行者不斷的探索小程式背後的執行機制。小程式的開發語法和API與前端工程師熟悉的html/js/css非常相似,所以會令很多人疑惑小程式與普通的HTML5應用到底有什麼區別。這篇文章其實將小程式的基本執行機制剖析的差不多了,簡單概括就是:
- 大部分內容會轉化為常規的html/css/js,並使用webview渲染;
- 部分元件呼叫native實現功能。
既然已經有先行者得出了結論,為啥還要寫這篇文章呢?當然是為了湊齊七篇啦,哈哈哈...
開玩笑!這篇文章的目的不是重複別人的結論,而是將筆者研究小程式開發工具原始碼的一些心得和結論記錄下來,以方便大家後續更深入的探索。
看看devtool的原始碼有什麼
第一步是找到小程式devtool的原始碼,以mac系統為例,原始碼的開啟方式如下圖:
其他的檔案不用理會,我們要研究的主要程式碼在Content/Resources/app.nw/dist
目錄下,這個目錄包括devtool的功能程式碼以及對小程式進行執行、編譯、打包、上傳等功能的程式碼。當然,這些程式碼都是經過混淆的,讀起來還挺費勁(攤手~
需要著重注意的是Content/Resources/app.nw/dist/weapp
目錄,以及commit和trans兩個子目錄:
從檔案的命名上大致可以猜到每個檔案對應的功能:
- trans目錄下的檔案負責將小程式原始碼進行一系列的轉換,最終被轉換為瀏覽器可識別的html、css以及js;
- commit目錄下的檔案負責執行小程式的構建、打包、上傳等功能。
既然我們知道小程式會進行構建打包流程,想得知小程式執行機制最好的辦法就是研究構建完畢之後的程式碼。有了這個目標之後,下一步就是檢視devtool的日誌獲取小程式構建之後的程式碼存放位置。
找到日誌檔案
Content/Resources/app.nw/dist/common/log/log.js
const a = require('fs'),
b = require('log'),
c = require('path'),
d = require('../../config/dirConfig.js'),
e = d.WeappLog;
其中e
便是日誌檔案的存放目錄,然後我們追溯到config/dirConfig.js
中發現目錄路徑是由nw.App.getDataPath()
生成的,這個函式是node-webkit提供的API,生成結果的規則在不同的作業系統下有差異,可惜筆者並沒有找到相關的說明(沮喪)。
但是此次程式碼的探索並非沒有收穫,起碼我們知道了日誌檔案存放的目錄名為“WeappLog”,我們可以使用強大的命令列從硬碟中搜索此目錄:
mdfind WeappLog
大家可以參考這篇文章瞭解
mdfind
命令的用法
從輸出結果可以得知日誌檔案在Mac系統的存放目錄為/Users/<使用者名稱>/Library/Application Support/微信web開發者工具/WeappLog
。進入目錄後就會發現很多以.log
為字尾的日誌檔案:
上傳小程式的流程
打包後的小程式在哪裡
找到日誌檔案後便可以從devtool的執行日誌中獲取小程式被構建後的程式碼存放位置。當然,第一步是要講小程式進行構建,操作方法是在小程式開發工具的“專案”選單”中點選”預覽“:
成功後再日誌檔案中會出現這麼一行記錄:
[Wed Jan 18 2017 15:20:24 GMT+0800 (CST)] INFO pack.js create /Users/<使用者名稱>/Library/Application Support/微信web開發者工具/Weappdest/1484724024071.wx success!
/Users/<使用者名稱>/Library/Application Support/微信web開發者工具/Weappdest/1484724024071.wx
就是構建完成的小程式程式碼!趕緊去看看!
興致勃勃的找到/Users/<使用者名稱>/Library/Application Support/微信web開發者工具/Weappdest/
目錄,然後發現:空空如也!
看來微信團隊還是很謹慎的,在將小程式原始碼上傳之後便會刪除構建產出的檔案。但是這點小伎倆難不倒程式設計師!任何行為都是程式執行的,我們直接修改相關的程式程式碼就可以了嘛!
做點小手腳,看看打包後的程式碼
在Content/Resources/app.nw/dist/weapp/commit/upload.js
中有一段這樣的程式碼:
const a = require('fs'),
j = require('rmdir');
//省略無關程式碼
_exports.uploadForTest = (l, m, n) => {
//省略無關程式碼
c(l, {
noCompile: !0
}, (s, t) => {
if (s) return void n(s.toString());
let u = d.join(k, `${+new Date}.wx`);
b(t, u, (v, w) => {
j(t, (A, B, C) => {});
//省略無關程式碼
if (y > q) return a.unlink(u, () => {}), void n(`程式碼包大小為 ${y} kb,超出限制 ${y-q} kb,請刪除檔案後重試`);
//省略無關程式碼
})
上述程式碼省略了一些與我們當前討論內容無關的程式碼,感興趣的讀者可以自行研究。
上述程式碼有兩個刪除檔案的行為:
rmdir
:刪除構建完成但是並未打包的程式碼目錄;fs.unlink
:刪除打包完成的檔案。
將執行刪除的程式碼註釋以後,再通過小程式開發者工具進行預覽上傳操作後,在上文中我們得到的目錄中便會留下構建以及打包後的檔案了。如下:
其中以.wx
為字尾的檔案是經過打包後的檔案,也就是上傳到微信伺服器的檔案。其同名的目錄資料夾是構建完成且打包之前的原始檔。
以config.js
為例,構建後的程式碼如下:
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
exports.default = {
basePath: 'https://djtest.cn',
fileBasePath: 'https://djtest.cn'
};
其實僅僅將ES6的語法轉譯成了ES5語法。其餘的wxml、wxss以及js檔案基本也是這樣的狀態,所以可以推斷原始碼上傳至微信伺服器後會執行真正的構建動作,開發工具只執行了一些簡單地構建行為。
雖然筆者並未從這份程式碼中得到全部的真相,但希望這篇文章能夠給後續的探索者提供一些微薄的幫助。