likes
comments
collection
share

学习脚手架开发

作者站长头像
站长
· 阅读数 11

在开发脚手架在前,需要现简单配置一个 node 环境

目前有些第三方包使用 ES Modules,有的包又使用 CommonJS,这就导致了在 node 中使用 ES Modules 时,无法使用 require 引入 CommonJS

这需要借助 rollup 之类的打包工具来实现了

const commonjs = require("rollup-plugin-commonjs");

export default {
  input: "src/index.js",
  output: {
    format: "umd",
    file: "bin/index.js",
    banner: "#! /usr/bin/env node",
  },
  plugins: [commonjs()],
};

无需在 package.json 中使用指定 "type": module

打包时运行 rollup --bundleConfigAsCjs --config rollup.config.js 即可:

  • bundleConfigAsCjs 作用是强制 rollup 把配置文件转换成 CommonJS
  • --config 指定配置文件

其中 output 属性 banner 的作用是在打包后的文件头部添加 #! /usr/bin/env node,这样就可以直接执行打包后的文件了

commander 使用

注册命令

我们用 commander 来解析命令行参数,通过 command 方法来注册命令

import commander from "commander";

const program = new commander.Command();
program
  .command("init")
  .description("init project")
  .action(() => {
    // 执行初始化操作
    // ...
  });

解析命令行参数

通过 parse 方法来解析命令行参数,不过需要注意的是,需要放在程序的最后面,否则会出现 commander 无法解析的情况

program.parse(process.argv);

监听全局命令

commander 可以通过 program.on("command:*", () => {}) 来监听全局命令

通过 command 函数注册的命令,如果没有匹配到,就会触发 command:* 事件

const program = new commander.Command();
program.on("command:*", function (operands) {
  console.error(operands);
  program.outputHelp();
  process.exit(1);
});

拉远程代码

在注册命令之前我们需要提供 -v 或者 --version 的参数,供用户查看脚手架的版本

const pkg = require("../package.json");

const program = new commander.Command();
program.version(pkg.version);

在命令行执行 node <index.js> 就可以查看当前脚手架的版本了

接下来,我们通过注册 initupdate 命令实现拉取远程代码的功能

program.command("init").description("初始化项目").action(action);
program.command("update").description("更新项目").action(action);

我们把 action 函数单独提取出来,方便后面扩展,不同的人可以实现不同的功能

创建

使用 fs-extra 代替原生的 fs 模块,可以更方便的操作文件

  • ensureDir:创建目录,如果目录不存在则创建,如果存在则不做任何操作
  • pathExists:判断文件或目录是否存在
  • emptyDir:清空目录

当前命令执行的目录,可以通过 process.cwd() 获取,然后在当前目录下创建一个新目录,用于存放拉取的远程代码

在拉取代码前,先判断一下代码是否已经拉取过了,如果拉取过了,更新就行了

import fs from "fs-extra";
const dir = process.cwd() + "/resources";
await fs.ensureDir(dir);
const isExist = await fs.pathExists(dir + "/.git");
if (isExist) {
  // 代码存在
} else {
  // 代码不存在
}

通过 fs.pathExists 判断目录下是否存在 .git 目录,如果存在则说明代码已经拉取过了,否则就拉取代码

拉取代码前,先清空 /resources 目录,然后再拉取代码

使用内置 child_process 库的 exec 来执行命令

exec 第一个参数是执行的命令,通过空格分隔,第二个参数是配置项,其中 cwd 是执行命令的目录

const { exec } = require("child_process");
await fs.emptyDir(process.cwd() + "/resources");
exec("git clone xxx .", { cwd: dir });

如果代码已存在,通过 exec 执行 git pull 命令来更新代码

const { exec } = require("child_process");
exec("git pull", { cwd: dir });

这样就已经实现拉取远程代码的功能了

命令行选择效果

实现命令行选择效果,可以使用 inquirer

不过在使用这个库时,最好使用 8.0.0 的版本,最新的 9.0.0 的版本不支持 CommonJS,这在 node 开发中很难受

inquirer@8.0.0文档

安装完之后,使用 inquirer.prompt 方法来实现选择效果

prompt 方法接收一个数组,数组中的每一项都是一个问题对象,问题对象中的 type 属性指定问题的类型,message 属性指定问题的描述,name 属性指定问题的名称,default 属性指定问题的默认值,choices 属性指定问题的选项

然后 prompt 结果,会按照问题的顺序收集在 answers 对象中,通过 Promisethen 方法获取,通过 catch 方法捕获错误

inquirer
  .prompt([
    {
      type: "input",
      message: "请输入项目名称",
      name: "name",
      default: "my-project",
    },
    {
      type: "list",
      message: "请选择项目类型",
      name: "type",
      choices: ["vue", "react", "node"],
    },
  ])
  .then((answer) => {
    console.log(answer); // { name: 'my-project', type: 'vue' }
  });

它还有一些其他的用法,可以参考文档

当我们拿到用户的选择之后,就可以根据用的选择去做不同的操作了

在控制台中打印出各种文本

使用 figlet 这个库可以在控制台打印出各种好玩文本

打印出 Hello World

figlet("Hello World", function (err, data) {
  if (err) {
    console.log("Something went wrong...");
    console.dir(err);
    return;
  }
  console.log(data);
});

效果

  _   _      _ _        __        __         _     _
 | | | | ___| | | ___   \ \      / /__  _ __| | __| |
 | |_| |/ _ \ | |/ _ \   \ \ /\ / / _ \| '__| |/ _` |
 |  _  |  __/ | | (_) |   \ V  V / (_) | |  | | (_| |
 |_| |_|\___|_|_|\___/     \_/\_/ \___/|_|  |_|\__,_|

还可以指定字体

figlet.text(
  "Boo!",
  {
    font: "Ghost",
    horizontalLayout: "default",
    verticalLayout: "default",
    width: 80,
    whitespaceBreak: true,
  },
  function (err, data) {
    if (err) {
      console.log("Something went wrong...");
      console.dir(err);
      return;
    }
    console.log(data);
  }
);

效果

.-. .-')                            ,---.
\  ( OO )                           |   |
 ;-----.\  .-'),-----.  .-'),-----. |   |
 | .-.  | ( OO'  .-.  '( OO'  .-.  '|   |
 | '-' /_)/   |  | |  |/   |  | |  ||   |
 | .-. `. \_) |  |\|  |\_) |  |\|  ||  .'
 | |  \  |  \ |  | |  |  \ |  | |  |`--'
 | '--'  /   `'  '-'  '   `'  '-'  '.--.
 `------'      `-----'      `-----' '--'

在控制台中打印出各种颜色的文本

使用 chalk 这个库可以在控制台打印出各种颜色的文本

console.log(chalk.yellow("hello world"));
console.log(chalk.bold.red("------------------------------------"));
console.log(chalk.bold.green("version: 1.0.0"));

效果:

学习脚手架开发