Vue脚手架创建的项目的启动流程

当利用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)
  • Service构造函数分析

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)
})))

到这里构造函数做的事情已经完毕了。

  • Service.run方法分析

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脚手架项目启动过程解析思维导图

在这里插入图片描述

高清无码大图下载

Logo

前往低代码交流专区

更多推荐