vue-cli命令npm run serve 源码解析(二)

前言

上次说到npm run serve 实际上是运行了node vue-cli-service.js
而主要的逻辑是在./lib/Service.js
今天就来看看./lib/Service.js的源码

构造函数

这个文件export了Service类,其构造函数:

constructor (context, { plugins, pkg, inlineOptions, useBuiltIn } = {})

主要是 获取 当前命令行的 进程上下文 和一些 配置文件的实例(插件,依赖,配置)
在构造函数中主要做一件事,就是 加载插件

inline是可以理解成为内置的意思
useBuiltIn 是一个boolean值,用来判断是否使用内置插件和内置配置
首先会把项目 package.json转换成为键值对存储对象:

...
    this.pkg = this.resolvePkg(pkg)
...

然后再通过函数resolvePlugins加载所有需需要的插件:

    this.plugins = this.resolvePlugins(plugins, useBuiltIn)

this.resolvePlugins(plugins, useBuiltIn)

@vue\cli-service\bin\vue-cli-service.js代码:

const service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())

可见,inlinePlugins是空的,useBuiltIn是false
而函数最终会返回一个集合plugins
最终返回的plugins有可能会由这三类plugin组成:

  1. builtInPlugins(这是一定会有的)
  2. inlinePlugins 和 projectPlugins(项目package.json文件的dependencies)
  3. localPlugins(vue相关的插件)

1.builtInPlugins

    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)

可以看到这里内置的插件有哪些,其中./commands/serve就是我们serve指令运行的插件。

2.inlinePlugins 与 projectPlugins

以下代码做了两件事:
1,当inlinePlugins有值的时候,就加载projectPlugins了

这里我个人猜测其实inlinePlugins的来源和projectPlugins其实是一样的,都是项目的package.json,只是如果在其他脚本已经加载过projectPlugins后再使用Service类的话,就不需要重复加载,而我们的npm run serve代码可见以下代码是首次加载,所以就会运行else代码

2.从this.pkg.dependencies加载projectPlugins 列表。
其中也分两类,一类是必要的插件,一类是可选插件

if (inlinePlugins) {
      plugins = useBuiltIn !== false
        ? builtInPlugins.concat(inlinePlugins)
        : inlinePlugins
    } else {
      const projectPlugins = Object.keys(this.pkg.devDependencies || {})
        .concat(Object.keys(this.pkg.dependencies || {}))
        .filter(isPlugin)
        .map(id => {
          if (
            this.pkg.optionalDependencies &&
            id in this.pkg.optionalDependencies
          ) {//判断插件是否可选插件
            let apply = () => {}
            try {
              apply = require(id)
            } catch (e) {
              warn(`Optional dependency ${id} is not installed.`)
            }

            return { id, apply }
          } else {
            return idToPlugin(id)
          }
        })
      plugins = builtInPlugins.concat(projectPlugins)//把结果合并到builtInPlugins中
    }

3.localPlugins

localPlugins就是从this.pkg.vuePlugins.service加载的插件

    if (this.pkg.vuePlugins && this.pkg.vuePlugins.service) {
      const files = this.pkg.vuePlugins.service
      if (!Array.isArray(files)) {
        throw new Error(`Invalid type for option 'vuePlugins.service', expected 'array' but got ${typeof files}.`)
      }
      plugins = plugins.concat(files.map(file => ({
        id: `local:${file}`,
        apply: loadModule(`./${file}`, this.pkgContext)
      })))
    }

大部分的item都是由idToPlugin构建的:

{
    const idToPlugin = id => ({
      id: id.replace(/^.\//, 'built-in:'),
      apply: require(id)
    })
}

id其实就是js文件的相对地址,只是开头区分了built-in(内置) 或者 local(本地)

最后返回了的plugins会在init的时候用到。

接下来就开始看看Service的run函数

posted @ 2020-06-15 14:42  不务正业的反派角色  阅读(717)  评论(0)    收藏  举报