做者介紹:週中堅,美團點評工程師,4年 Web 前端開發經驗,主要負責過會員卡、外賣、預訂、商家平臺等業務的前端開發,如今是美團點評點餐團隊的一員。css
咱們團隊的小程序開發經驗系列文章已經發布了4篇,這些文章主要介紹了小程序開發概述,小程序的視圖層,小程序的邏輯層, 小程序開發中碰到的坑(幾個設計實例)。相信你們看了這些文章,再結合官方文檔已經能夠毫無壓力地開發小程序了,可是爲何有這些坑,是否是能夠繞過去,怎麼排查問題,咱們還想從源頭——小程序的源碼的角度來嘗試分析,所以有了這篇源碼解析。html
以 mac 電腦爲例,首先進入應用程序文件夾,再右鍵微信開發者工具顯示包內容,最後讓咱們進入 ./Contents/Resources/app.nw
目錄下就能夠查看小程序的源碼了,代碼結構如圖:
前端
文件夾看起來不少,但命名還算清晰,如今讓咱們先從開發者工具界面的角度來看下都用到了哪些文件吧。web
package.json
對應起來,好比name, icon, version等。
./app/dist/components/setting/setting.js
,而用戶設置的保存(包括後面要說的模擬器設備、網絡等信息)是調用了
./app/dist/stores/*.js
方法。
./app/dist/common/menu/menu.js
,動做在
./app/dist/common/actions/actions.js
,你們能夠自行到代碼中查看文件的
require
進一步分析。
./app/dist/config/DeviceModules.js
,網絡配置在
./app/dist/common/jssdk/osInfoSdk.js
。
其中 Console, Sources, Network 就是直接使用的 DevTools, 而 Storage, AppData, Wxml, Sensor 是本身實現的。chrome
參照 Storage, AppData, Wxml, Sensor 這些調試工具,這些咱們要本身添加一個其實很是簡單,只要在./app/dist/extensions
目錄下新建一個文件夾,用html/css/js
完成這個工具的功能,再改devtools.html將這個工具引入進來chrome.devtools.panels.create()
便可,如圖:
json
有趣的是,在0.15.150201這個測試版中已經發現了一個名爲Bluetooth的開發工具。
小程序
上面一節主要講的是小程序開發者工具的源碼,咱們藉助分析源碼能夠搞清楚代理是怎麼設置的,模擬器的設備和網絡如何添加,怎樣開發一個知足本身特定需求的 DevTool。微信小程序
這一節主要介紹咱們寫的微信小程序的代碼是如何變成頁面在用戶的終端運行的:api
onlinevendor/wcc
在編譯時把 wxml 文件 轉爲 js,onlinevendor/wcsc
在編譯時把 wxss 文件轉化爲 js,這也是編譯包比代碼庫要大很多的重要緣由。trans/transWxmlToHtml
將 wxml 轉成 dom tree, 再進一步用 webview 渲染,trans/transWxssToCss
將 wxss 轉成 css,提供 view 層樣式。onlinevendor/WAService.js
提供了service 層幾乎一切功能。首先是看一下剛纔提到的 pageFrame,對應的 transConfigToPf 主要用字符串替換的方式完成轉換。微信
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon">
<meta http-equiv="Content-Security-Policy" content="script-src 'self' *.qq.com 'unsafe-inline' 'unsafe-eval'">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0" />
<script>
var __webviewId__;
</script>
<!-- percodes -->
<!--{{appconfig}}-->
<!--{{pageconfig}}-->
<!--{{WAWebview}}-->
<!--{{reportSDK}}-->
<!--{{webviewSDK}}-->
<!--{{exparser}}-->
<!--{{components_js}}-->
<!--{{virtual_dom}}-->
<!--{{components_css}}-->
<!--{{allWXML}}-->
<!--{{eruda}}-->
<!--{{style}}-->
<!--{{currentstyle}}-->
<!--{{generateFunc}}-->
</head>
<body>
<div></div>
</body>
</html>複製代碼
開發者工具提供了封裝過的 wxml pannel, 咱們並不能從中看到頁面完整的 dom 結構,可是用 $('*')
選擇器咱們能夠看到頁面的 appservice 模板,看這段代碼咱們能夠分析出小程序是如何使用 wxml, wxss, js 將頁面生成出來的。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline' 'unsafe-eval'">
<link href="https://res.wx.qq.com/mpres/htmledition/images/favicon218877.ico" rel="Shortcut Icon">
<script>
var __wxAppData = {}
var __wxRoute
var __wxRouteBegin
global = {}
</script>
<script></script><!-- 加載一堆script標籤 -->
</head>
<body>
<p>
開發者工具使用 nwjs 來模擬小程序的實現,幫助你們來開發和調試微信小程序,因此這裏是一個 webview,但真實
的手機端是運行在 jscore 中的,因此請不要使用任何 bom 對象。
</p>
<p>
咱們建議你先完整閱讀該開發文檔,這將有助於更快地完成開發。若是發現咱們的文檔有任何錯漏,
或者開發過程當中有任何疑問或者你有更好的建議,歡迎經過下列郵箱聯繫咱們
weixin_developer@qq.com
或者訪問微信小程序開發者社區提交問題:
https://developers.weixin.qq.com
</p>
<script>
window._____sendMsgToNW({
sdkName: 'APP_SERVICE_COMPLETE'
})
</script>
</body>
</html>複製代碼
WAService.js 是小程序頁面運行的核心方法,主要有幾大功能:
// 內置的 report 方法定義,用於內部 API 的調用日誌 & 報錯記錄等。
var Reporter = {
surroundThirdByTryCatch,
slowReport,
speedReport,
reportKeyValue,
reportIDKey,
thirdErrorReport,
errorReport,
log,
submit,
registerErrorListener,
unRegisterErrorListener,
triggerErrorMessage
}
// 微信小程序 API 封裝,全部文檔中的 [API](https://mp.weixin.qq.com/debug/wxadoc/dev/api/)都在這裏封裝了,以showModal爲例簡單分析一下
showModal: function() {
var e = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {}
, t = {
title: "",
content: "",
confirmText: "肯定",
cancelText: "取消",
showCancel: !0,
confirmColor: "#3CC51F",
cancelColor: "#000000"
};// 默認值,此處比文檔準確
if (t = (0,
f.extend)(t, e),
a("showModal", t, {// 調用 jsbridge,見下方代碼
title: "",
content: "",
confirmText: "",
cancelText: "",
confirmColor: "",
cancelColor: ""
}))
return t.confirmText.length > 4 ? void B("showModal", e, "showModal:fail confirmText length should not large then 4") : t.cancelText.length > 4 ? void B("showModal", e, "showModal:fail cancelText length should not large then 4") : void (0, // 各類校驗
u.invokeMethod)("showModal", t, {
beforeSuccess: function(e) {
e.confirm = Boolean(e.confirm)// 返回值處理
}
})
}
// 此處調用 WeixinJSBridge,此外還對每一個 API 調用記 log,方便微信小程序的問題排查
function a() {
var e = Array.prototype.slice.call(arguments)
, t = e[1];
e[1] = function(e, n) {
var o = e.data
, r = e.options
, i = arguments.length > 2 && void 0 !== arguments[2] ? arguments[2] : {}
, a = r && r.timestamp || 0
, s = Date.now();
"function" == typeof t && t(o, n),
Reporter.speedReport({
key: "webview2AppService",
data: o || {},
timeMark: {
startTime: a,
endTime: s,
nativeTime: i.nativeTime || 0
}
})
}
,
WeixinJSBridge.subscribe.apply(WeixinJSBridge, e)
}
// WeixinJSBridge 封裝,底層是調用 WeixinJSCore
e.WeixinJSBridge = {
invoke: d,
invokeCallbackHandler: p,
on: h,
publish: v,
subscribe: g,
subscribeHandler: y
}
// 內置的 jsbridge core
WeixinJSCore = {
invokeHandler,
publishHandler
}
// setData 方法定義,邏輯層經過 setData 方法改變 virtual dom,改變 dom tree,從而改變視圖層
// appServiceEngine 模塊,提供 App 和 Page 相關的接口複製代碼
若是是爲了源碼分析而進行源碼分析,我以爲大可沒必要,在小程序的場景下,源碼分析的價值在於:
本文對你有幫助?歡迎掃碼加入前端學習小組微信羣: