Rax 编译型小程序构建方案源码分析

751 阅读3分钟

Rax 是阿里的跨端解决方案,由于涉及多个端,miniapp 更是经历了编译型到运行时的转变,所以仓库有很多个,找起来比较麻烦,但是 miniapp 相关的都集中在 raxjs/miniapp 仓库里,涉及编译型的主要有:

  1. jsx2mp-cli:编译型小程序最底层的 cli 工具,主要获取 webpack 配置
  2. jsx-compiler:将 Rax 组件的内容编译成小程序的 4 个文件的内容
  3. jsx2mp-loader:使用 jsx-compiler 处理 Rax 组件,然后生成文件
  4. jsx2mp-runtime:编译后小程序所需要的 runtime 搭一个最简单的 demo,app.json 用来声明小程序的一些配置,同时告诉 jsx2mp-cli 小程序的 pages 的路径,用来生成 webpack 配置的 entry

bceb7dc2-2871-42ad-9c24-2ac60024c76e.png

生成的产物并不像一般 webpack 打包过后的产物,也没有 __webpack_require__ 等 webpack 运行时的代码,非常干净,目录结构也和之前一样,只不过是把原来的 Rax 组件生成小程序的 4 个文件,node_modules 依赖也都放到了生成的 npm 文件夹里

af60a359-1905-4f01-8648-4b594b6774d2.png

运行 jsx2mp start 命令,得到的 webpack 配置如下,entry 这里通过 url 来添加 appLoader 和 pageLoader,js 和 ts 文件通过 scriptLoader 处理,其他静态资源文件通过 fileLoader 处理。在通过配置得到 webpack compiler 之后,会把 outputFileSystem 设置成 memfs,让 webpack 的产物不会生成到 dist 中

13dc4a16-7f5f-4cb2-9c80-6cef96b9e964.png

首先看 scriptLoader,如果 this.loaders 里有 appLoader、pageLoader、componentLoader 其中一个,就说明不是一个普通的 js 文件,直接 return 给对应 loader 处理。如果没有就说明是一个普通的 js 文件,或者是一个外部的小程序组件包,外部小程序组件包的处理跟 componentLoader 类似,这里略过;普通 js 文件就调用 output 写到 dist 中,output 会根据是不是 node_modules 里的文件判断是否生成到 npm 文件夹中,生成后 loader return content 直接把传入的 content 原封不动的传出

appLoader、pageLoader 和 componentLoader 作用大同小异,都是调用 jsx-compiler 得到小程序的内容,然后在 loader 里调用 output 把 4 个文件生成到 dist 中,最后 loader return 的内容只是一串 import,import 的 url 就是该文件所有的依赖,再根据依赖的类型在 url 上写好对应的 loader,由于 outputFileSystem 用的 memfs,而且文件通过 output 直接写到 dist 里,所以 return 的作用只是告诉 webpack 文件的依赖,继续使用 loader 处理依赖,以此递归,直到所有需要的文件都经过处理 output 到 dist 中

fileLoader 直接把静态资源 copy 到 dist 中

上面配置中还有一个 JSX2MPRuntimePlugin,是在 emit 钩子上获取对应小程序平台的 runtime 文件,然后 copy 到 dist/npm 中,而原来文件中引用的 rax-app 也通过 jsx-compiler 在编译过程中替换为 runtime 的相对路径

经过 jsx-compiler 编译后的 js 文件如下,通过 runtime 中的 createPage 创建真正的 page 对象,createPage 可以说是对原生小程序的一个增强,这样就可以在组件里使用 hooks(实现跟 Preact 中 hooks 类似),jsx 部分编译成了 this._update... 这样组件每次渲染就会调用 hooks 得到状态并运行 sideEffects,最后 this._update... 调用 this.setData 进行更新

8fcc8bb7-9a2c-4fa8-b89b-97377f1205eb.png

taro2 的方式是:编译 -> 打包 -> 生成,Rax 编译型的构建通过 loader 直接 output 吐文件,与 taro2 构建不同在于少了打包这一步,只做了必须要做的事,而其他的可以交给原生小程序的打包工具进行打包和做一些优化