新手从零搭建前端脚手架

11 阅读4分钟

一. 创建目录 & 文件 & package

  • 整体目录 结构如下

    my-cli/
    ├── bin/
    │   └── cli.js         # 脚手架入口
    ├── templates/         # 模板目录
    │   └── project/       # 项目模板
    │       ├── _package.json
    │       └── src/
    │           └── index.js
    ├── lib/
    │   ├── create.js      # 项目创建逻辑
    │   └── utils.js       # 工具函数
    └── package.json
    

第一: 在 my-cli 项目目录中,创建bin目录以及cli.js

  • cli.js 文件中

    #!/usr/bin/env node
    
    console.log(process.argv);
    

    其中 #!/usr/bin/env node 这行代码的作用就是告诉系统(不同系统 Unix/Linux/macOS),让用户无需显式输入 node script.js,只需 ./script.js 即可运行

    另外 process.argv 来获取命令中的参数,(process 是node中一个全局变量,提供了有关当前 Node.js进程的信息并对其进行控制)

第二: 在 my-cli 项目目录中,使用 npm init 生成 package.json 文件

{
  "name": "mycli",
  "version": "1.0.0",
  "main": "index.js",
  "bin": {
    "mycli": "./bin/cli.js"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
}

第三: 在当前项目目录中,使用 npm link (如果你是在本地开发,需要将包链接到全局)

第四: 在命令行中执行代码 mycli,可以看到cli.jsconsole.log信息

二. 命令行库(轻松定义命令、选项、参数以及处理用户输入) commander

  • 安装 commander 依赖
// 安装依赖
npm install commander
  • 通过 command 配置命令
const program = require("commander");

program
  .command('create <project> [other...]')
  .alias('c')
  .description('创建项目')
  .action((project, other) => {
     // 命令行执行逻辑代码
     // 这边是 project 
     console.log('创建项目', project, other);
  })

.command()的第一个参数为命令名称。命令参数可以跟在名称后面,也可以用.argument()单独指定。参数可为必选的(尖括号表示)、可选的(方括号表示)或变长参数(点号表示,如果使用,只能是最后一个参数)。

.argument() 表示 参数定义,跟.command()的一样

.alias() 表示别名

.description() 表示 当前命令描述

.action() 表示 回调函数

.option() 表示 定义选项,参数: 短选项名称(-后面接单个字符)和一个长选项名称(--后面接一个或多个单词),使用逗号、空格或|分隔。并且短和长选项名称,后面也可以带上参数 可为必选的(尖括号表示)、可选的(方括号表示)或变长参数(点号表示,如果使用,只能是最后一个参数)

program
  .command('create <project> [other...]')
  .alias('c')
  .description('创建项目')
  .option('--first', 'display just the first substring')
  .action((project, other) => {
     // 命令行执行逻辑代码
     // 这边是 project 
     console.log('创建项目', project, other);
  })

program
  .version('0.1.0')
  .argument('<username>', 'user to login')
  .argument('[password]', 'password for user, if required', 'no password given')
  .action((username, password) => {
    console.log('username:', username);
    console.log('password:', password);
  });

program.command('split')
  .description('Split a string into substrings and display as an array')
  .argument('<string>', 'string to split')
  .option('--first <char>', 'display just the first substring')
  .option('-s, --separator <char>', 'separator character', ',')
  .action((str, options) => {
    console.log('string:', str, 'options:', options);
    const limit = options.first ? 1 : undefined;
    console.log(str.split(options.separator, limit));
  });
执行--> mycli c CC 123 或者 mycli create CC 123
打印--> 创建项目 CC [ '123' ]

执行--> mycli split aaa --first ceshi
打印--> string: aaa options: { separator: ',', first: 'ceshi' }

三. 命令行问答式交互库 inquirer

  • 安装 inquirer
// 安装
npm install @inquirer/prompts

通过 inquirer.prompt() 来实现。prompt 函数接收一个数组,数组的每一项都是一个询问项,下面是常用的配置项。

  • type:提问的类型,常用的有

    类型描述示例
    input文本输入{ type: 'input', name: 'name', message: '姓名:' }
    number数字输入{ type: 'number', name: 'age', message: '年龄:' }
    confirm是/否选择{ type: 'confirm', name: 'agree', message: '同意协议?' }
    list单选列表{ type: 'list', name: 'color', choices: ['红', '绿', '蓝'] }
    checkbox多选框{ type: 'checkbox', name: 'tools', choices: ['Git', 'Docker', 'K8s'] }
    password密码输入{ type: 'password', name: 'pwd', mask: '*' }
    select下拉框{ type: 'select', name: 'xiala', mask: '*' }
  • name:存储当前问题答案的变量;

  • message:问题的描述;

  • default:默认值;

  • choices:列表选项,在某些type下可用;

  • validate:对用户的答案进行校验;

  • filter:对用户的答案进行过滤处理,返回处理后的值。

  • 等等

image.png image.png image.png image.png image.png image.png image.png image.png

例子:

const inquirer = require('inquirer');

inquirer.prompt([
  {
    type: 'input',
    name: 'username',
    message: '用户名:',
    validate: input => input.trim() !== '' || '不能为空'
  },
  {
    type: 'password',
    name: 'password',
    mask: '•',
    message: '密码:',
    validate: input => input.length >= 6 || '至少6个字符'
  },
  {
    type: 'list',
    name: 'role',
    message: '角色:',
    choices: ['用户', '管理员', '开发者']
  },
  {
    type: 'checkbox',
    name: 'skills',
    message: '选择技能:',
    choices: ['JavaScript', 'Python', 'Java', 'Go']
  }
]).then(answers => {
  console.log('\n注册信息:');
  console.log('用户名:', answers.username);
  console.log('角色:', answers.role);
  console.log('技能:', answers.skills.join(', '));
});

三. 下载远程项目代码库 download-git-repo

  • 安装 download-git-repo
npm install download-git-repo
download('direct:'+config.framworkPath[answer.framwork], project, { clone: true },function (err) {console.log(err ? 'Error' : 'Success') })

四. 命令行loading库ora

npm install ora@5
const ora = require("ora");
const spinner = ora().start('downloading');
setTimeOut(()=>{
    spinner.succeed("download success");
    // spinner.fail("download fail");
})
image.png

五. 命令行样式渲染库 chalk

npm install chalk@4
const chalk = require("chalk");
console.log( chalk.blue('cd project') );
console.log( chalk.green.bold('npm install') );
console.log( chalk.rgb(123, 45, 67)('npm run dev') );
image.png