上文说到创建完package.json
文件并安装plugins
的依赖,然后后续会初始化Generator
实例,Generator
内部会调用各个plugin
,涉及到插件机制的实现,这里单独起一篇介绍。
plugin程序
首先了解一下@vue/cli
中plugin
的开发方式,plugin
由一个 Service 插件index.js
文件作为引导,此外还可以包含generator.js
,prompts.js
这些文件。
index.js
可以修改 webpack 配置,创建新的 vue-cli service 命令或者修改已经存在的命令。
generator
主要用于拓展项目依赖,创建新的文件或者编辑已经存在的文件;且必须是一个函数。
prompts.js
则在创建一个新的项目或者在已有项目中添加新的插件时处理用户选项,通过inquirer
实现。
.
├── README.md
├── generator.js # generator(可选)
├── index.js # service 插件
├── package.json
├── prompts.js # prompt 文件(可选)
└── ui.js # Vue UI 集成(可选)
加载plugin
紧接上文继续分析Creator
内部的create
方法,在安装完@vue/cli
内部的vue-cli-service
等插件的依赖后,会通过resolvePlugins
方法对preset
的plugins
执行顺序进行排列,保证vue-cli-service
始终第一个执行,并且加载plugin
内部的generator.js
和prompts.js
程序,推入apply
方法。
初始化Generator
加载完plugin
之后,会初始化Generator
实例。
plugins排序
在Generator
构造函数内部会对plugins
进行排序,这个排序有点讲究的,根据代码里的注释来看使用了 leetcode 210 题的算法,这里以后探索。
加载generator程序
初始化的时候还会加载package.json
内部的其他插件,放入实例的allPlugins
内部。
调用generate方法
初始化完Generator
会调用实例的generate
方法,generate
内部首先会调用initPlugins
initPlugins
内部会为每一个plugin
初始化一个GeneratorAPI
的实例,然后将实例对象传入apply
方法,上文说到apply
就是plugin
内部的generator
程序,所以这里就是执行plugin
内部的generator
。
GeneratorAPI
GeneratorAPI
这个类内部包含编写plugin
的generator
所需要的所有方法,其在初始化的时候接收plugin
的名称id
,Generator
的实例,插件的参数options
。其内部定义了生成模板文件的方法render
,拓展package.json
的依赖项extendPackage
等。
vue-cli-service
以vue-cli-service
为例,其内部generator
程序如下,使用render
方法渲染template
内部的模板文件,拓展package.json
的依赖项以及注入scripts
和browserslist
字段。
render
render
方法会解析传入的文件夹路径,使用globby
匹配获取文件夹下的所有文件。对于ejs
模板还会调用renderFile
方法将参数填入模板内部。
最后通过_injectFileMiddleware
推入Generator
实例的fileMiddlewares
中。
extendPackage
extendPackage
内部会拓展Generator
实例的pkg
属性,也就对应package.json
内部的字段。
生成配置文件
继续看generate
方法,之后会调用extractConfigFiles
方法,extractConfigFiles
会获取在package.json
内部的配置项字段,例如babel
,eslintConfig
,browserslist
等,将它们对应的有效配置文件名称推入实例的files
属性内部,然后删除package.json
内部的这些字段。
之后会调用writeFileTree
生成所有文件,writeFileTree
内部使用fs-extra
来操作文件。这样plugin
的generator
就执行完了。