前言

提到 vue-cli,官方文档对其的介绍如下:

A simple CLI for scaffolding Vue.js projects. 一个简单的Vue.js工程命令行脚手架工具。

说白了,vue-cli 其实就是一个基于webpack构建,可以让用户快速初始化一个项目的工具。

基本原理: vue-cli并非从无到有地凭空生成一个项目,而是通过下载/拉取(通过download-git-repo工具)已有的工程到本地,完成生成项目的工作。

  • 注意安装vue-cli 3前,如若已安装旧版本vue-cli,需先卸载旧版本vue-cli,再重新安装vue-cli 3
  • node版本要求: 安装 Node.js8.9 或更高版本

这次我分享的主要主要内容是 vue-cli 3,当然不是全面的介绍,只是将我这次运营系统工作流改造中遇到比较深刻的点进行一番简单介绍

而对于根据我个人对vue-cli 3的认识,我将需掌握的内容概括为四个部分:Vue.config.jsVue-cli-service插件UI

概括:

下面这张图是我对vue-cli 3 知识点进行了一个简单的概括

比较常接触到vue一些基本的命令,比如说:

  • vue create: 快速初始化一个项目
  • vue serve:为某个原型(如:单独一个vue文件)快速启动一个服务(要求全局安装@vue/cli-service-global
  • vue ui: 通过图形化界面创建或管理界面

接下来谈一谈 Vue.config.js

我觉得对于一个普通的项目的工作流构建来说,配置vue.config.js足够了

而里面比较特别和常用的主要是以下这些:除了 publicPathoutputDirfilenameHashingpages 等这些常用字段外,我觉得还需要提一下的是 configureWebpack 字段和 chainWebpack 字段

我对这两个字段的理解是

  • configureWebpack 是让用户字段写一个配置对象,其内部再通过webpack-merge将原有对象和用户配置的对象进行合并
  • chainWebpack 是通过利用webpack-chain提供的链式调用方法去直接修改原有的配置对象

对于 vue-cli 3来说,它还存在一个比较特别的模块,就是它提供了自定义插件的功能

插件

说到vue-cli 3 的插件,其实可以将其分为两种情况:

  1. 一种是vue-cli插件,这种情况一般是对外的,主要是开发一些npm包,并将其发布到npm上;

  2. 另一种就是service 插件, 也就是我这次工作流改造中用到的主要内容,其主要包括內建命令和配置模块,而这两部分的内容都是在调用vue-cli-service命令时才会触发;因此,使用到service插件的用户,需要安装一下vue-cli-service

  • Cli插件(GeneratorPrompts):为@vue/cli项目添加额外特性的 npm 包
  • service插件(內建命令和配置模块):会在一个Service实例被创建时自动加载——比如每次vue-cli-service命令在项目中被调用时。
Vue-cli-service
  1. 內建命令

    该功能的实现主要是调用了api.registerCommand这个方法向vue-cli-service内部注入额外的命令,vue-cli 3提供的vue-cli-service servevue-cli-service build等命令的实现也是利用了这个方法。

  2. 配置模块

    该功能的实现则是利用的api.chainWebpackapi.configureWebpack方法对webpack配置进行修改。

  3. 注:稍后我会在文章的下面给出一个自定义命令的 demo
1
2
// 可以通过下面这个命令查看所有命令,从而确认自定义的命令是否创建成功
npx vue-cli-service help

然后接下来看一看具体实操例子

需求场景

  1. 支持watchbuild命令,并满足以下功能
  2. 同时支持--key命令读取.json文件中的key来进行构建,并支持多个key
  3. 同时支持.json配置文件,可以指定entry路径和output路径

需求示例:

1
2
3
4
5
# watch 监听某个入口的文件变动并编译
$ node ./scripts/Bundler.js watch --key=[your_key]

# build 打包编译某个入口的文件(生产模式)
$ node ./scripts/Bundler.js build --key=[your_key]

这对第三点,假设项目根目录下有 Views.json 文件,形如:

1
2
3
4
5
6
7
8
9
10
11
12
{
"basePath": "resources/assets/js/views",
"destBasePath": "public/js/res",
"entry": {
"page": { // 入口的唯一命名,打包和开发时要用到的 key 值
"name": "page", // 入口文件的文件名(例如 queryDetail.js)
"srcPath": "job/template/page", // JS 入口源文件所在的文件夹的根目录
"output": "page" // 输出文件的名称
"description": "页面功能描述", // 页面功能描述,不启任何作用
}
}
}

然而我为什么没有直接使用vue-cli-service提供的servebuild命令呢?

原因如下:
对于watchbuild命令,其实他们除了要求具备vue-cli-service提供的servebuild命令效果外,还得让用户通过--key传入打包入口,而vue-cli-service提供的这些命令是其内部写好了的,我们无法对其内部进行修改,所以为了实现这个需求,我们需要进行自定义命令。

解决方式:

要实现 watchbuild 功能,其实在 vue-cli 3vue-cli-service 有提供了相对应的 api 给用户进行调用,也就是注册自定义的命令,实际上就是向 vue-cli-service 注入额外的命令。

注册命令的第一种方式 —- 使用 vue-cli-service 插件

以注册watch命令为例,做一个小demo

demo github 地址

  1. 新建一个项目

    1
    2
    3
    4
    5
    6
    // 首先进行 vue-cli 安装
    npm i -g @vue/cli
    // 查看是否安装成功,看到版本号就是安装成功了
    vue -V
    // 新建一个项目
    vue create 项目名
  2. 针对已有项目使用 vue-cli-service

安装vue-cli-service

1
2
// 进行 vue-cli-service 安装
npm i -D @vue/cli-service
  1. package.json中的vuePlugins对象中的service字段引入相应的js文件(用于注册watch 命令的文件, 假设该文件名为:vue-cli-plugin-watch.js,并放在根目录)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // package.json 中
    // 注册命令的 js 文件名为 vue-cli-plugin-watch.js
    {
    "scripts": {
    "watch": "vue-cli-service watch"
    },
    "vuePlugins": {
    "service": [
    "./vue-cli-plugin-watch"
    ]
    }
    }
  2. vue-cli-plugin-watch.js 代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    module.exports = (api, projectOptions) => {
    api.registerCommand('watch', {
    description: 'watch plugin for vue cli 3',
    usage: 'vue-cli-service watch',
    options: {

    }
    }, (args) => {
    console.log('watch 命令注册成功')
    })
    }
  3. 在终端输入npm run watch,看到终端输出“watch命令注册成功”后,恭喜watch命令基本注册完成啦。

可以通过运行npx vue-cli-service help查看vue-cli-service下面的所有命令,可以看到新增加了一个watch命令

  1. 补充:另外,对于一个插件的使用,我们可以选择性的让用户进行一些设置;通过让用户在vue.config.js中的pluginOptions向插件进行传参数

在项目根目录创建vue.config.js文件

1
2
3
4
5
6
7
8
9
// vue.config.js相关代码
module.exports = {
pluginOptions: {
watch: {
// vue-cli-plugin-watch 插件可以作为 `projectOptions.pluginOptions.watch` 访问这些选项,其他插件也可以拿到
param: '传参数给內建插件'
}
}
}

修改vue-cli-plugin-watch.js 代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = (api, projectOptions) => {
api.registerCommand('watch', {
description: 'watch plugin for vue cli 3',
usage: 'vue-cli-service watch',
options: {}
}, (args) => {
// 输出传入的参数
console.log('watch 命令注册成功')
// projectOptions 拿到的是 vue.config.js 文件暴露出来的配置
console.log(projectOptions.pluginOptions.watch.param)
// 通过终端传进来的参数
const key = args.key ? args.key : process.env.npm_config_key
console.log(`--key = ${key}`)
})
}

运行npm run watch命令,可见终端输出了‘传参数给內建插件’,即通过vue-config.js传参成功
运行npm run watch命令,可见终端输出了‘传参数给內建插件’,即传参成功

其实再去看看build命令的实现源码,其实和上面watch的实现是差不多的

Vue-cli-service build 命令源码

注册命令后,就可以通过调用 api.resolveWebpackConfig() 取回解析好的 webpack 配置。每次调用都会新生成一个 webpack 配置用来在需要时进一步修改。

1
2
3
4
5
6
7
8
module.exports = api => {
api.registerCommand('my-build', args => {
const configA = api.resolveWebpackConfig()
const configB = api.resolveWebpackConfig()

// 针对不同的目的修改 `configA` 和 `configB`...
})
}

也可以通过调用 api.resolveChainableWebpackConfig() 获得一个新生成的链式配置

1
2
3
4
5
6
7
8
9
api.registerCommand('my-build', args => {
const configA = api.resolveChainableWebpackConfig()
const configB = api.resolveChainableWebpackConfig()

// 针对不同的目的链式修改 `configA` 和 `configB`...

const finalConfigA = configA.toConfig()
const finalConfigB = configB.toConfig()
})

再看回operation的项目需求,要求实现watchbuild,watch实现还好说,但是考虑到直接使用vue-cli-service的内建命令模块实现build会将其原有的命令进行覆盖,这种操作不太理想,所以改用了另外一种实现方式:使用 commander 实现注册命令。

注册命令的第二方式 —- Commander

  • 定制自己的命令watch

demo github源码地址

主要实现代码如下:

demo具体步骤:

  1. 初始化一个项目
  2. 在根目录下创建一个script文件夹,在该文件夹目录下新建一个用于实现注册命令的js文件,我在这创建的文件名为commandar-watch.js
1
2
// 安装 Commander
npm install Commander -D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// commandar-watch 具体实现代码
// 注:可同时注册多个命令

const program = require('commander')

program.version('0.1.0')
.option('-k, --key [type]', 'key to build')

program
.command('watch')
.description('run the given remote command')
.action(function(){
console.log('watch 命令注册成功')

/**
* 用户传进来的 key 值
* yarn 运行命令时,可通过 program.key 获取到用户传进来的 key 值
* npm 运行命令时,需通过 process.env.npm_config_key 获取到用户传进来的 key 值
*/
const key = program.key ? program.key : process.env.npm_config_key
console.log(key)
})

program.parse(process.argv)
  1. package.json文件中scriptswatch中,使用node执行commandar-watch.jswatch命令

    1
    2
    3
    4
    5
    {
    "scripts": {
    "watch": "node ./script/commandar-watch.js watch",
    },
    }
  2. 在终端执行npm run watch命令,看到终端输出‘watch 命令注册成功’后,恭喜watch命令注册成功啦。当然,你也可以传入--key的值,如:npm run watch --key=用户传的key值,可见到终端输出‘用户传的key值’,证明已经获取到用户传的参数啦。

再谈谈项目中 build 和 watch 的不同点

其实这两个命令主要用到的配置还是Vue-cli 3提供的基本配置,在再次基础上针对不同页面特别设置一些配置,比如说针对某些页面需要进行css提取,还有不同页面设置不同的entryoutput等等。而着这两个命令的主要区别就是Watch 字段、不同mode;对于是否压缩打包,我通过设置不同的环境模式从而设置文件是否需要打包(webpack 4提供了这个功能);至于是否需要监听文件的改变功能的实现,我借鉴了vue-cli-service build命令的--watch实现方式。

vue-cli-service build –watch ,核心代码 是获取webpack 配置,并将配置对象的watch字段的值设置为true。

注: vue-cli-service中的build命令--watch的实现源码地址

Public 文件夹

主要用来放置一些无需经过webpack处理的静态资源或模板等等。其目录下的内容会被直接拷贝到构建输出目录下
关于存在原因:index.html模板,动态引入图片,引入不兼容模块

实现源码

推荐使用 inspect

审查 vue-cli 项目的 webpack 配置,可以很方便将查看使用 vue-cli 3配置后,其具体的 webpack配置

结语

针对这次分享的内容,虽然说我侧重分享了插件部分的内容,但是并不意味着vue-cli 3 内容只有这些,只是我这次开发中遇到比较多的模块就是service插件这一块,所以就特别提了一下,它还有其他的内容比如说ui那一块等等;

体会:
在开发过程中,当遇到,对api不熟悉,造成无法很好的运用好某些api的情况时,其实可以考虑去研究研究一下源码,会发现事情变得简单,其实在vue-cli 的官网里面也有提到配合源码去学习api,这才能真正灵活的使用对应的功能等等。
在这个项目里面,我就是在一边学习一边实现需求。还有,考虑问题要全方面的想,多测试一些页面。比如说npmyarn在终端中的传参方式不一样,导致代码中获取的key值方式也不一样这个问题,就是得多测试才会发现。还有要多请教一些前辈,你会发现有时候经验对于开发方式和开发效率来说,真的很重要。

参考文章:

拓展文章: