前端开发系列132-进阶篇之脚手架Yue-cli的实现01-commander模块

这是系列文章`前端脚手架实现`的第一篇,主要讲解脚手架工具中的核心模块命令行参数解析功能的实现,重点讲解 Node 模块 [commander]()的使用。

在前端开发中我们已经接触过各种各样的脚手架工具,从Yeomanvue-clidva-cli等,这几篇文章将讲解脚手架工具的核心功能以及具体实现细节,本文探讨哪些功能呢?我们先随便拿一个现成的脚手架工具vue-cli来作为参考。

当我们通过npm install -g @vue/cli 来全局安装 @vue/cli之后,就可以在终端中使用 vue 指令了。

bash 复制代码
wendingding:vue-test wendingding$ vue --version
@vue/cli 4.3.1
wendingding:vue-test wendingding$ vue --help
Usage: vue <command> [options]

Options:
  -V, --version                              output the version number
  -h, --help                                 output usage information

Commands:
  create [options] <app-name>                create a new project powered by vue-cli-service
  add [options] <plugin> [pluginOptions]     install a plugin and invoke its generator in an already created project
  invoke [options] <plugin> [pluginOptions]  invoke the generator of a plugin in an already created project
  inspect [options] [paths...]               inspect the webpack config in a project with vue-cli-service
  serve [options] [entry]                    serve a .js or .vue file in development mode with zero config
  build [options] [entry]                    build a .js or .vue file in production mode with zero config
  ui [options]                               start and open the vue-cli ui
  init [options] <template> <app-name>       generate a project from a remote template (legacy API, requires @vue/cli-init)
  config [options] [value]                   inspect and modify the config
  outdated [options]                         (experimental) check for outdated vue cli service / plugins
  upgrade [options] [plugin-name]            (experimental) upgrade vue cli service / plugins
  migrate [options] [plugin-name]            (experimental) run migrator for an already-installed cli plugin
  info                                       print debugging information about your environment

  Run vue <command> --help for detailed usage of given command.
  
  wendingding:vue-test wendingding$ abc 
  -bash: abc: command not found

观察上面的终端命令和显示输出,我们总共输入了三个命令 $ vue --version 查看版本信息 $ vue --help 获取帮助信息 $ abc 随意输入的指令,显示command not found该指令不存在。

本文将专注实现上面的功能,假设我们自己实现的脚手架名为Yue-cli那么当我在终端中使用Yue-cli的时候,系统应该认识该指令,且能够获取当前脚手架的版本并能够获取帮助信息,下面给出具体的实现过程。
项目准备

在电脑中新创建文件夹,假设为 Yue-cli ,在该文件夹下面执行下面的命令先做一些准备工作。

bash 复制代码
npm init -y                         # 初始化package.json
npm install eslint husky --save-dev # eslint是负责代码校验工作,husky提供了git钩子功能
npx eslint --init                   # 初始化eslint配置文件,用于语法检查

目录结构

参考下面的目录结构来创建文件和文件夹,关键。

bash 复制代码
.
├── bin
│   └── www            <!-- 全局命令执行的根文件 -->
├── node_modules       <!-- 安装的包文件 -->
│   ├── @babel
│   ...
│   └── yaml
├── package-lock.json
├── package.json       <!-- 元信息文件 -->
├── src       
│   └── main.js        <!-- 项目入口文件 -->
│── .huskyrc           <!-- git hook -->
│── .eslintrc.json     <!-- 代码规范校验文件 -->
└── util
    └── constants.js   <!-- 该文件用于存放公共常量数据 -->

配置和链接

❏ 配置 package.json 校验src文件夹下的代码

json 复制代码
"scripts": {
    "lint":"eslint src"
}

❏ 配置 husky 文件,当使用git提交前校验代码是否符合规范

json 复制代码
{
  "hooks": {
    "pre-commit": "npm run lint"
  }
}

❏ 链接全局包,编写 package.json 文件设置在终端中执行 Yue-cli 时调用 bin 目录下的 www 文件

json 复制代码
 "bin": {
        "Yue-cli": "./bin/www"
    },

bin 目录下面的 www 文件设置使用 main.js 作为入口文件,并且以 node 环境 执行此文件

javascript 复制代码
#! /usr/bin/env node
require('../src/main.js');

❏ 链接包到全局环境下使用

bash 复制代码
npm link

到现在这一步,我们就已经可以成功的在命令行中使用Yue-cli命令了,当在终端中执行Yue-cli命令的时候其内部会执行main.js文件,如果我们在该文件中加上一行打印代码console.log("hello Yue-cli"),那么在终端中可以看到对应的输出。
使用 commander 解析命令行参数

commander 模块可以帮助我们自动的生成 help 信息,解析选项参数大家可以点击到npmjs网站查看包模块的详细情况。

先在系统中安装 commander 模块

bash 复制代码
npm install commander

在入口文件 main.js 文件中引入该模块并测试

arduino 复制代码
const program = require("commander")

// process.argv就是用户在命令行中传入的参数
program.version('1.0.1').parse(process.argv);   

此时,我们终端使用 Yue-cli --help 或者是 Yue-cli --version 就能看到对应的提示信息。

bash 复制代码
wendingding$ Yue-cli --version
1.0.1

wendingding$ Yue-cli --help
Usage: Yue-cli [options]

Options:
  -V, --version  output the version number
  -h, --help     display help for command

注意:脚手架的这个版本号应该使用的是当前cli项目的版本号,我们需要动态的来获取,具体实现方式是直接把package.json 文件中的 version 字段值导入到main.js文件中直接使用即可。

javascript 复制代码
 const { name, version } = require("../package");

另外,当我们使用脚手架工具的时候,往往不同的指令会对应不同的功能,譬如vue create app的作用是创建项目,而vue ui的作用是开启一个服务以 UI 界面的方式来创建项目,也就是说不能的 命令 它的功能、别名以及使用示例这些信息都是不同的,如何实现呢?

commander 模块我为了提供了对应的方法,下面给出具体的示例(演示使用,实际功能暂欠缺)。

javascript 复制代码
    /* main.js 文件的内容 */
    /* 0.导入模块 */
    const program = require("commander")

    /* 导入常量(package 包中的名称和版本号) */
    const { name, version } = require("../package");

    /* 1.Yue-cli crete */
    program
        /*  命令的名称 */
        .command("create") 
        /*  命令的别名 */
        .alias("c") 
        /* 命令的描述 */
        .description("create a project whit Yue-cli....") 
        /* 该命令的具体功能(动作) */
        .action(() => { 
            console.log(`执行 action-> create`);
        });

    /* 2.Yue-cli config */
    program
        .command("config")
        .alias("conf")
        .description("config info....")
        .action(() => { 
            console.log(`执行 action-> config`);
        });

    /* 3.Yue-cli xxx  (其它未定义指令) */
    program
        .command("*")
        .alias("")
        .description("command not found")
        .action(() => { 
            console.log(`执行 action-> nothing`);
        });

    /* 4.示例信息 */
    const examples = [
        "Yue-cli create <project-name>",
        "Yue-cli config get <k>",
        "Yue-cli config set <k> <v>"
    ];

    // 5.监听用户的help 事件
    program.on('--help', () => {
        /* 当终端输入 Yue-cli --help指令的时候打印nExamples信息 */
        console.log('\nExamples:');
        examples.forEach(example => console.log(`   ${example}`))
    });

    /* 6.版本信息 + 命令行参数解析 */
    program.version(`version = ${version}`).parse(process.argv);

我们来看看此时,我们的工具拥有了哪些功能?

bash 复制代码
wendingding$ Yue-cli --help
Usage: Yue-cli [options] [command]

Options:
  -V, --version   output the version number
  -h, --help      display help for command

Commands:
  create|c        create a project whit Yue-cli....
  config|conf     config info....
  *               command not found
  help [command]  display help for command

Examples:
   Yue-cli create <project-name>
   Yue-cli config get <k>
   Yue-cli config set <k> <v>

wendingding$ Yue-cli --version
version = 1.0.1

wendingding$ Yue-cli create myapp
执行 action-> create

wendingding$ Yue-cli config
执行 action-> config

wendingding$ Yue-cli c app
执行 action-> create

写到这里,脚手架工具的基本提示功能就已经实现了,但代码较长且脚手架的指令肯定不止 createconfig 这么两个,因此这里适当调整下代码结构让其可维护性更高一些。

javascript 复制代码
    /* main.js 文件的内容 */
    /* 导入模块 */
    const program = require("commander");
    /* 导入常量(package 包中的名称和版本号) */
    const { name, version } = require("../util/constants");

    /* 组织映射结构 */
    const actions = {
        create: { // 项目创建(初始化)指令
            description: 'create project with Yue-cli',
            alias: 'c',
            examples: [
                'Yue-cli create <project-name>',
            ],
        },
        config: { // 设置项目配置文件指令
            description: 'config info',
            alias: 'conf',
            examples: [
                'Yue-cli config get <k>',
                'Yue-cli config set <k> <v>',
            ],
        },
        '*': {
            description: 'command not found',
            alias: '',
            examples: [],
        },
    };

    Object.keys(actions).forEach((action) => {
        program
            /* 命名的名称 */
            .command(action)
            /* 命名的别名 */
            .alias(actions[action].alias)
            /* 命令的描述信息 */
            .description(actions[action].description)
            /* 命令的任务(功能) */
            .action(() => { // 动作
                console.log(`执行 action->`, action);
            });
    });

    // 监听用户的help 事件
    program.on('--help', () => {
        console.log('\nExamples:');
        Reflect.ownKeys(actions).forEach((action) => {

            actions[action].examples.forEach((example) => {
                console.log(`  ${example}`);
            });
        });
    });

    /* 版本信息 + 命令行参数解析 */
    program.version(`version = ${version}`).parse(process.argv);
相关推荐
吃杠碰小鸡10 分钟前
高中数学-数列-导数证明
前端·数学·算法
kingwebo'sZone15 分钟前
C#使用Aspose.Words把 word转成图片
前端·c#·word
xjt_090135 分钟前
基于 Vue 3 构建企业级 Web Components 组件库
前端·javascript·vue.js
我是伪码农1 小时前
Vue 2.3
前端·javascript·vue.js
夜郎king1 小时前
HTML5 SVG 实现日出日落动画与实时天气可视化
前端·html5·svg 日出日落
辰风沐阳1 小时前
JavaScript 的宏任务和微任务
javascript
夏幻灵2 小时前
HTML5里最常用的十大标签
前端·html·html5
冰暮流星2 小时前
javascript之二重循环练习
开发语言·javascript·数据库
Mr Xu_2 小时前
Vue 3 中 watch 的使用详解:监听响应式数据变化的利器
前端·javascript·vue.js
未来龙皇小蓝2 小时前
RBAC前端架构-01:项目初始化
前端·架构