【小程序 - 大智慧】深入微信小程序的核心原理

小程序 0

5.png


目录

  • 课程目标
  • 背景
  • 双线程架构
  • WebView 结构
  • 快速渲染 PageFrame
  • 编译原理
  • Exparser
  • 通讯系统
  • 生命周期
  • 基础库解包
  • 跨端框架
    • 预编译
    • 半编译半运行
    • 运行时框架
  • 主流技术
    • Taro
    • uni-app
    • 汇总
  • 下周安排


课程目标

本次课程主要通过后台管理小程序回顾一下小程序的高阶语法,然后讲解整体小程序流程原理:

  • 前端相关的编码规范、设计规范
  • 页面切换、生命周期、数据通信等基础知识
  • 双线程架构、webview 渲染、PageFrame 模板、通讯系统、生命周期、跨端框架等
  • 掘金小册推荐 https://juejin.cn/book/6982013809212784676

背景

进程:操作系统进行进行资源分配和调度的基本单位

线程:操作系统能够进行运算调度的最小单位,其是进程中的一个执行任务(控制单元),负责当前进程中程序的执行

  1. 微信开发者工具底层是 Chrome XWeb 内核,进行开发跨平台的桌面应用(如QQ、WeChat客户端)。
  2. 左上角选择,微信开发者工具 -> 调试 -> 调试微信开发者工具,和谷歌调试界面几乎一模一样(利用这个工具,我们后续可以处理一些内部报错的调试BUG)。
  3. 接下来,我们利用脚本遍历开发工具的 webview 元素。
// 获取所有的 webviewdocument.getElementsByTagName('webview')// 打开调试的 webviewdocument.getElementsByTagName('webview')[0].showDevTools(true, null)
  1. webview 的含义如下:当前小程序的页面 两个渲染层 逻辑层 调试器
  2. 新开一个页面就会新增一个 webview,微信限制最多10个以保证性能问题的底层原因
  3. 利用命令打开一个 webview 页面进行具体的调试
  4. 页面的样式、调试库、渲染库、开发工具的配置…
  5. body 下面的标签就是利用 小程序开发的 Exparser 框架将 dom 转换为自定义组件的一套规则
  6. 每个 webview 都加载了这么多文件,是如何保证高效运作的?

快速渲染 PageFrame

  1. 利用 page frame 模板生成 webview 视图。
  2. 基本的 webview 模板和之前打开的一致,但是包含一些注释占位符,后续会被编译为具体的执行 js 文件。

加载流程如下:

  1. 首页启动时,即第一次通过 pageframe.html 生成内容后,后台服务会缓存 pageframe.html 模板首次生成的html内容。
    1. 非首次新打开页面时,页面请求的 pageframe.html 内容直接走后台缓存。
    2. 非首次新打开页面时,pageframe.html 页面引入的外链js资源(如上图所示)走本地缓存。
  2. 生成 webview 模板后,初始化 webview 地址 http://127.0.0.1:${global.proxyPort}/aboutblank?${c} 空地址,其中 ${c} 为对应 webview 的 id。
  3. 监听页面的 ready 操作,注入执行代码脚本生成最终的 webview 地址和执行代码。

编译原理

基础语法不作过多赘述,主要编译原理和rpx动态适配。WXSS/WXML并不可以直接执行在webview层进行渲染,通过wcsc/wcc执行脚本编译为js文件,然后注入webview中,这里可以演示一下。

// help() 查看编译命令help()// 编译 WXSS 命令./wcsc -js index.wxss >> style.js  // 编译 WXML 命令./wcc -js index.wxml >> test.js// 执行 $gwx 文件var decodeName = decodeURI("./pages/home-tab/index.wxml")var generateFunc = $gwx(decodeName)generateFunc()
var eps = 1e-4var transformRPX =  window.__transformRpx__ ||  function (number, newDeviceWidth) {    if (number === 0) return 0    number = (number / BASE_DEVICE_WIDTH) * (newDeviceWidth || deviceWidth)    number = Math.floor(number + eps)    if (number === 0) {      if (deviceDPR === 1 || !isIOS) {        return 1      } else {        return 0.5      }    }    return number  }
  1. wcsc 将 WXSS 编译为 JS 文件。

  2. JS 文件注入到 WebView 中。

  3. 逻辑层执行 JS 文件,主要是设备信息获取(宽度、高度、横屏)、特定规则 rpx 适配为 px,写入编译后的 CSS 文件到 head style 头部。

  4. WCC 将 WXML 编译为 JS 文件。

  5. 但是文件作了压缩混淆,本质逻辑执行 $gwx 函数。

  6. generateFunc 就是接受动态数据,并生成虚拟 DOM 树的函数,DOM 树已存在的数据直接渲染为 wx-view/wx-text,需要 JS 脚本异步获取的数据采取 tag: virtual 虚拟 DOM 元素进行占位,等到获取后端数据之后直接填充 => 真实 DOM。

Exparser

WebComponents Shadow Dom

Exparser是微信小程序的组件组织框架,内置在小程序基础库中,为小程序提供各种各样的组件支撑。内置组件和自定义组件都有Exparser组织管理。

这部分后面单独抽离一篇文章进行讲解…

通讯系统

在正式讲解小程序的通讯系统前,先来熟悉一下小程序的 发布 - 订阅模式

美团一面:你了解发布-订阅模式吗?「每天搞透一道JS手写题💪Day8」 - 掘金

概述:引入中间平台进行注册和通知,有效解决了观察者维护列表导致的解耦不彻底问题

观察者通过 onEventBus 注册事件,然后 Subject 通过 emitEventBus 发射事件,由 EventBus 来向观察者更新。本质上是维护一个 events 对象,通过事件名注入到 events,每个 事件名 里面都有相应的回调函数,发布之后会分发到相应事件 回调函数 的方法。

class PubSub {  constructor() {    this.events = {};  }  subscribe(event, callback) {    if (typeof event !== 'string') {      throw new Error('Event name must be a string');    }    if (typeof callback !== 'function') {      throw new Error('Callback must be a function');    }    if (!this.events[event]) {      this.events[event] = [];    }    this.events[event].push(callback);  }  unsubscribe(event, callback) {    if (typeof event !== 'string') {      throw new Error('Event name must be a string');    }    if (typeof callback !== 'function') {      throw new Error('Callback must be a function');    }    if (!this.events[event]) return;    this.events[event] = this.events[event].filter(cb => cb !== callback);  }  publish(event, data) {    if (typeof event !== 'string') {      throw new Error('Event name must be a string');    }    if (!this.events[event]) return;    this.events[event].forEach(callback => callback(data));  }}

微信开发者工具里面选择的基础库为微信中的基础库版本(后面标识了兼容性和用户的数量),可用于微信开发者工具内的调试。每个版本的微信客户端都会自带一个版本的小程序基础库,而不是微信客户端带着所有版本的基础库,所以开发时选择的版本尽量和客户端的一致(最新的为好),避免 API 兼容性问题。

接下来,我们利用 openVendor() 找到 基础库进行解析,找到原始的 wxvpkg 然后利用 Github 工具进行反编译出源码,https://github.com/csj5588/wxappUnpacker

构建后的结果在 dist 文件下,本质上还是渲染层和逻辑层两个线程脚本之间的交互流程,后续在深入探讨。

跨端框架

由于小程序语法较为原始,工程化工具不支持,市面上太多平台的小程序需要适配开发,基于此市面上的第三方框架也慢慢进入大众的视野,目前来说流行的就是 taro 和 uni-app。

下面先来介绍下框架的分类:

预编译

画板

本质上是利用 DSL(语法规则) + 语法解析,将一些逻辑转换为小程序支持的语法,但是这样存在一些问题:

  • 如果React或者Vue后期再出一些新特性的话,预编译框架都需要进行语法解析扩展编写。
  • 兼容问题,比如小程序不支持的一些属性,如果不支持,预编译框架要进行兼容。

半编译半运行

Taro 介绍 | Taro 文档

Taro 特点总结

  • 采用 TypeScript (TS) 加上部分 Rust 进行开发
  • 底层标准参考 微信小程序,兼容性较好,其他平台的兼容性未知
  • ReactWebpack 语法有良好的兼容性支持,Vue 3 加上 Vite 新推出,也可以用
  • 调试开发需要下载不同平台的工具,无法直接导出运行
  • GitHub 上搜索近两年 stars 30+ 的开源项目,资源只有一页,显示资源较少
  • 不支持使用 Vue 3scoped CSS 样式隔离语法,这可能需要更详细的介绍

资源链接

Taro UI | O2Team

NutUI - 移动端组件库

组件库选择建议

  • Taro 组件库:由 Taro 维护,但不推荐安装
  • NutUI 组件库:多端组件库分离,推荐作为开发的首选

uni-app

uni-app官网
相关资源链接

  • uview-plus 3.0 - 全面兼容nvue的uni-app生态框架 - uni-app UI框架
  • GitHub - Moonofweisheng/wot-design-uni: 一个基于Vue3+TS开发的uni-app组件库,提供70+高质量组件,支持暗黑模式、国际化和自定义主题。
  • 页面 | uni-app官网

uni-app 特点总结

本质上有两种体系:

  • 一种是 uniapp + HBuilder 工具构建的一套自己的规范,其中包含:uts(TypeScript 超集)、uni-modules (依赖管理)、uvue(编译语言)、uniCloud(云服务),最终这些被 uni-app x 统一集成,需要重新学习一套标准、时间成本和难度过高,编辑器也不如前端常用的编辑器 VSCode、WebStorm
  • 另一种可以借助原本的命令行执行,和其他的前端项目一致,可以借助第三方优质模板,但是注意 app 部分打包仍然需要 HBuilder 开发工具(推荐)

汇总

维度Taro得分Uni-app得分
社区文档清晰明确8较为混乱、自有体系和前端不兼容6
上手成本VUE 版本上手容易、React 较高8底层采用 VUE 开发,熟悉程度更高9
开源项目 pushed:>2023-09-01 stars:>3068714310
Github 活跃stars:35.3k+ issues:1.2k + 1w+10stars:39.9k+ issues:0.9k + 3k+8
三方组件库官方组件库统一,资源优质 NutUI VUE 6k+9官方组件库较为简陋、社区UI生态较差、大部分收费、一部分不敢用5
TS 支持兼容性优秀9兼容性优秀8
VUE 语法兼容兼容大部分 VUE 语法7兼容大部分 VUE 语法8
React 语法兼容支持0不支持0
总计🥇🏅🎖️5854

跨端开发框架深度横评

下周安排

开源商城项目拆解

  • 腾讯有数
  • gz-yami - Overview
  • EastWorld

也许您对下面的内容还感兴趣: