揭秘 Vue-cli!六部带你写出自己的 cli 工具

213 阅读7分钟

hi...我是 achens,19岁!求职ing...

NPM 官网:

www.npmjs.com/

NPM 中文文档

www.npmjs.com.cn/

本文仓库地址:

gitee.com/achens/s-cl…

Webpack5 模板:

基于 Webpack5 搭建 Vue2 后台开发环境

Vite2 模板:

基于 Vite2 搭建 Vue3 + Ts 开发环境

一、定义本地全局指令

本地新建文件夹 --》 index.js,写上一行 console.log(),输出任意内容。
然后在当前文件夹的终端输入 node 执行命令即可用 node 执行一个 js 文件。

node index.js

image.png
image.png
但是这样输出又有些不方便,这时就可以尝试在本地定义一个全局的自定义命令。

  1. 初始化 node_module

输入命令后文件夹下会多出一个 package.json 配置文件。

npm init -y

  1. 配置自定义命令

现在在在这个配置文件的最下面添加 bin 选项并自定义一个名叫 run 的指令执行 index.js。
image.png

  1. 指令连接全局

输入 link 连接全局后,我们就可以在全局任何地方通过输入 run 命令来运行 index.js。

npm link

解绑指令:

npm unlink

且 index.js 最上面必须加上这行代码,或者绑定指令之后运行会报错。

#!/usr/bin/env node

image.png
image.png

二、使用 Commander 解析命令行参数

1. 原生获取命令行参数的方式

使用:process.argv 关键字。
image.png
image.png
可以通过空格添加多个命令:
image.png

2. 使用包 Commander.js 模块来获取处理命令行参数

Commander.js 中文文档:

github.com/tj/commande…

  1. 安装

npm install commander

  1. 安装好后我们可以直接将官网中的示例复制到我们的代码中,然后在控制台输入 run -V 就可以看到控制台已经输出了我们的默认版本号。

image.png
同理,直接输入 run 会弹出选项提示:
image.png

3. 设计自己的命令行参数

1. init 初始化模板命令

// init 命令
program
  // 定义命令:.command(命令名,[参数])
  // []:表示可选参数
  // <>:表示必填参数
  .command("init <templateName> <projectName>")
  // 命令别名
  .alias("i")
  // 命令作用介绍
  .description("初始化项目模板")
  // 可接在此命令之后连用的指令
  .option("-i, --init <name>", "命令后使用选项接参数示例", "normal")
  // 命令执行回调
  .action((templateName, projectName, options) => {
    // templateName:传给本项命令的参数
    // projectName:传给本项命令的第二个参数
    // options.***:传给命令之后使用的指令的参数(option.init)
    console.log(
      `使用模板名:${templateName}, 项目名称为:${projectName}, ${
        options.init === "normal" ? "" : `选项参数为:${options.init}`
      }`
    );
  });

2. list 查看模板命令

// list 命令
program
  .command("list")
  .description("查看所有可用模板")
  .action(() => {
    console.log(`
    Webpack Webpack-vue2模板
    Webpack Webpack-vue3模板
    Vite Vite-Vue2模板
    Vite Vite-Vue3模板
    `);
  });

三、进行模板下载

1. 准备模板

  1. 进入 GitHub 或 Gitee 新建仓库准备好需要使用的模板。

image.png

  1. 初始化模板信息

这里我是在 GitHub 上新建一个仓库,并将自己之前写的一个开发环境上传当做这里的模板进行测试的。
基于 Webpack5 搭建 Vue2 后台开发环境

// 存储模板地址
const templates = {
  "vue2-admin": {
    // 仓库地址
    url: "https://github.com/3068495230/vue2-admin.git",
    // 仓库下载地址,格式为:仓库地址:用户名/仓库名#分支名
    downloadUrl: "github:3068495230/vue2-admin#master",
    description: "Webpack5 + Vue2 + Element-ui + Sass 后台开发模板",
  },
};
  1. 修改 run list 命令

image.png

2. 下载模板(download-git-repo/clone-repo)

这里依据个人情况选在不同插件,能够直接下载仓库内容的插件有很多,可以上 NPM 寻找适合的。
也可以使用 git-clone 或 download 这两个插件,我看了看 clone-repo 的源码发现其内部最后就是调用 git-clone 进行 git 克隆,或是使用 download 直接通过 HTTP 进行下载。

1. 使用 download-git-repo 下载

NPM 地址:

www.npmjs.com/package/dow…

  1. 安装

npm i download-git-repo

  1. 引入后使用

download-git-repo 仅支持以下三个仓库源:

  • GitHub
  • GitLab
  • Bitbucket
// 引入
const download = require('download-git-repo')
// 使用 download-git-repo 下载模板
download(
  // 下载目标,格式为:仓库地址:用户名/仓库名字#分支
  'https://github.com:userName/storeName#master',
  // 下载完成后的项目名称,也就是文件夹名
  'projectName',
  {
    // 以克隆形式下载
    clone: true,
  },
  // 下载结束后的回调
  (err) => {
    // 如果错误回调不存在,就表示下载成功了
    console.log(err ? `下载失败!${err}` : "下载成功!");
  }
);
  1. 现在输入命令:

run init vue2-admin demo

我们的项目目录下就会出现一个 demo 文件夹,里面内容就是我们自己的模板。
image.png

2. 使用 clone-repo 下载

NPM 地址:

www.npmjs.com/package/clo…

  1. 安装

npm i clone-repo

  1. 使用

clone-repo 是国内大佬基于 download-git-repo 3.0.2 版本扩展开发的,与 download-git-repo 不同的是 clone-repo 会返回一个 Promise,且 clone-repo 支持以下四个仓库源:

  • GitHub
  • GitLab
  • Gitee
  • Bitbucket
// 引入
const downloa = require('clone-repo')
// 使用
download("gitee:用户名/仓库名:分支名", "projectName", {
  // 以克隆形式下载
  clone: true,
  // 完成回调
}).then((err) => {
  console.log(err);
});

四、使用 inquirer 和 handlebars 采集处理用户信息

1. 命令行交互 inquirer

能够与用户在命令行进行参数选择交互。

  1. 安装

npm i inquirer

  1. 使用

将其放在 download 的下载回调中。

inquirer.prompt([
  {
    // 输入类型
    type: "input",
    // 字段名称
    name: "name",
    // 提示信息
    message: "请输入项目名称",
  },
  {
    // 输入类型
    type: "input",
    name: "description",
    message: "请输入项目简介",
  },
  {
    type: "input",
    name: "author",
    message: "请输入作者名称",
  },
])
// 获取输入结果
.then((answers) => {
  console.log(answers.author);
});
  1. 效果:

image.png

2. 模板引擎 handlebars

能够读取当前项目下的文件,并重新写入。

  1. 安装

npm i handlebars

  1. 修改模板的 package.json

注意哈,这里是修改模板的配置文件,而不是当前项目的配置文件。

// 修改模板中的 name description author
"name": "{{ name }}",
"description": "{{ description }}",
"author": "{{ author }}",
  1. 使用
// 把采集到的用户数据解析替换到 package.json 文件中
// 使用 fs 获取下载到的模板中额 package.json 配置文件
const packageContent = fs.readFileSync(
  `${projectName}/package.json`,
  "utf8"
);
// 使用 handlebars 编译这个文件为渲染函数
const packageResult = handlebars.compile(packageContent)(answers);
console.log(packageResult);

控制台会输出:
到这一步不要急着看下载下来的项目中的 package.json 文件有无被修改!还没写入呢...
image.png

  1. 写入配置文件中

依然使用 fs 模块中的 .writeFileSync() 进行文件写入。

// 把采集到的用户数据解析替换到 package.json 文件中
// 保存下载下来的模板 package.json 配置文件路径
const packagePath = `${projectName}/package.json`;
// 使用 fs 获取下载到的模板中额 package.json 配置文件
const packageContent = fs.readFileSync(packagePath, "utf8");
// 使用 handlebars 编译这个文件为渲染函数
const packageResult = handlebars.compile(packageContent)(answers);
// 将修改后配置写入下载下来的模板中
fs.writeFileSync(packagePath, packageResult);
console.log("初始化模板成功!");

现在来看下载下来的模板中的 package.json 中的配置信息:

  1. 控制台输出:

image.png

  1. 模板配置文件:

image.png

五、使用 ora 增加下载中 loading 效果

  1. 安装

npm i ora

  1. 因其 ora 最新版只能使用 import 来导入,所以要设置当前项目的默认包管理为 ESModule。
// 在 package.json 文件中,添加这行。
"type": "module",
  1. 修改包引入

将 require 引入方式全部改为 import 方式。

// 拿到 Command 对象
import { program } from "commander";
// 引入 clone-repo
import download from "download-git-repo";
// 引入模板引擎 handlebars
import handlebars from "handlebars";
// 引入 node 文件处理
import fs from "fs";
// 引入命令行交互 inquirer
import inquirer from "inquirer";
// 引入 ora 下载中美化样式
import ora from "ora";
// 初始化 ora
const loading = ora("模板下载中...");
  1. 使用

分别在模板下载开始前,下载中,下载完后调用 ora 的 start()、fail()、succeed() 方法。

// 添加下载中样式,开始
loading.start();

// 调用 ora 下载失败方法,进行提示
loading.fail("下载失败:");

// 调用 ora 下载成功方法,进行提示
loading.succeed("下载成功!");

六、使用 chalk 和 logSymbols 增加文本样式

1. 字体美化 chalk

chalk 能够自定义使输出的命令行字体颜色。

  1. 安装

npm i chalk

  1. 使用

在模板下载失败处,和文件写入后的地方调用 chalk 输出多色文本。

// 前面代码省略...
// 调用 ora 下载失败方法,进行提示
loading.fail("下载失败:");
// 输出红色警告字体告知用户模板下载失败
console.log(logSymbols.error, chalk.red("模板下载失败!"));
console.log("错误原因:", err);

// 前面代码省略...
// 将修改后配置写入下载下来的模板中
fs.writeFileSync(packagePath, packageResult);
// chalk 内部并没有内置橙色,所以需要我们自己使用 hex 生成对应颜色字体,再去输出
// 以橙色字体提示用户模板已经下载完成
const log = chalk.hex("#FFA500");
// 模板初始化成功后输出
console.log(logSymbols.success, log("模板初始化成功!"))

2. 日志符号 logSymbols

logSymbols 能够在控制台输出指定的日志符号。

  1. 安装

npm i log-symbols

  1. 使用

通过调用 logSymantec 的 success 和 error 输出成功与失败的日志符号。

// 输出红色警告字体告知用户模板下载失败
console.log(logSymbols.error, chalk.red("模板下载失败!"));
console.log("错误原因:", err);

// 以橙色字体提示用户模板已经下载完成
const log = chalk.hex("#FFA500");
// 模板初始化成功后输出
console.log(logSymbols.success, log("模板初始化成功!"));

下载失败提示:

image.png

下载成功提示:

image.png

七、npm 发包

  1. 上 NPM 官网注册一个账号,官网:

www.npmjs.com/~achens

  1. 上 NPM 搜索看有无重名包。
  2. 把 package.json 中的 name 修改为发布到 NPM 上的包名。

这一点适合本地项目名称无关的。

  1. 打开同志太,执行登录命令:

npm login

  1. 登陆成功以后,在项目下执行发布命令:

npm publish

  1. 进行验证并下载我们自己的包

// 取消本地连接的全局指令 npm unlink // 安装我们自己的包 npm i achens-cli

测试

在本地安装后使用 unlink 解绑后,照样可以使用命令 s(我把 run 换为了 s)。
搜狗截图22年02月15日2248_1.png
换另一台电脑,也可以正常安装使用。
B3F2A07135643A3D4C7926A416B1F5A0.jpg


原文地址:www.yuque.com/xiaochens