「大众点评点餐」小程序开发经验 05:解析开发工具

爱范儿  •  扫码分享

文 | 周中坚

作者介绍:周中坚,美团点评工程师,4年 Web 前端开发经验,主要负责过会员卡、外卖、预订、商家平台等业务的前端开发,现在是美团点评点餐团队的一员。

知晓程序(微信号 zxcx0101)已经为大家带来 4 篇来自大众点评的小程序开发文章,相信大家看了这些文章、再结合官方文档已经可以毫无压力地开发小程序了。

关注知晓程序(微信号 zxcx0101),回复「 点评 」,获取该系列所有文章。

但是为什么有这些坑,是不是可以绕过去,怎么排查问题, 我们还想从源头——小程序的源码的角度来尝试分析 ,因此有了这篇源码解析。

代码结构

以 macOS 系统为例,首先进入应用程序文件夹,再右键微信开发者工具显示包内容,最后让我们进入 ./Contents/Resources/app.nw 目录。

接下来,我们就可以查看小程序的源码了。代码结构如图:

「大众点评点餐」小程序开发经验 05:解析开发工具

文件夹看起来很多,但命名还算清晰。现在,让我们从开发者工具入手,来看下都用到了哪些文件吧。

开发者工具

首页

「大众点评点餐」小程序开发经验 05:解析开发工具

这个页面里的很多信息,可以和这个项目中的  package.json  对应起来,比如 name、icon、version 等。

代理

「大众点评点餐」小程序开发经验 05:解析开发工具

代理的设置在 ./app/dist/components/setting/setting.js ,而用户设置的保存(包括后面要说的模拟器设备、网络等信息)是调用了  ./app/dist/stores/*.js  方法。

菜单

「大众点评点餐」小程序开发经验 05:解析开发工具

上图可以看到我对菜单做的一些定制。

菜单的设置在  ./app/dist/common/menu/menu.js ,动作在  ./app/dist/common/actions/actions.js ,大家可以自行到代码中查看文件的  require  进一步分析。

设备及网络

「大众点评点餐」小程序开发经验 05:解析开发工具

上图可以看到我自己添加了一个设备以及一个网络类型。

模拟器的设备配置在  ./app/dist/config/DeviceModules.js ,网络配置在  ./app/dist/common/jssdk/osInfoSdk.js

调试工具

「大众点评点餐」小程序开发经验 05:解析开发工具

调试工具是这一节最核心的内容了。乍一看,微信的调试工具和 Chrome 的 DevTools 长的很像。查查源代码,果然就是借助它实现的。

「大众点评点餐」小程序开发经验 05:解析开发工具

其中 Console、Sources、Network 就是直接使用的 DevTools,而 Storage、AppData、Wxml、Sensor,都是微信自己实现的。

参照这些调试工具,我们自己弄一个自己的调试工具就很简单了。

只要在 ./app/dist/extensions 目录下新建一个文件夹,用
html/css/js 完成这个工具的功能,再将 devtools.html 这个工具引入
chrome.devtools.panels.create()

「大众点评点餐」小程序开发经验 05:解析开发工具

有趣的是,在  0.15.150201  这个测试版中已经发现了一个名为 Bluetooth 的开发工具。

「大众点评点餐」小程序开发经验 05:解析开发工具

(知晓程序注:最新版微信,已支持小程序蓝牙接口。)

WeApp

上面一节主要讲的是小程序开发者工具的源码。我们借助分析源码可以搞清楚代理是怎么设置的,模拟器的设备和网络如何添加,怎样开发一个满足自己特定需求的 DevTool。

这一节主要介绍, 我们写的微信小程序的代码是如何变成页面,在用户的终端运行的

  • tpl 文件夹下是页面模板。
  • onlinevendor/wcc 在编译时把 WXML 文件转为 JS 文件, onlinevendor/wcsc 在编译时把 wxss 文件转化为 js,这也是编译包比代码库要大不少的重要原因。
  • trans 文件夹下有五个方法,其中 transConfigToPf 可以将配置转成 pageFrametrans/transWxmlToHtml 将 WXML 转成 DOM 树,再进一步用 WebView 渲染, trans/transWxssToCss 将 WXSS 转成 CSS,提供 View 层样式。
  • onlinevendor/WAService.js 提供了service 层几乎一切功能。

pageFrame

首先是看一下刚才提到的 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>
				
			

AppService 页面模板

开发者工具提供了封装过的 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

WAService.js 是小程序页面运行的核心方法,主要有几大功能:

  • 内置的 report 方法定义
  • 微信小程序 API 封装
  • WeixinJSBridge 封装
  • appServiceEngine 模块
				
					// 内置的 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 相关的接口
				
			

总结

如果是为了源码分析而进行源码分析,我觉得大可不必。在小程序的场景下,源码分析的价值在于:

  • 官方文档不一定和实际情况是对齐的,开发时碰到不一致的情况可以查阅源码,以此为准。
  • 熟悉源码结构可以快速定位问题,提升开发效率,甚至给自己开发合适的 DevTool。
  • 小程序可以认为是前端的一个子集,而且相对封闭,开发时会有各种约束,查阅源码可以有助于小程序的设计。

本文由知晓程序授权转载,关注微信号 zxcx0101,在微信后台回复「 点评 」,获取大众点评小程序开发系列文章。


随意打赏

大众点评点餐小程序大众点评小程序大众点评点餐程序开发经验小程序 点餐大众点评外卖大众点评商家大众点餐
提交建议
微信扫一扫,分享给好友吧。