Vue CLI插件开发

293 阅读5分钟

1. 前言

一个CLI插件其实就是一个npm包,它可以为Vue CLI创建的项目添加额外功能,这些内容包括:

  • 修改项目webpack配置

  • 添加vue-cli-service命令

  • 扩展package.json

  • 在项目中创建新文件或修改老文件内容

  • 提供用户选项

2. 主要结构

├── README.md
├── generator.js  # generator(可选)
├── index.js      # service 插件
├── package.json
├── prompts.js    # prompt 文件(可选)
└── ui.js         # Vue UI 集成(可选)
  • README.md

插件介绍及使用文档

  • generator.js

一个发布为npm包的Vue CLI插件可以包含一个generator.js或者generator/index.js文件。它在以下两种场景会被调用:

1.在一个项目初始化创建过程中,如果CLI插件作为项目创建preset的一部分被安装。

2.插件在项目创建好之后通过vue invoke独立调用时被安装。

  • index.js

Service插件通俗理解主要起修改webpack配置所用。

  • package.json

不过多阐述

  • prompts.js

prompt选项配置

  • ui.js

Vue UI相关配置

3. Generator

介绍

Generator部分是当你想要为当前Vue CLI创建的项目添加项目扩展包、创建新文件或者编辑已存在的文件时需要。

参数

一个generator应该导出一个接受三个参数的函数:

  1. 一个GeneratorAPI实例;

  2. 插件的generator选项。使用prompts.js创建对话的参数,或者从一个保存在~/.vuerc中的preset中加载。

例如:

{
    "presets": {
        "foo": {
            "plugins": {
                "@vue/cli-plugin-foo": { "option": "bar" }
            }
        }
    }
}

如果用户使用preset foo创建了一个项目,那么@vue/cli-plugin-foo的generator就会收到{ option: 'bar' }作为第二个参数。

  1. 整个preset(presets.foo)将会作为第三个参数传入。

GeneratorAPI

  • extendPackage

    • 入参

      • { object | () => object }
    • 使用说明:在package.json中增加依赖。除非传递{ merge:false },否则嵌套字段是深度合并的,还解决插件间的依赖冲突。

  • render

    • 入参

      • { string | object | FileMidderware } 可以是某个文件夹的相对路径、自定义文件中间件函数、{ sourceTemplate: targetFile }映射的对象哈希

      • { object }[additionalData] 模版可用的其他数据

      • { object }[ejsOptions] ejs额外参数

    • 使用说明:使用ejs渲染文件到项目结构中

  • resolve

    • 入参

      • { string }相对于工程根目录的目录
    • 返回值

      • { string }文件绝对路径
    • 使用说明

      • 获取一个文件/文件夹的绝对路径

4. Service插件

介绍

Service插件会在一个Service实例被创建时自动加载——比如每次执行vue-cli-service命令时被调用。

此外@vue/cli-service的内建命令和配置模块也全部以service插件实现的。

参数

一个service插件应该导出一个函数,这个函数接受两个参数

  • 一个PluginAPI实例

  • 一个包含vue.config.js内指定的项目本地选项对象,或者在package.json内的vue字段。

PlguinAPI

  • registerCommand

    • 作用:在cli中注册一个类似于vue-cli-service [name]的命令

    • 入参:

      • name(命令名称)

      • args(可选参数)

{
    description: string,
    usage: string,
    options: { [string]: string }
}

vue-cli-service build为例

module.exports = (api, options) => {
api.registerCommand('serve', {
    description: 'start development server',
    usage: 'vue-cli-service serve [options] [entry]',
    options: {
      '--open': `open browser on server start`,
      '--copy': `copy url to clipboard on server start`,
      '--mode': `specify env mode (default: development)`,
      '--host': `specify host (default: ${defaults.host})`,
      '--port': `specify port (default: ${defaults.port})`,
      '--https': `use https (default: ${defaults.https})`,
      '--public': `specify the public network URL for the HMR client`,
      '--skip-plugins': `comma-separated list of plugin names to skip for this run`
    }})
}
  • chainWebpack

    • 作用:通过链式的方式修改webpack相关配置

    • 入参:callback

  • configureWebpack

    • 作用:修改webpack配置,注意如果configureWebpack为Object,是merge配置操作!如果configureWebpack为Function,是直接修改配置!
module.exports = (api, projectOptions) => {
    api.chainWebpack(webpackConfig => {
        // 通过webpack-chain修改webpack配置
    })
    
    api.configureWebpack(webpackConfig => {
        // 修改webpack配置
        // 或者返回webpack-merge合并的配置对象
    })
    
    api.registerCommand('test', args => {
        // 注册 vue-cli-service test
    })
}

// 如果已经注册的插件命令需要运行在特定的模式下,需要module.exports.defaultModes({ key: value })的形式暴露
module.exports.defaultModes = { build: 'production' }
  • resolveWebpackConfig

    • 作用:得到使用过api.configureWebpack或者api.chainWebpack之后到修改后的webpack值
  • getCwd

    • 作用:当前工作目录
  • version

    • 作用:当前使用cli的@vue/cli-service版本
  • resolve

    • 作用:返回指定目录的绝对路径

    • 入参:相对于根目录的目录

5. Prompts

大家是否还记得vue create创建项目或者vue add插件添加插件的时候,需要用户处理一些选择。所有的逻辑均在prompts.js中进行实现。

当用户初始化插件时,如果插件的根目录存在prompts.js时,则会对其进行调用。

prompts.js导出可以有两种方式:

  1. 导出一个数组

  2. 导出一个函数

其中导出结果将为generator/index.js的第二个参数

导出数组的结构

{
    // 默认值为输入:input
    type: "input | number | confirm | list | rawlist | expand | checkbox | password | editor",
    
    // 可以通过generator/index.js的第二个参数进行获取
    name: String,
  
    // 问题内容。如果定义为函数,则第一个参数将是当前查询者会话答案。缺省值为name(后跟冒号)
    message: String | Function,
    
    // 当前问题默认值,如果定义为函数,则第一个参数将是当前查询者会话答案。
    default: String | Number | Boolean | Array | Function,
  
    // Choices数组或返回choices数组的函数。如果定义为函数,则第一个参数将是当前查询者会话答案
    choices: Array | Function,
    
    // 校验输入的值是否符合要求
    validate:Function,
    
    // 接收用户输入并返回要在程序内部使用的过滤值
    filter: Function,
    
    // 接收当前用户的答案哈希,并应返回true或false取决于是否应询问此问题
    when: Boolean | Function,
    
    // 当使用list, rawList, expand, checkbox的时候可能存在分页
    pageSize: Number,
  
    // 更改默认的前缀消息 
    prefix: String,
  
    // 更改默认的后缀消息
    suffix: String
}

6. UI集成

UI集成文档