乐趣区

关于javascript:Taro-源码解读-tarojscli-篇

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

首先从官网拉取最新的 Taro 源码,版本号为 3.0.18,源码目录如下:

目录没什么特地的,咱们来重点关注一下 packages 目录中的外围包(如下图)

这些外围包形成了 Taro,实现了 Taro 的多平台构建。

本次解析的模块是 tarojs/cli 篇,那咱们开始吧。

taro 命令

taro 命令是 @taro/cli 的外围指令,应用 taro init 能够新建一个 taro 我的项目,这个命令的入口是 packages/taro-cli/bin/taro,代码实现如下:

从上图能够看出,入口文件创建了一个新的 Cli 实例,而后运行了 run 命令。

Kernel 内核

接下来咱们间接看看 Cli 实例(如下图)

从上图能够看出,Cli 实例的实现还是比较简单的,run 命令所做的工作就是解析命令行参数 – parseArgs

在解析入参后,会新建一个 Kernel(内核) 实例(Kernel@taro/cli 的灵魂,咱们在前面会开展解说),而后应用这个 内核 来创立我的项目(如下图)。

而第 58 行调用的 init 办法,实际上是调用了 kernel.run() 办法,所以咱们接下来看看这个办法(如下图)

kernel.init

run 办法的实现比较复杂,咱们须要进行逐行剖析,首先是第 266 行的 kernel.init() 办法(如下图)

在上图的 init 办法中,initConfig 办法初始化了我的项目配置;而 initPaths 办法初始化了一些根底的我的项目门路,比方我的项目目录(appPath),依赖目录(nodeModulesPath),我的项目配置文件(configPath)。

kernel.initPresetsAndPlugins 办法比拟要害,咱们须要认真看看代码实现(如下图)

在上图代码中:

  • 89~90 行中,收集了所有的预设和插件汇合。
  • 91 行中,为 require 办法注册了 babel,为它加上一个钩子。尔后,每当应用 require 加载.js、.jsx、.es 和.es6 后缀名的文件,就会先用 Babel 进行转码。—— Babel 入门教程
  • 97~98 行中,加载了所有的 presetsplugin,最初都以 plugin 的模式注册到 kernel.plugins 汇合中。

plugins 其实就是预设与插件的汇合,每一个 plugin 都蕴含了一个 apply 函数,执行该该函数能够导出对应的 Plugin 模块。(如下图)

初始化 Kernel 插件过程

上面咱们来看一个初始化 Kernel 插件的过程(如下图)

首先,在第 140 行代码处,初始化插件的 ctx(上下文),initPluginCtx 办法返回的是一个 Proxy 对象(如下图)

从上图能够看出,该办法创立了一个新的 Plugin 实例,而后在这个实例的根底上新建了一个 Proxy,在拜访该实例的属性时,优先返回 methods 对象中的办法,其次是改写了 this 的实例办法。

而后咱们回到下图的办法中持续解析

在上图的代码中,第 141 行,将 pluginCtx 作为入参,执行导出的插件(模块)函数。

咱们还是以微信平台举例,在微信平台中,对应的 apply 函数是这样的(如下图):

咱们上图能够看出,在 weapp 插件中导出的办法,反过来调用了 ctx.registerPlatform 办法进行平台注册,这也是设计模式中十分有名的 管制反转 Ioc 模式。

kernel.initPresetsAndPlugins

上面咱们来看看在实现 initPresetsAndPlugins 办法后,Kernel 的各个属性变成什么样了。

kernel.methods

上面展现了 methods,这些办法看起来很眼生,在扩大 Taro 插件的文档中,是一些被用来批改编译过程的 API。

咱们来看看官网文档中是如何编写一个插件的吧(如下图)

看起来是不是很像咱们下面看到的微信平台的 plugin 代码,哈哈~

kernel.hooks

接下来咱们看看 hooks(如下图)

hooks 的命令也很相熟,是咱们平时应用 taro-cli 时会应用的命令,在对应的执行命令将会调用对应的钩子。

kernel.platforms

接下来咱们看看 platforms(如下图)

platforms 中蕴含了各个平台的编译代码,用于将 ReactVue 语法转换成对应的平台语法。

kernel.commands

最初咱们来看看 commands(如下图)

从上图能够看出,commands 其实对应的就是 Taro 脚手架自带的各种命令了。

Kernel 生命周期钩子

至此,Kernel 就根本拆卸实现了,进入到 Kernel 的生命周期钩子。

Kernel 的前两个生命周期钩子是 onReadyonStart,并没有执行操作,开发者在本人编写插件时能够注册对应的钩子。

执行完下面两个钩子后,Kernel 开始执行 init 钩子(如下图)。

咱们须要逐行剖析一下上述代码:

  • 233 行:创立了一条 流水线 - AsyncSeriesWaterfallHook 工程,用于程序执行异步工作,AsyncSeriesWaterfallHook 的实现来自于 tapable 库(如下图)

  • 237 行:循环 hooks 数组,将所有的钩子注册到 waterfall 中。
  • 255 行:执行流水线工作。

通过下面的剖析,咱们对 taro-cli 的执行流程基本上就能够理解了。

init 钩子

那么上面就进入到 Kernelinit 钩子(如下图)

init 钩子最初调用了 project.create(),开始创立新我的项目。在命令行中有以下提醒(如下图):

从上图看到的欢送语其实就是代码中的 Project 实例中的 init 函数(如下图)

从上图能够看到,在第 78 行时还调用了 ask 函数,而 ask 函数对应的就是创立新我的项目时的询问选项(如下图)。

Taro 以及很多脚手架的命令行交互性能都是通过 inquirer 库实现的。

在选项确认当前,将通过 git 拉取近程模板(如下图)

而咱们在 taro 官网也能找到一个对应的模板仓库(如下图)

咱们轻易关上外面一个文件看看,例如 package.json(如下图)

从上图能够看出,在模板文件仓库的文件是 tmpl 的后缀名,而后通过相似于 ejs 的模板语法依据不同的配置项将其改写成对应的配置文件(如下图)。

从上图能够看出,最初通过 create 中的 createApp 函数,将文件写入到目录中,实现我的项目的创立。

我的项目创立实现后会主动装置依赖,而后就实现啦,init 钩子就执行完啦!

init 执行实现后,taro init 命令也就执行实现了,一个新的 Taro 我的项目创立胜利啦!

最初,咱们画一个流程图,来帮忙大家了解一下吧。

小结

到这里,@tarojs/cli 就曾经解析实现了,这部分源码的实现还是比拟精辟的,利用 Kernel + 注册插件 + 生命周期钩子函数 的实现形式,灵便的实现了各个不同的命令组合。

可能有些童鞋曾经猜到了,应用 taro 开发时的不同平台构建命令,比方微信小程序的构建命令 taro build --type weapp,也是应用 Kernel + 钩子 实现的,只不过调用的是 build 钩子和平台专属编译 Plugin,这部分代码感兴趣的童鞋能够自行浏览一下~

最初一件事

如果您曾经看到这里了,心愿您还是点个赞再走吧~

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

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

退出移动版