Taro 源码解读 - miniRunner 篇

1,574 阅读6分钟

因为近期使用到 Taro 编写小程序,出于好奇,准备研读一下 Taro 的源码。

在上一篇文章 Taro 源码解读 - taro build 篇 中,已经讲解了 taro-cli 的实现原理,然后以 taro build 为案例解释了核心 Kernel + 钩子的运行机制,以及最终到达 webpack 构建阶段。

本篇文章将会是对 taro build 篇的一个补充,着重介绍运行 taro build 后,最终 webpack 实现的打包机制,以及简单介绍一下 Taro Next 从编译时到运行时的转变。

话不多说,我们开始吧。

miniRunner 概览

miniRunner 其实是一个函数,我们先来整体看看 miniRunner 所做的事情吧(如下图)

image

我们来逐行解析一下代码实现:

代码行数解释
21定义构建 mode,也就是 `"production""development""none"`
24完善构建配置,这里主要是完善一些 sass loader 的配置
27~37根据项目配置生成 webpack 的构建配置
39~80使用 webpack 进行代码编译

从上面的分析可以看出,miniRunner 主要做的工作就是根据项目配置组装 webpack 配置,然后根据 webpack 配置生成编译后的代码。

接下来,我们重点关注项目自带的 webpackChain 配置(第 27 行),看看默认的配置是什么样的吧~

默认配置

这里我们以 taro build --type weapp 命令为例,将 react 技术栈的代码编译到微信小程序平台。

我们先来看看默认配置(如下图)

image

我们从上面的配置中可以看到 framework(框架)是 reactplatform(目标平台)是 weapp(微信)。下面我们来看看这份配置生成的 webpackChain,也就是 miniRunner 中的第 27 行代码(如下图)

image

接下来的解析也是对 webpack 配置的解析科普,可能会比较枯燥,大家耐心看完就知道内部编译所做的事情了。

基础配置

我们先找到 buildConf 函数(如下图)

image

从上图的第 27 行中可以看出,内部使用 getBaseConf 来获取一个初始设置(如下图)

image

下面我们来逐行解析一下基础配置项,如下:

  • 9 行:源文件使用的扩展名,这里包括 '.js', '.jsx', '.ts', '.tsx', '.mjs', '.vue',值得注意的是,mjs 指的是 JavaScript modules 模块
  • 10 行:指定导入模块时使用 package.json 中的哪个字段,这里的配置将优先使用 browser 属性解析文件,其次是 module,最后是 main
  • 11 行:符号链接(symlink)解析到它们的符号链接位置(symlink location)。相关资料可以参考 当 webpack 遇上 symlink
  • 12~15 行:告诉 webpack 解析模块时应该搜索的目录,这里对应的就是 node_modules 目录。
  • 16~21 行:这里是一些运行时的模块,将其指向本地 node_modules 顶层,以保证状态一致。
  • 23~27 行:解析 webpack loader 包,指定 node_modules 目录。
  • 28~30 行:代码包是包含副作用的,不希望被 tree shaking 优化。
  • 33~35 行:添加 taro 自带的 MultiPlatformPlugin 插件,这个我们在后面在展开介绍。

构建项配置

在梳理完了基础配置后,我们来继续探究 buildConf 函数(如下图)。

image

从上图可以看出,第 98~100 行时,将 copy 属性解析为 copy-webpack-plugin 插件,加入到 webpack 中(如下图)

image

接下来几行代码则展示了一些从 React微信小程序 中间的玄妙之处。(如下图)

image

从第 103 行可以看出,如果 frameworkreactminiRunner 内部则会将 react-dom 指向 @tarojs/react

react 体系中,react 库实现了 ReactComponentReactElement 的核心部分,而 react-dom 库负责通过操作 DOM 来实现 react 在浏览器中的渲染更新操作。在小程序中,并不能直接操作 DOM 树或者说没有传统的 DOM 树,此时直接使用 react-dom 则会导致报错。所以,taro 实现了一套在小程序上的 仿 react-dom 运行时,以保证 React 可以正常在小程序端渲染、更新节点。

我们也可以这么理解,react-dom 是浏览器端的 renderreact-native 是原生 APP 的 render,而 @tarojs/react 是小程序上的 render

我们接着往下看(如下图)

image

在第 119 行中,将一些常量进行收集,后续用 definePlugin 进行处理(如下图)

image

我们接着往下看(如下图)

image

在第 120~133 行中,主要是根据 isBuildPlugin 变量(是否为打包插件)来确定 entryRes(入口资源)、defaultCommonChunks(默认的 chunk)。

接下来,miniRunner 注册了一系列的插件(如下图)

image

此时注册的插件包括:

代码行数解释
134定义 definePlugin 插件,用于定义一些全局变量
135定义 TaroMiniPlugin 插件,该插件主要负责将 framework 源文件转换为 platform 平台代码
157定义 MiniCssExtractPlugin 插件,该插件主要负责将所有的 css 文件提取到一个文件中
39~80定义 ProvidePlugin 插件,该插件负责了一个核心功能,就是将运行时环境从浏览器环境切换到 taro 的运行时环境,比如将 window 替换成 @tarojs/runtime 中导出的 window

TaroMiniPlugin@tarojs/runtime 大家先做个笔记,我们后面还要再展开解析。

我们先接着往下看。(如下图)

image

在第 173~186 行中,主要是配置 jscss 文件的压缩插件(如下图)

image

image

在接下来,webpackChain 又合并了一系列的基础参数(如下图)

image

我们来进行逐行解析:

  • 189 行:提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。
  • 190 行:控制是否生成 source-map
  • 191 行:入口文件,也就是 app.js
  • 192 行:定义代码编译后的生产目录。
  • 200 行:指定目标(target)环境。
  • 203 行:合并 alias 别名选项。
  • 204 行:配置 module,这里主要是配置一些不同的 loader
  • 226 行:配置 plugin 插件。
  • 227 行:手动配置了一些编译选项优化。

在合并完了一系列参数配置后,buildConf 最后进行了 vue 的兼容处理,最后将 chain 返回。(如下图)

image

配置项概览

在了解完了内部的 webpackChain(buildConf) 组成后,我们来继续回到 miniRunner 中来看代码(如下图)

image

在上图第 30 行中,miniRunner 将内部 webpackChain 和开发者设置的 webpackChain 相结合,得到最终的 webpackChain(如下图)。

image

我们来看看由这份 webpackChain 最终生成的 webpack 配置长什么样子吧~(如下图)

image

配置很长,我们还是需要关注两个比较重要的部分

一是 taro 内部插件 - TaroMiniPlugin(如下图)

image

二是 taro 内部 loader - miniTemplateLoader(如下图)

image

可以说,只要搞懂了 TaroMiniPluginminiTemplateLoader,就能搞懂从 React 到小程序的流程。

小结

TaroMiniPluginminiTemplateLoader 部分的内容比较复杂,我们会在后面单独开设两个章节进行讲解。

那么,本次对 miniRunner 的梳理到这里就算完成啦。

最后我们画一个流程图来帮助大家理解(如下图)

image

最后一件事

如果您已经看到这里了,希望您还是点个赞再走吧~

您的点赞是对作者的最大鼓励,也可以让更多人看到本篇文章!

如果觉得本文对您有帮助,请帮忙在 github 上点亮 star 鼓励一下吧!