当利用vue脚手架创建项目之后利用 npm run serve 启动开发环境,我们就从这里来开始分析。
首先从package.json中的脚本配置来看,npm run serve调用的是vue-cli-service serve命令。
这个时候就应该来到node_modules中的.bin查找vue-cli-service.js文件。
但是在vue-cli-service.js文件中有一句代码const Service = require(’…/lib/Service’),但是根据这个路径是找不到这个文件的。那么这个文件在哪里呢?
其实真正入口在node_modules/@vue/cli-service/bin/vue-cli-service.js。
那在vue-cli-service.js中到底做了什么事呢?
核心逻辑:
1、初始化Service
const Service = require('../lib/Service')
const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
2、调用service的run方法
service.run(command, args, rawArgv)
1、初始化一些内置参数
2、读取package.json中的配置信息 this.resolvePkg(pkg)
3、读取插件信息 this.resolvePlugins(plugins, useBuiltIn)
this.resolvePlugins函数到底做了什么事呢?
1、加载builtInPlugins插件(比如当前目录下的’./commands/serve’,’./commands/build’等),然后把各个插件中导出的函数挂载到apply字段中
const idToPlugin = id => ({
id: id.replace(/^.\//, 'built-in:'),
apply: require(id)
})
let plugins
const builtInPlugins = [
'./commands/serve',
'./commands/build',
'./commands/inspect',
'./commands/help',
// config plugins are order sensitive
'./config/base',
'./config/css',
'./config/prod',
'./config/app'
].map(idToPlugin)
// 说明:apply等于各个插件中导出的函数
apply = module.exports = (api, options) => {}
2、加载package.json中devDependencies配置的插件,同样将导出的函数挂载到apply
const projectPlugins = Object.keys(this.pkg.devDependencies || {})
...
3、加载本地插件
4、合并所有插件并返回
plugins = builtInPlugins.concat(projectPlugins)
plugins = plugins.concat(files.map(file => ({
id: `local:${file}`,
apply: loadModule(`./${file}`, this.pkgContext)
})))
到这里构造函数做的事情已经完毕了。
1、根据参数加载需要过滤的插件 this.setPluginsToSkip(args)
2、this.init(mode)
3、从this.commands中取出fn函数并执行
let command = this.commands[name]
const { fn } = command
return fn(args, rawArgv)
this.init(mode)方法详细分析:
1、根据mode读取环境配置this.loadEnv(mode)
2、读取基本的环境配置this.loadEnv()
3、loadUserOptions(),加载vue.config.js和vue.config.cjs中的配置
4、遍历所有插件然后执行
this.plugins.forEach(({ id, apply }) => {
if (this.pluginsToSkip.has(id)) return
apply(new PluginAPI(id, this), this.projectOptions)
})
5、加载一些其他配置
apply(new PluginAPI(id, this), this.projectOptions)这个函数做了什么事情呢?
1、创建PluginAPI实例,传入插件名称和Service的实例
2、根据上面分析,apply()就是调用插件导出的函数
这里以第一个插件"./commands/serve"来分析说明:
// serve.js
api.registerCommand('serve', {},async function serve (args) {})
// PluginAPI.js
registerCommand (name, opts, fn) {
if (typeof opts === 'function') {
fn = opts
opts = null
}
this.service.commands[name] = { fn, opts: opts || {}}
}
serve插件调用apply()函数就是调用PluginAPI中的registerCommand函数。
1、根据以上第5步分析,this.service = Service
2、相当于在Service的commands对象中存储了一个"serve" = serve (args) {}键值对。
回到Service.run的最后一步就是执行的这里填入的方法。
serve插件为例:
fn(args, rawArgv) = async function serve (args) {}
那serve函数中就是一些关于开发环境中资源的加载、webpack的编译、WebpackDevServer的创建等的操作。
其他加载的插件也是这么分析的,可以根据不同文件的具体实现了解里面的操作。
终上所述:
下面是Vue脚手架项目启动过程解析思维导图
高清无码大图下载