从零开始使用node.js制作一个脚手架

从零开始使用node.js制作一个脚手架

🎉🎉🎉欢迎来到我的博客,我是一名自学了2年半前端的大一学生,熟悉的技术是JavaScript与Vue.目前正在往全栈方向前进, 如果我的博客给您带来了帮助欢迎您关注我,我将会持续不断的更新文章!!!🙏🙏🙏

1.介绍脚手架

脚手架是用于生成一个项目的基本结构的工具,它可以帮助我们构建Vue,React等项目的基本结构,让我们不用自己建立项目的结构简便了我们的开发同时也规范了项目的结构.

我们创建vue项目时就会使用 npm create vite@latest来创建,这个命令本质上就是帮我们安装一个create-vite的包并运行它,这个包就是创建这个项目的脚手架.生成项目的结构一般如下所示,根据选项的不同,生成的项目结构会有一点差异,我这里以Vue3+Ts的项目结构为例.

在这里插入图片描述

脚手架的功能只有生成项目的基本结构!!!,打包代码等功能都是打包工具提供的不要弄混了.

2.准备工作

在制作脚手架之前需要先安装node.js以及一些库

node.js的安装我这里就不赘述了,网上有很多教程,我这里主要是介绍我们制作过程中会用到的第三方库.

commander => 用来进行终端操作 官网链接

chalk => 用来美化我们在终端中输出的文字 官网链接

figlet => 可以在控制台中输出艺术字 官网链接

inquirer => 用于设置问题让用户来选择 官网链接

fs-extra => fs模块的增强版,用来进行IO操作 官网链接

git-clone => 用来进行git clone操作 官网链接

ora => 用来美化控制台的加载 官网链接

npm i chalk figlet inquirer fs-extra git-clone ora

ora和chalk这两个库需要进行降级才能支持commonJS

npm i chalk@4.0.0 ora@5.0.0

3.开始制作

1.初始化项目结构

新建一个文件夹,我这里以my-cli为例,然后在vscode中打开这个文件夹.

再在终端中打开这个文件夹,输入npm init -y初始化package.json文件.

新建bin目录,在bin目录下新建index.js文件写入以下内容

#!/usr/bin/env node
console.log("Hello Node")

再去package.json中添加bin选项写入以下内容

"bin":{
	"my-cli":"/bin/index.js"
}

在bin选项里面的命令可以在终端中输入并执行对应的代码文件

在终端中输入npm link将包本地安装

接下来在终端输入上面bin中的命令my-cli就会显示Hello Node

-> my-cli
Hello Node

2.注册命令

我们通过my-cli create <项目名> 来创建项目 但目前我们还没注册这个命令,所以在终端中输入命令没用

注册命令通过以下代码

const { program } = require("commander");

program
  .command("create <app-name>")
  .description("创建一个项目")
  .action(appName=>{
	console.log("执行回调",appName)		
})
program.parse(program.argv);

通过commander库可以注册命令, <>中的是用户需要填写的项目名,用户填写的项目名称会在action回调函数中作为参数来传递也就是appName.现在在终端中输入 my-cli create aa命令后会输出执行回调 aa这四个字.

-> my-cli create aa
执行回调 aa

接下来的代码都会在这个回调函数中进行.

首先我们先要判断当前目录下有没有用户输入项目名相同的文件夹,如果有再让用户选择是否覆盖,选择是就把文件夹覆盖,否的话就退出创建.代码如下

const fs = require("fs-extra")
program
  .command("create <app-name>")
  .description("创建一个项目")
  .action(appName=>{
	const targetPath = path.join(process.cwd(), appName); // 获取当前目录
    // 判断当前目录下有没有同名文件夹
    if (fs.existsSync(targetPath)) {
        // 设置问题
      const answer = await inquirer.prompt([
        {
          message: "项目已存在,是否覆盖?", // 问题标题
          type: "confirm", // 问题类型 confirm=>yes/no
          name: "isOver",// 问题结果的变量名
          default: "false",// 是否有默认值
        },
      ]);
      // 判断用户是否选择覆盖
      if (answer.isOver) {
          // 覆盖的话就删除这个文件夹
        fs.remove(targetPath);
        console.log(chalk.blue("移除成功"));
      } else {
          // 不覆盖的话就退出创建
        return;
      }
    }	
})

如果当前目录下没有同名文件夹则进行项目结构的创建,但在创建之前还需要问几个问题,让用户选择自己需要创建的项目,在这里我就只提供Vue3和React加是否Ts的项目创建.

首先我们需要在github上创建Vue3,React,Vue3+ts,React+ts的基本项目结构仓库,我已经创建好了,大家直接用我的就好了

const projectList = {
  vue: "https://github.com/zhangruiKU/vue-template.git",
  react: "git@github.com:kfc-vme50/react-template.git",
  "react&ts": "git@github.com:kfc-vme50/react-template-ts.git",
  "vue&ts": "https://github.com/zhangruiKU/vue-template-ts.git",
};

编写问题代码

const result = await inquirer.prompt([
      {
        type: "list",
        message: "choose a framework",
        default: "vue",
        name: "framework",
        choices: [
          {
            name: "vue",
            value: "vue",
          },
          {
            name: "react",
            value: "react",
          },
        ],
      },
      {
        type: "confirm",
        message: "是否使用typescript?",
        name: "isTs",
        default: "false",
      },
    ]);
    const key = result.framework + (result.isTs ? "&ts" : ""); // 拼接项目模板的key
    const gitUrl = projectList[key]; // 通过拼接的key 获取对应项目结构的git仓库链接
    console.log(gitUrl);
    const spinner = ora("正在下载模板...").start(); // 显示加载条
	// 拉取git仓库代码
    gitClone(gitUrl, appName, { checkout: "main" }, () => {
      spinner.succeed(chalk.blue.bold("项目创建成功"));// 结束加载条并显示成功消息
        // 展示信息
      console.log(chalk.green.bold("运行以下命令以启动项目"));
      console.log("");
      console.log(chalk.green.bold(" cd ", appName));
      console.log(chalk.green.bold(" npm i"));
      console.log(chalk.green.bold(" npm run dev"));
      console.log(chalk.blue.bold(figlet.textSync("zrOvO", {})));
      console.log(chalk.blue("感谢您的使用!"));
    });

现在一个基本的脚手架就搭好了,再把版本显示,帮助显示加上就好了,代码如下

// 版本号
program.version(`${require("../package.json").version}`);
// 首行提示
program.name("zr").usage("<command> [options]");
// 监听 --help
program.on("--help", () => {
  console.log(chalk.green.bold(figlet.textSync("zrOvO", {})));
});

4.完整代码

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

const projectList = {
  vue: "https://github.com/zhangruiKU/vue-template.git",
  react: "git@github.com:kfc-vme50/react-template.git",
  "react&ts": "git@github.com:kfc-vme50/react-template-ts.git",
  "vue&ts": "https://github.com/zhangruiKU/vue-template-ts.git",
};

// 首行提示
program.name("zr").usage("<command> [options]");

// 添加命令
program
  .command("create <app-name>")
  .description("创建一个项目")
  .action(async appName => {
    const targetPath = path.join(process.cwd(), appName);
    if (fs.existsSync(targetPath)) {
      const answer = await inquirer.prompt([
        {
          message: "项目已存在,是否覆盖?",
          type: "confirm",
          name: "isOver",
          default: "false",
        },
      ]);
      if (answer.isOver) {
        fs.remove(targetPath);
        console.log(chalk.blue("移除成功"));
      } else {
        return;
      }
    }
    // 新建项目
    const result = await inquirer.prompt([
      {
        type: "list",
        message: "choose a framework",
        default: "vue",
        name: "framework",
        choices: [
          {
            name: "vue",
            value: "vue",
          },
          {
            name: "react",
            value: "react",
          },
        ],
      },
      {
        type: "confirm",
        message: "是否使用typescript?",
        name: "isTs",
        default: "false",
      },
    ]);
    const key = result.framework + (result.isTs ? "&ts" : "");
    const gitUrl = projectList[key];
    console.log(gitUrl);
    const spinner = ora("正在下载模板...").start();
    gitClone(gitUrl, appName, { checkout: "main" }, () => {
      spinner.succeed(chalk.blue.bold("项目创建成功"));
      console.log(chalk.green.bold("运行以下命令以启动项目"));
      console.log("");
      console.log(chalk.green.bold(" cd ", appName));
      console.log(chalk.green.bold(" npm i"));
      console.log(chalk.green.bold(" npm run dev"));
      console.log(chalk.blue.bold(figlet.textSync("zrOvO", {})));
      console.log(chalk.blue("感谢您的使用!"));
    });
  });

// 版本号
program.version(`${require("../package.json").version}`);

// 监听 --help
program.on("--help", () => {
  console.log(chalk.green.bold(figlet.textSync("zrOvO", {})));
});

program.parse(program.argv);

如果需要发布包的话,需要注册一个npm的账号,然后在终端进行登陆npm login,然后再输入npm publish即可发布包,如果出现报错可以把package.json的name字段改一下,可能是包重名了

==请注意发布包时你的npm源是官方的不是第三方的源,可以通过npm config get registry来查看你npm的源,如果显示**https://registry.npmjs.org/**则是官方的,如果不是可以通过➞ npm config set registry https://registry.npmjs.org/来进行设置.

5.结语

Hi👋,这里是瑞雨溪**->一个喜欢JavaScript和Vue的大学生,如果我的文章给你带来的帮助,欢迎您关注我->**我会持续不断的更新更多优质文章.

你的关注就是我的动力!!!🎉🎉🎉

  • 36
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑞雨溪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值