前言

随着 1.0 版本的发布,Rax 在小程序端的转换能力也得到了补齐。现在,你可以像过去开发 Web/Weex 端的应用一样使用 Rax 来进行小程序的开发。本系列文章将介绍 Rax 转小程序链路的实现原理。这是本系列的第一篇。

首先,我们需要对小程序(如无特别交代,文中的小程序均指支付宝小程序)的开发方式有一定的了解。你可以查看这里对整个小程序体系框架有一个大概的认知。本文假定读者已对上述内容有所了解。为了明确转换链路要做的事情,我们以最简单的情况举例:在使用 Rax 开发项目时,单个组件的内容如下所示:

// foo.js
import { createElement } from 'rax';
import View from 'rax-view';export default (props) => {return (<View>Hello World!</View>);
};

经过处理后,该组件对应的小程序代码应当包含 foo.jsfoo.axmlfoo.json 等三个同名文件(如有样式内容,还会多一个 foo.acss 文件)。其中,foo.js 会包含源文件中的业务逻辑,foo.axml 会与源文件中的 JSX 有所对应,而 foo.json 则需要包含源文件引入自定义组件(该示例中只引入了 rax-view)的声明。Rax 转小程序链路做的就是以上的转换操作。当然,这只是简单的单个组件层面的转换,项目级别的构建会有很多复杂的问题需要考虑,下面我们将解析 Rax 转小程序链路在工程上的实现原理。

概览

先看一下整体的架构图:

Rax 转小程序链路在实现上主要分为四个模块:CLI、loader、compiler 以及 runtime。CLI 即命令行工具,是整个链路的入口,用户编写的所有业务代码都经由 CLI 读取、处理和输出。loader 即 webpack loader,用于处理各种类型的文件,包括 app、page、component、script 以及静态资源等。compiler 用于进行 AST 转换并生成对应的小程序代码。最后,runtime 为生成的 js 代码提供了运行时的支持,确保其在小程序环境下能正常运行。而在更上层,我们有多端统一的 universal 组件以及 API 的基础服务支持,使得小程序的开发体验和原先的 Web/Weex 端几无区别。

本文将介绍 CLI 和 loader 两个工程模块。

CLI

把 CLI 和 loader 放在一起介绍是因为二者在功能上联系非常紧密。CLI 本身底层依赖 webpack 对项目进行依赖分析,然后调用 loader 层提供的各种 loader 对对应类型的文件进行处理。CLI 对外提供 watch 和 build 两个指令。前者用于监听代码变动并实时编译,后者相比前者会剔除部分调试用的代码(如 source map)并压缩代码,完成编译打包。

具体到实现上,CLI 本身并不复杂,用一句话概括的话就是从命令行读取各种必要参数,然后传入 webpack 执行。利用 webpack 的依赖分析能力,我们能够遍历到所有有效代码并交由对应的 loader 进行处理。这里可能会有同学提出疑问,入口文件是什么样的,它又是如何声明依赖的?因为在小程序原生开发框架中,入口文件 app.js 并没有声明依赖,而 pages 是在 app.json 中注册的。下面就需要先介绍一下 Rax 小程序的工程目录。

为了保持多端统一,Rax 采用同一套工程目录,当我们使用 rax-scripts 创建一个小程序项目时,其目录结构如下所示:

.
├── README.md                   # 项目说明
├── build.json                  # 项目构建配置
├── package.json
└── src                         # 源码目录├── app.js                  # 应用入口文件├── app.json                # 应用配置,包括路由配置,小程序 window 配置等├── components              # 应用的公共组件│   └── Logo                # 组件│       ├── index.css       # Logo 组件的样式文件│       └── index.jsx       # Logo 组件 JSX 源码├── document                # 页面的 HTML 模板│   └── index.jsx       └── pages                   # 页面└── Home                # home 页面└── index.jsx

app.json 中包含路由配置。其默认内容如下:

{"routes": [{"path": "/","source": "pages/Home/index"}],"window": {"defaultTitle": "Rax App 1.0"}
}

CLI 将读取其中的 routes 内容并将所有引用到的 pages 文件以及 app.js 作为 entry,类似于多页应用程序的配置。至此,以 pages 文件为入口,所有依赖文件将依次被遍历并交由对应 loader 进行处理。loader 处理完毕后最终的编译代码将生成到目的目录,而 webpack 默认生成的 bundle 对我们来说并不需要,我们将 outputFileSystem 设置为内存文件系统使其不产出至磁盘上即可。

loader

jsx2mp-loader 中一共存在以下五个角色的 loader,分别用来处理对应类型的文件。下面将分别介绍其功能。

app && page && component loader

一句话概括三种 loader 的主要功能就是读取对应类型的文件内容(app-loader 处理 Rax 源码中的 app.js,page-loader 处理定义在 app.json 中 routes 属性内的 page 类型组件,component-loader 处理 component 类型组件)并交由 jsx-compiler 处理然后产出编译后代码,并写入至指定目标文件夹位置。除此之外,每个loader 还有一些自己特定的职责:

  • app-loader

    • 处理 app.json 中 的 `window` 属性并作支付宝/微信两端的配置抹平
  • page-loader
    • 根据 jsx-compiler 中解析到的该组件所引用组件的信息,写入 json 文件的 usingComponents 属性中,并将这些组件加入 webpack 依赖分析链并交由 component-loader 处理
    • 处理用户定义在 app.json 中 routes 数组内每一个页面的配置(即 window 配置项)并输出至对应页面的 json 文件中
  • component-loader
    • 根据 jsx-compiler 中解析到的该组件所引用组件的信息,写入 json 文件的 usingComponents 属性中,并将这些组件加入 webpack 依赖分析链并交由 component-loader 处理

file loader

处理图片等静态文件资源,将其拷贝至指定目标文件夹。

script loader

所有 loader 中任务最繁重的非 script-loader 莫属。script-loader 负责处理所有 js 文件。而对于 js 文件,有一个非常重要的需要考虑的问题就是依赖路径处理。在 Rax 转小程序链路中,我们默认采用将 node_module 中使用到的文件提取并拷贝至目标文件夹,这样做的原因基于以下两点:

  1. 微信小程序项目不支持直接使用 npm 包(在我们设计方案时微信尚不支持,但是目前已经通过在 IDE 中点击『构建 npm』功能来使用 npm 包,其原理也是通过拷贝提取 npm 包文件至其指定的 miniprogram_npm 目录)
  2. 支付宝小程序虽然支持使用 npm 包,但是如果该 npm 包没有按照标准发布 ES5 语法的文件,则无法正常使用。支付宝小程序默认不会编译 node_modules 中的文件,理由是会拖慢编译速度(不过在最新版本中,支付宝已经支持对 npm 包作最基本的 ES6 转 ES5 的处理)

所以,依赖路径处理是 script-loader 最核心的功能之一,其基本工作流程是:搜集代码中使用到的 npm 依赖,获取 npm 包的真实地址 => 路径处理 => babel 编译 => 输出代码至目标文件夹。

在 Rax 小程序项目中,对于来自 npm 包的纯 js 文件(比如 loadsh)或者用户自己编写的本地 js 文件(比如 utils 文件),执行以上流程即可。对于以下两种类型,除上述基本流程外,script-loader 还需要一些额外操作:

来自 npm 包的第三方原生小程序库

用户使用绝对路径去使用第三方原生小程序库时,script-loader 需要读取 js 文件同目录下同名的 json 文件中的 usingComponents 字段并将其加入 webpack 的依赖分析链

来自 npm 包的依据多态组件(库)协议开发并发布的小程序组件(库)

关于多态组件(库)协议可以点击这里查看官网文档。 Rax 基础组件均基于该协议支持小程序端。实际上,通过使用绝对路径引入原生小程序组件使用完全可以满足需求,但是 Rax 定位于多端统一开发框架,这样做会使开发小程序端时产生平台特定的代码,无法真正做到一套代码多端运行,因此我们设计了多态组件(库)协议。用户在小程序端引入组件时可以正常如 Web/Weex 端一样边写代码如 import View from 'rax-view',但实际上由 script-loader 去读取 package.json 中 miniappConfig 字段的值以获取真实使用的原生小程序组件地址。基于多态组件(库)协议,用户可以方便地进行 Rax 小程序组件的构建与发布,然后在 Rax 项目中引入使用。

总结

本文阐述了 jsx2mp-cli 与 jsx2mp-loader 的基本原理,也梳理了 Rax 转小程序链路工程上的整体脉络。关于 jsx-compiler 怎么处理编译以及 jsx2mp-runtime 是如何作了运行时的支撑并抹平了原生小程序组件实例与 Rax 实例的差异,敬请期待后面的文章。

其它

  • Rax 开源仓库
  • 往期文章
  • 钉钉交流群
  • Rax 微信交流群
  • Rax 小程序外部用户答疑群

项目解析jsx文件_Rax 转小程序链路原理解析(一)相关推荐

  1. vue项目实战-4.前端渲染.微信小程序

    设置整个页面结构 1.由于是手机端项目,所以需要加上手机端相关处理,修改index.html代码,增加meta处理 <meta name="viewport" content ...

  2. 微信小程序富文本解析点击图片放大_微信小程序解析富文本过程详解

    前言 最近公司在开发OTA微信小程序,一些页面的详情内容是HTML富文本格式的的,但是微信小程序不能直接解析HTML,需要将内容中的HTML标签转换成微信小程序所支持的标签. 开始的时候想过自己写方法 ...

  3. 通过调试微信小程序示例代码解析flex布局参数功能(一)

    通过调试微信小程序示例代码解析flex布局参数功能 官方示例小程序源代码下载地址:https://github.com/wechat-miniprogram/miniprogram-demo 通过调试 ...

  4. 限时团购,6.9折:《微信开发深度解析:公众号、小程序高效开发秘籍》推荐序

    全书由目 Senparc.Weixin SDK 作者苏震巍历时 2 年完成,涵盖了开发微信公众号及小程序需要用的的各项后端开发技能.技巧.避坑提示,以及 Senparc.Weixin SDK 微信公众 ...

  5. 微信小程序使用towxml解析md/html

    Towxml Towxml github地址 注意 最新测试生成的是dist文件,然后直接引入会出现错误.需要更改一下文件. 介绍 Towxml 是一个可将HTML.Markdown转为微信小程序WX ...

  6. 微信小程序富文本解析

    微信小程序富文本解析 *人狠话不多,直接代码搞起* html代码(后台返回的html代码) <p>这是一段文字</p><p><strong>这是加粗的字 ...

  7. H5练手项目-写一个菜鸟裹裹小程序

    新手写小程序并不简单,菜鸟裹裹查看快递是很方便的,平常自己查看快递的时候都是在用.当我在微信端搜索菜鸟裹裹小程序时,却没有发现,于是便想自己动手仿app版写一个菜鸟裹裹的小程序,对其中的快递查询物流跟 ...

  8. 【微信小程序】无法解析京东商城商品详情富文本数据

    小程序的rich-text富文本标签不支持link标签,这就导致我们从京东商城拿到的商品详情富文本无法解析. rich-text组件用法 小程序商城对接京东商城商品,拿到的京东商品详情的富文本数据格式 ...

  9. c vscode 高亮_vscode怎么高亮打开wpy文件开发微信小程序

    原本想用mpvue来开发小程序的,后面决定使用wepy来开发,踩坑开始,哈哈. 安装使用 安装(更新) wepy 命令行工具. npm install wepy-cli -g 生成开发示例 wepy ...

最新文章

  1. docker 异常:“fork/exec /proc/self/exe: no such file”
  2. 利用pyinstaller打包Python程序为一个可执行文件
  3. C++实现归并排序(附完整源码)
  4. 下拉多选择框 实现方式_物体检测之旅(三)|设计选择,经验教训和物体检测的趋势...
  5. 阿捷外传之Git代码统计:DotNetCore + PowerBI 实现Git仓库日志分析
  6. #3551. [ONTAK2010]Peaks加强版(kruskal 重构树 + 主席树)
  7. python能和wincc一起用_搬家第二天-41.Wincc V7.3 利用Inputbox和Msgbox做权限管理和二次确认设计...
  8. 反射的妙用-类名方法名做参数进行方法调用实例demo
  9. Android 系统(255)---dump解码所得图片方法
  10. MTK 驱动(4)---MTK Android Driver知识大全
  11. 剑指Offer之从上往下打印二叉树
  12. VB中的New 与 CreateObject的区别
  13. 随机数生成--可复现--可重复:random_state
  14. Webpack配置问题
  15. 高性能的MySQL(8)优化服务器配置一安全与稳定
  16. ESXi主机性能问题
  17. Install deepin-wine QQ inside a docker image in Ubuntu 20.04
  18. 64 ---- 平面与直线的位置关系
  19. Raptor制作猜数游戏流程图
  20. 一本书读懂大数据 读书笔记(1)

热门文章

  1. 《吉佳公众健康管理平台》解决方案
  2. 为什么金融AI要做猪脸识别?
  3. mysql字符串包含insert_字符串中包含关键字,insert into不成功
  4. cront计划任务的详细讲解
  5. 华侨大学计算机本科导师,华侨大学计算机科学与技术学院导师简介:彭淑娟
  6. FTP主动模式和被动模式
  7. 程序员必备书籍(改天买去)
  8. python单位转换编程英寸厘米_Python字节单位转换实例
  9. 安装操作系统前须知知识(理论)
  10. wget无法建立SSL连接