Taro的CLI
一、CLI
的入口
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/fb9d8ca8-4898-47f6-b4ea-b994569bad6e/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=d0d2afc12a8be7bccb3fb77bc754d10176004bfdda75906aaa445d3080ddb7e3&X-Amz-SignedHeaders=host&x-id=GetObject)
首先,在package.json
里面定义了taro
命令和对应的可执行文件,然后我们看可执行文件中的内容
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/54ea8773-0414-47e8-95ea-14c8bee44fda/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=5cfbf3cbbc11afbe1648af2f4413e5da6a0ae5165e3c2ed6a4b4032dd1834678&X-Amz-SignedHeaders=host&x-id=GetObject)
先调用一遍printPkgVersion
方法,在每次执行taro
命令时先打印一遍taro
版本号
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/a0cd74a2-0394-466e-9ad2-1ed814efe748/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=0bab41ee2c6af92bdedf8aaa1b7c443ea728a689ecbd6174ea3e9380d11e7b24&X-Amz-SignedHeaders=host&x-id=GetObject)
后面新建了一个CLI
类的实例并执行了 run
方法也就是 parseArgs
方法, parseArgs
方法解析命令行参数并作对应处理
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/0ef1a618-216c-4c5c-96ec-97f746513f5e/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=ebc712f14e18cab5def2346f163b4c7f83d5d78bdd118ef36f29a0d448ef83d9&X-Amz-SignedHeaders=host&x-id=GetObject)
二、解析命令参数
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/b3e0a6fe-258b-4859-8739-130d50248cf7/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=adecaddaad3235d2b99071844aae26e5ffc845bc796fa5185fbb9c17a6593bae&X-Amz-SignedHeaders=host&x-id=GetObject)
taro
使用了minimist
这个库来解析,解析结果里面的首个key
是_
,它的值是个数组,包含的是所有没有关联选项的参数,比如taro build --type weapp --watch
命令解析的结果是:
三、设置环境变量
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/b2a55902-922f-4310-91a6-e6ab1e99ac02/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=3e6221928f5d4c633c5dfe86e2fe1fee7fd0f3bcb18c57575175238fad1c4c64&X-Amz-SignedHeaders=host&x-id=GetObject)
- 若命令行参数有传入
env
字段,则将环境变量NODE_ENV
设置为传入的值,若未传入env
字段,则根据是否传入watch
字段来设置NODE_ENV
为development
或者production
- 根据传入的
type
或t
或plugin
字段来设置TARO_ENV
- 自动导入默认的
env
环境文件.env
和.env.local
,同时根据传入mode
字段或者前面设置的NODE_ENV
导入对应的env
文件
四、获取项目配置
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/e482fde6-29ee-49e7-9494-7024d4d052f3/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=0255a83267b38bddfd0a84361bcc589c6d4c54601a33ec8e52fba9e3f4526130&X-Amz-SignedHeaders=host&x-id=GetObject)
taro
将获取配置信息封装成了一个类并且抽离到了 @tarojs/service
包中,实例化后,调用了 init
方法
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/6e3bb97d-a97b-4d44-8d5b-2e8e7b456816/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=2185e3c0143b083e3a1ec4b68a54fee01790716a475eb5ddac44e36b0820c79e&X-Amz-SignedHeaders=host&x-id=GetObject)
init
方法里面首先判断当前路径下是否有 config/index
文件,如果没有,比如我们是在空白文件夹下运行 taro init
命令,它会去执行 initGlobalConfig
方法来尝试获取全局配置,如果有,则通过@swc/register
即时编译,然后读取配置文件内容保存到initialConfig
中
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/9f4219f4-00f4-49f4-a598-8f5065fcc3af/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=709de4cbdbe0a3916601e35f2c35b95a3856fecb181e0cbdabfc6d521eb8cea1&X-Amz-SignedHeaders=host&x-id=GetObject)
getConfigWithNamed
方法会在Kernel
类里面通过Config
实例对象调用,将编译配置里面平台对应的信息铺平,比如mini
,h5
这些
五、实例化Kernel
并执行run
方法
Kernel
是抽离到 @tarojs/service
包中的一个类,taro
运行的各项命令都是围绕它展开
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/14bcd7c6-9492-45d9-bf1f-df83fd907f8d/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=4575645823869674840b8c934320169c7ab8945e4ba994091f4ab58b5079b8d6&X-Amz-SignedHeaders=host&x-id=GetObject)
创建类实例的时候传入了一个包含4个属性的对象
- appPath:
process.cwd()
返回的当前工作目录 - presets:
taro
预设的一些plugins
集合 - config:运行
taro
命令的相关配置信息,也就是前文实例化后的config
对象 - plugins:初始值空数组
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/02ce3891-8ccc-4e3a-b2ee-f6090f46fbf0/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=eed82b28367038c9d0d28a4d8a9afd2e45a1191890ce638d152642cdade93872&X-Amz-SignedHeaders=host&x-id=GetObject)
在构造方法中接收参数保存到内部属性中,同时进行了一些初始化操作
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/e8d5cc95-6934-40fd-b305-f835fd7e14ce/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=05b2125b02a6bf41b6062eadfb279117501b46be87edb4e95665f902c31a7b0e&X-Amz-SignedHeaders=host&x-id=GetObject)
在实例化完成后,通过对传入的命令行参数进行判断,收集执行本次命令需要使用到的所有插件,保存到optsPlugins
属性中,然后执行customCommand
方法
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/8d8838f9-abe7-4398-b69d-0b7079c357de/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=92a9925af0ed4c053eb274ab8ba890258336f54f45a84517cb1f4b2f7135b63c&X-Amz-SignedHeaders=host&x-id=GetObject)
customCommand
方法就是对 kernel
的 run
方法进行了一个封装,代码执行到这里,正式进入到kernel
内部
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/e46869aa-0f93-45f2-9245-f7fe0576ffa7/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=7bed1f37e19a629b8f2e66c991d7479f04d85de2dff65e3bfbb0ee41422920a5&X-Amz-SignedHeaders=host&x-id=GetObject)
在Kernel
类的 run
方法里面,首先通过 initPresetsAndPlugins
方法进行初始化项目中使用到的插件
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/5f6cfbc0-ea29-4685-b60e-cc9486978d53/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=c08f3a956dd8c4cc29575de87feb86b16f73046270826972777baf7d69cbe6ca&X-Amz-SignedHeaders=host&x-id=GetObject)
合并实例化时传入的presets
和项目配置的presets
并转换为一个JSON
对象cliAndProjectConfigPresets
,合并实例化时传入的plugins
和项目配置的plugins
并转换为一个JSON
对象cliAndProjectPlugins
,然后分别调用resolvePresets
和resolvePlugins
进行处理
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/dfd7bdfe-096e-4685-b1e5-1bc0eea30312/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=9a3ccb9becf054ede862471f8887a9d5f0cf7e4de813d92d72b93fd1a8065f33&X-Amz-SignedHeaders=host&x-id=GetObject)
通过resolvePresetsOrPlugins
方法将presets
和plugins
转换为对象数组,单个元素的格式如下:
然后对于每个preset
进行initPreset
处理,对于每个plugin
进行initPlugin
处理
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/79d80f9a-9df3-493c-9d53-652ae2d78c67/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=41279b8869ce02dfe9d4ba02ee81e4c3f2f5c8033f125ffb5d2c7855dd49ffcb&X-Amz-SignedHeaders=host&x-id=GetObject)
可以看到这2个函数都是先调用了initPluginCtx
方法来获取插件上下文,initPluginCtx
方法实例化了一个Plugin
类作为插件上下文,同时通过Proxy
对上下文对象进行了扩展,kernelApis
里面的这些属性和方法可以直接被插件上下文对象调用,当有插件监听了某个hook
,就会触发proxy
的get
函数, 然后调用method
里面的方法也就是Plugin
类里面的register
方法,将这个hook
保存到kernel
中的hooks
字段里
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/e32f3f77-11d9-4517-8381-fbb16b0df9fa/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=2c731d8fbea5b2e8996dd4d979549b62afd19f464aca936e6be89df08ac4c2ba&X-Amz-SignedHeaders=host&x-id=GetObject)
六、Plugin
类
在Plugin
类里面,通过ctx
字段保存kernel
上下文对象来访问和修改kernel
的属性,这样kernel
内部可以直接获取到插件信息
- register:注册一个可供其他插件调用的钩子,接收一个参数,即 Hook 对象
- registerCommand:注册一个自定义命令
- registerPlatform:注册一个编译平台
- registerMethod:向
ctx
上挂载一个方法可供其他插件直接调用 - addPluginOptsSchema:为插件入参添加校验,接受一个函数类型参数,函数入参为
joi
对象,返回值为joi schema
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/7acb656d-b194-48c6-a064-2ff4158cb0f4/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=cd053ed01d4504756cd453c831f0124caae7c288f223580f5dda9694be0c3a40&X-Amz-SignedHeaders=host&x-id=GetObject)
taro
的插件都有固定的代码结构,通常由一个函数组成,比如这个官网的示例
源码里面在获取到initPluginCtx
方法返回的插件上下文后,通过apply
方法获取插件返回的函数,然后执行这个函数并将插件上下文作为第一个参数传入,这个上下文能做很多事情,最直接的,可以调用Plugin
类里面的方法,然后,前文也提到了,还可以访问Kernel
类里面部分属性和方法,除此之外,还可以访问taro
内置的通过registerMethod
挂载的方法或者hooks
,这些挂载的方法内容都保存在kernel
的 methods
属性里,比如上例编译生命周期这些hooks
,如果有插件监听的话,就会执行methods
里面的函数,fn
就是我们监听某个hook
的处理函数,跟name
一起作为参数调用register
方法,这样hooks
信息就保存了起来,所有的方法介绍可以看 官网
七、applyPlugins
方法
在 initPresetsAndPlugins
方法执行完成后,我们再回头看 run
方法,发现run
方法后续只调用了多次 applyPlugins
函数,没错,插件执行的架构就是在applyPlugins
里面实现的
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/899cec3e-3efb-4310-8fbe-69f511e59ede/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=2d9ee4c9f359172b804affe7766a07ca53890b0af425ca6911f106ee42ae5018&X-Amz-SignedHeaders=host&x-id=GetObject)
applyPlugins
函数里面先判断this.hooks
里面是否存在指定name
对应的hooks
,也就是查询是否有插件通过Plugin
注册过这个name
的钩子,如果没有注册过name
则直接返回,如果有注册,则使用 Tapable 的AsyncSeriesWaterfallHook
(异步串行瀑布式钩子)来调用,在插件里面也经常会用到applyPlugins
函数来触发不同插件注册的钩子
八、taro init
做了什么
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/311a6960-3561-4bc9-b46c-76aa6962350f/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=e4ff6d3313f53ef5369200123c4451401d82a92e536ffb9c2f30ab2cf8ad0f20&X-Amz-SignedHeaders=host&x-id=GetObject)
从 customCommand
到kernel.run
再到 applyPlugins
,最终执行的是taro
内部自带的init
插件
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/fdebbd66-e62d-4815-aee7-d0f3d204e4d2/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=40105bb61b48099acd17cb8c8e986dc45eafdd36b879e6555c2d80deece5f4e9&X-Amz-SignedHeaders=host&x-id=GetObject)
插件里面代码很简单,获取下命令行参数,实例化 Project
类,执行create
方法
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/7b08614b-31c2-4d86-a6d7-ca1f831d2ab0/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=830ee1805df147b71765be8d7fa34a3b441be2c1482ca99d90db56a9861ef4cb&X-Amz-SignedHeaders=host&x-id=GetObject)
在ask
函数里面通过inquirer
这个交互式命令行工具让用户选择项目的配置,然后执行write
方法创建项目文件
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/f88743e4-dfd3-4314-a713-cd30a9968e21/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=c60b6d19e5b5870c97d0ea501c92040b935ae3cf0db7ed7b0cd397ab735c8034&X-Amz-SignedHeaders=host&x-id=GetObject)
这里的handler
是用于控制是否生成某文件,或给文件传入特定参数,详细介绍可以参考官网
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/41394987-cba6-4916-8adb-03be45006c3f/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=4564aa96e672ba491cf8d1e577e26ba89abd04d8ee586a08d9f6d46417752830&X-Amz-SignedHeaders=host&x-id=GetObject)
write
函数其实也是对createProject
方法的封装,createProject
方法是从 @tarojs/binding
库中引入的,@tarojs/binding
是通过napi-rs框架实现的Node.js
扩展
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/f3e35390-e2ba-4733-9b90-83302bd8543e/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=65a796109b945d7baaf418ddcf4aa1f5bbeb8b72b518641fbb503f5590129cdd&X-Amz-SignedHeaders=host&x-id=GetObject)
create_project
里面先是调用了结构体Project
的impl
的关联函数new
创建一个实例,Project
是从taro_init
这个 Package
中引入的,然后调用实例的create
函数
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/d85e3315-de8d-4c44-a2fb-e8551603f1e8/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=c34953281f3d1390783c80cdda2cd58e94d5de79a86c7f1890121ad3378ff610&X-Amz-SignedHeaders=host&x-id=GetObject)
create_options
就是初始化的配置信息,这里新添加了几个字段,比如固定page_name
为index
,all_files
就是模板文件夹下面的所有文件组成的数组,比如选择默认模板,获取的就是 taro cli
自带模板default
目录下所有文件:
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/dca2179c-030f-4447-8930-b42f74372afb/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=c40a8d77bb637fe7e0810299a2aa430bc7f5fd7f7c76f94fa4af542a5a5de684&X-Amz-SignedHeaders=host&x-id=GetObject)
然后就调用create_files
函数并把all_files
作为第一个参数传入,第二个参数template_path
是模板文件夹的路径,第三个参数options
是新建项目的配置信息,第四个参数js_handlers
就是前文说的handler
,进入函数后,便对所有文件进行遍历操作
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/df315a72-dcc0-4ca3-8728-05eb5918470b/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=7087fe852a4ff3be33d90d2a2a7e50f67b2c6019b665817c9380969f7ec3ff52&X-Amz-SignedHeaders=host&x-id=GetObject)
file_relative_path
就是将完整的绝对路径file
移除template_path
转换成相对路径,handler
里面的key
就是用的相对路径,这样就可以进行匹配了,如果这个文件在js_handlers
里面匹配到了,就对其在hander
里面定义的函数进行调用,函数支持返回一个布尔类型或者一个JSON
对象,布尔类型可以控制是否创建文件,可以看到,taro
将返回的结果保存在 need_create_file
里,当need_create_file
为真值是才会创建文件,这样可以实现指定某个文件只有在使用指定框架或者使用Typescript
时才会创建, 如果返回的是JSON
对象,会获取对象里面指定key
的值进行操作,这里目前支持4个固定key
:
- setPageName:设置文件的输出路径
- changeExt:是否自动替换文件后缀
- setSubPkgPageName:分包文件的输出路径
- subPkg:分包页面路径
整理完信息后,便正式开始创建文件,可以看到,create_files
最终是执行的self.tempate
函数来创建文件,传入3个参数, from_path
就是模板文件的路径,dest_path
就是要生成文件的路径,options
还是创建项目的配置信息, self.tempate
函数里面又执行了generate_with_template
函数
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/6b02a411-c8e8-4108-ae91-8e055f0ee765/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=9be4bf2902112f8058c78a002c521e48dd1d6e06b8e67b0e7fa5795dbb3e864f&X-Amz-SignedHeaders=host&x-id=GetObject)
这里在读取到模板文件内容后,还调用了HANDLEBARS.render_template
来转换模板文件,这样生成的文件内容才是我们想要的
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/ccacc17d-b3af-4aff-820b-57d09c01cb93/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=c3f68292fcafe24b924d6f8d8e0bc7b71e444e257f6dfe1134d046aba3638809&X-Amz-SignedHeaders=host&x-id=GetObject)
在 create_files
函数创建文件完成后,回到create
函数里,又调用了init_git
函数进行git
初始化
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/68c6c619-7243-4430-9464-9ad80040505d/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=731f023a32abef2999928a953b12730d6ba770884dfac737fe0f6492f3a91122&X-Amz-SignedHeaders=host&x-id=GetObject)
最后,执行install_deps
函数安装项目依赖
![](https://prod-files-secure.s3.us-west-2.amazonaws.com/44da4746-95f3-43f1-b4eb-1901acbbe54d/7b2a7455-0ceb-4532-b2f4-139c37081979/Untitled.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=AKIAT73L2G45HZZMZUHI%2F20240908%2Fus-west-2%2Fs3%2Faws4_request&X-Amz-Date=20240908T022109Z&X-Amz-Expires=3600&X-Amz-Signature=f012986ae9edd0be29e67168eb1d81dee5eebe5467eea421d4cba73dc074e9f5&X-Amz-SignedHeaders=host&x-id=GetObject)
至此,taro init
创建项目的流程便走完了