Skip to content

自定义vue脚手架

项目初始化

创建项目,通过npm init初始化。添加一个bin/index.js文件,在package.json当中指定bin字段,指向bin/index.js文件

js
#!/usr/bin/env node
console.log("this is modify-cli");

执行命令npm link,我这个库的名称为modify-cli,在cmd当中执行modify-cli命令,就会执行bin/index.js文件

常用的库

commander

commander 命令行工具,自定义选项option与命令command

js
#!/usr/bin/env node
const {program} = require("commander");
program.name("modify-cli").usage("<command> [options]");

program
  .option("-d, --debug", "output extra debugging")
  .option("-s, --small", "small pizza size")
  .option("-p, --pizza-type <type>", "flavour of pizza");

program
  .command("clone <source> [destination]")
  .description("clone a repository into a newly created directory")
  .action((source, destination) => {
    // action接收到的参数分别是source和destination
    console.log("clone command called", source, destination);
  });

program.parse(process.argv);

const options = program.opts();

console.log("options:", options);

chalk

chalk 命令行打印美化

IMPORT: Chalk 5 is ESM. If you want to use Chalk with TypeScript or a build tool, you will probably want to use Chalk 4 for now.(Chalk 5是ES Module。如果您想使用Chalk与TypeScript或构建工具,现在可能 want to use Chalk 4)

js
const chalk = require('chalk');
console.log(chalk.blue.bold.underline.bgWhite('Welcome Use Modify-Cli!'));

Inquirer.js

Inquirer.js 用户交互工具包

和chalk一样,最新的v9.0也是es module,所以还是用8.0的版本。

js
const inquirer = require('inquirer');

inquirer
  .prompt([
    {
      type: 'input',
      name: 'name',
      message: 'What is your name?',
      default: 'modify-cli'
    },
    {
      type: 'confirm',
      name: 'confirm',
      message: 'Are you sure?',
      default: false
    }
  ])
  .then((answers) => {
    console.log('answers:', answers);
  })
  .catch((error) => {
    if (error.isTtyError) {
      // Prompt couldn't be rendered in the current environment
    } else {
      // Something else went wrong
    }
  });

ora

ora loading效果

js
const ora = require('ora');
const spinner = ora('Loading...').start();

setTimeout(() => {
  spinner.text = 'Downloading...';
  spinner.color = 'red';
}, 2000);

setTimeout(() => {
  // spinner.succeed("Downloading done!");
  spinner.fail('Loading failed!');
}, 4000);

git-clone

figlet

figlet 打印艺术字

js
const figlet = require('figlet');
figlet('Modify-Cli', function (err, data) {
  if (err) {
  }
  console.log(data);
});

fs-extra

fs-extra 原生fs的替代品

脚手架代码

简单实现一个modify-cli create my-project

js
#!/usr/bin/env node
const {program} = require("commander");
const chalk = require("chalk");
const inquirer = require("inquirer");
const ora = require("ora");
const figlet = require("figlet");
const fs = require("fs-extra");
const path = require("path");
const gitClone = require("git-clone");
const {read} = require("fs");

const gieResponse = {
  vue: "https://gitee.com/iamkun/dayjs.git",
  react: "https://gitee.com/iamkun/dayjs.git",
  "react-ts": "https://gitee.com/iamkun/dayjs.git",
  "vue-ts": "https://gitee.com/iamkun/dayjs.git",
};

// 首行提示
program.name("modify-cli").usage("<command> [options]");
// 设置版本号
program.version(`v${require("../package.json").version}`);
// 监听 --help 执行
program.on("--help", () => {
  console.log(
    `\r\nRun ${chalk.cyan(
      "modify-cli <command> --help"
    )} for detailed usage of given command\r\n`
  );
});
// 添加命令
program
  .command("create <project-name>")
  .description("create a new project")
  .action(async (name) => {
    // 判断是否存在
    const targetPath = path.join(process.cwd(), name);
    const isExist = fs.existsSync(targetPath);
    if (isExist) {
      const answers = await inquirer.prompt([
        {
          type: "confirm",
          name: "overwrite",
          message: "当前文件夹已存在,是否覆盖",
          default: false,
        },
      ]);
      if (answers.overwrite) {
        // 覆盖(先做删除)再做拉取
        fs.removeSync(targetPath);
      } else {
        console.log(chalk.red.underline("请更换一个项目名称,再重新创建"));
        return;
      }
    }

    inquirer
      .prompt([
        {
          type: "list",
          name: "template",
          message: "请选择技术框架",
          default: "vue",
          choices: ["vue", "react"],
        },
        {
          type: "confirm",
          name: "ts",
          message: "是否使用 typescript",
          default: true,
        },
      ])
      .then((answers) => {
        // 通过选择的结果,拉取对应的模板
        const {template, ts} = answers;
        const key = ts ? `${template}-ts` : template;
        const gitUrl = gieResponse[key];
        const spinner = ora(`${name} Code Loading...`).start();
        gitClone(gitUrl, name, {checkout: "master"}, (err) => {
          if (err) {
            console.log(chalk.red(err));
            spinner.fail(`${name} 项目创建失败!`);
          } else {
            spinner.succeed(`${name} 项目创建成功!`);
            // 把 .git 目录删除,把 .github 目录删除
            fs.removeSync(path.join(targetPath, ".git"));
            fs.removeSync(path.join(targetPath, ".github"));
            console.log(chalk.green(`\r\n  cd ${name}`));
            console.log(chalk.green("  npm install"));
            console.log(chalk.green("  npm run dev"));

            figlet("Modify-Cli!", function (err, data) {
              if (err) {
                console.dir(err);
                return;
              }
              console.log(data);
            });
          }
        });
      });
  });
program.parse(process.argv);

项目发布

modify-cli npm地址

modify-cli github地址

发布时先切换到官方源

bash
npm config set registry https://registry.npmjs.org
# npm config set registry https://registry.npm.taobao.org
# 在发布之前可以执行查看发布的结果
# npm pack
npm login
npm publish

使用脚手架

bash
npm i modify-cli -g
modify-cli create my-project

By Modify.