跳到主要内容

vuecli源码解析(2)

· 阅读需 9 分钟

image-20220122161800174

上文说到创建完package.json文件并安装plugins的依赖,然后后续会初始化Generator实例,Generator内部会调用各个plugin,涉及到插件机制的实现,这里单独起一篇介绍。

plugin程序

首先了解一下@vue/cliplugin的开发方式,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方法对presetplugins执行顺序进行排列,保证vue-cli-service始终第一个执行,并且加载plugin内部的generator.jsprompts.js程序,推入apply方法。

image-20220122165140480

初始化Generator

加载完plugin之后,会初始化Generator实例。

image-20220122162924717

plugins排序

Generator构造函数内部会对plugins进行排序,这个排序有点讲究的,根据代码里的注释来看使用了 leetcode 210 题的算法,这里以后探索。

image-20220123224513408

image-20220123225127884

加载generator程序

初始化的时候还会加载package.json内部的其他插件,放入实例的allPlugins内部。

image-20220123231305314

image-20220123231340125

调用generate方法

初始化完Generator会调用实例的generate方法,generate内部首先会调用initPlugins

image-20220123230342636

initPlugins内部会为每一个plugin初始化一个GeneratorAPI的实例,然后将实例对象传入apply方法,上文说到apply就是plugin内部的generator程序,所以这里就是执行plugin内部的generator

image-20220123232325784

GeneratorAPI

GeneratorAPI这个类内部包含编写plugingenerator所需要的所有方法,其在初始化的时候接收plugin的名称idGenerator的实例,插件的参数options。其内部定义了生成模板文件的方法render,拓展package.json的依赖项extendPackage等。

vue-cli-service

vue-cli-service为例,其内部generator程序如下,使用render方法渲染template内部的模板文件,拓展package.json的依赖项以及注入scriptsbrowserslist字段。

image-20220123233651940

render

render方法会解析传入的文件夹路径,使用globby匹配获取文件夹下的所有文件。对于ejs模板还会调用renderFile方法将参数填入模板内部。

image-20220124000415280

最后通过_injectFileMiddleware推入Generator实例的fileMiddlewares中。

image-20220124000509280

extendPackage

image-20220124000730967

extendPackage内部会拓展Generator实例的pkg属性,也就对应package.json内部的字段。

生成配置文件

继续看generate方法,之后会调用extractConfigFiles方法,extractConfigFiles会获取在package.json内部的配置项字段,例如babeleslintConfigbrowserslist等,将它们对应的有效配置文件名称推入实例的files属性内部,然后删除package.json内部的这些字段。

image-20220123235424070

之后会调用writeFileTree生成所有文件,writeFileTree内部使用fs-extra来操作文件。这样plugingenerator就执行完了。

image-20220123235711778