从零开发多模板GitHub初始化CLI并发布至NPMjs完整教程

手把手教你基于Node.js开发支持多模板选择的GitHub项目初始化CLI脚手架,包含本地调试、npm打包、发布到npmjs全流程,零基础可落地。

本教程将手把手教你开发一款自定义脚手架CLI,实现 通过命令行从GitHub远程拉取模板项目初始化本地项目 的核心功能,并完成最终 发布到npmjs官方仓库 的全流程。全程基于 Node.js 开发,无需后端知识,零基础可实操,内置多模板交互式选择功能。

一、环境准备

开发和发布前需安装基础环境,确保版本达标:

  1. Node.js:v14.0+(推荐v16/v18稳定版),自带npm工具

  2. Git:用于拉取GitHub仓库代码

  3. npm账号:前往 npmjs官网 免费注册

  4. GitHub仓库:提前准备一个公开的项目模板仓库(用于CLI拉取初始化)

环境校验命令(终端执行):

1
2
3
node -v
npm -v
git --version

二、前期准备:配置GitHub模板仓库

我们的CLI核心功能是克隆GitHub模板仓库到本地并初始化项目,首先准备好模板项目:

  1. 在GitHub新建一个公开仓库,作为项目模板(可自定义Vue/React/Node/空模板)

  2. 仓库无需复杂配置,保证可公开克隆即可,记录仓库地址,格式:https://github.com/用户名/模板仓库名.git

  3. 建议去掉仓库默认的 .git 关联(CLI初始化后会重新初始化git,避免模板仓库关联污染新项目)

三、创建CLI脚手架项目(内置多模板选择功能)

3.1 初始化本地CLI项目

新建空文件夹(如 qqlabs-cli),终端进入文件夹,执行初始化:

1
npm init -y

初始化完成后生成 package.json,这是CLI项目的核心配置文件。

3.2 安装核心依赖

开发GitHub拉取、命令行交互、文件处理所需依赖:

1
2
3
4
5
# 核心依赖
npm install commander inquirer download-git-repo ora chalk fs-extra

# 开发依赖(热更新调试)
npm install -D nodemon

依赖说明:

  • commander:解析命令行指令、定义CLI命令

  • inquirer:命令行交互式问答(输入项目名、选择模板)

  • download-git-repo:核心!专门用于下载/克隆GitHub仓库模板

  • ora:命令行加载动画

  • chalk:命令行文字配色,优化交互体验

  • fs-extra:增强版文件读写、文件夹操作,替代原生fs

3.3 创建CLI入口文件

项目根目录新建 index.js(CLI核心入口文件),首行必须添加脚本执行标识,以下为整合多模板选择的完整最终代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/usr/bin/env node

// 引入依赖
const program = require('commander')
const inquirer = require('inquirer')
const download = require('download-git-repo')
const ora = require('ora')
const chalk = require('chalk')
const fs = require('fs-extra')
const path = require('path')

// 核心:多模板配置列表(可自由增删改)
const TEMPLATE_LIST = [
  {
    name: 'Vue3 基础模板',
    value: 'github:qiqilabs/vue3-template#main'
  },
  {
    name: 'React 基础模板',
    value: 'github:qiqilabs/react-template#main'
  },
  {
    name: 'Node 后端模板',
    value: 'github:qiqilabs/node-server-template#main'
  },
  {
    name: '空项目模板',
    value: 'github:qiqilabs/empty-template#main'
  }
]

// 1. 定义CLI版本和基础信息
program
  .version('1.0.0', '-v, --version')
  .description('基于GitHub模板的项目初始化CLI工具(支持多模板选择)')

// 2. 定义初始化命令:init
program
  .command('init [projectName]')
  .description('交互式选择GitHub模板,初始化项目')
  .action(async (projectName) => {
    // 双层交互式问答:输入项目名 + 选择模板
    const res = await inquirer.prompt([
      {
        name: 'name',
        message: '请输入项目名称',
        default: projectName || 'my-new-project'
      },
      {
        type: 'list',
        name: 'template',
        message: '请选择需要初始化的项目模板',
        choices: TEMPLATE_LIST
      }
    ])

    // 拼接项目路径
    const targetPath = path.resolve(process.cwd(), res.name)

    // 判断文件夹是否已存在,防止覆盖本地文件
    if (fs.existsSync(targetPath)) {
      console.log(chalk.red(`❌ 项目文件夹 ${res.name} 已存在!请更换项目名后重试`))
      return
    }

    // 开启加载动画
    const spinner = ora(chalk.blue('正在从GitHub拉取选中的模板项目...')).start()

    // 根据选中的模板拉取对应GitHub仓库代码
    download(res.template, targetPath, { clone: true }, async (err) => {
      if (err) {
        spinner.fail(chalk.red('❌ 模板拉取失败!请检查网络或模板仓库地址是否有效'))
        console.log(chalk.gray('错误详情:', err))
        return
      }

      // 清除模板原有git关联,保证新项目独立
      await fs.remove(path.join(targetPath, '.git'))
      spinner.succeed(chalk.green('✅ 项目初始化成功!'))
      // 输出后续操作指引
      console.log(chalk.green(`\n👉 进入项目目录:cd ${res.name}`))
      console.log(chalk.green(`👉 安装项目依赖:npm install`))
      console.log(chalk.green(`👉 启动项目:查看项目README.md启动脚本`))
    })
  })

// 解析命令行参数
program.parse(process.argv)

3.4 配置package.json

修改 package.json,配置CLI命令映射、入口文件、发布信息(关键配置,必须修改):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
  "name": "@qqlabs/cli", // npm包名(全局唯一,不能重复)
  "version": "1.0.0", // 版本号(发布时需迭代更新)
  "description": "从GitHub模板初始化项目的CLI工具",
  "main": "index.js",
  "bin": {
    "qqlabs": "./index.js" // 自定义全局命令名(终端执行的指令)
  },
  "scripts": {
    "dev": "nodemon index.js", // 本地调试命令
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": ["cli", "github", "template", "init-project"], // npm搜索关键词
  "author": "你的昵称",
  "license": "MIT",
  "dependencies": {
    "chalk": "^4.1.2",
    "commander": "^9.4.0",
    "download-git-repo": "^3.0.2",
    "fs-extra": "^10.1.1",
    "inquirer": "^8.2.4",
    "ora": "^5.4.1"
  },
  "devDependencies": {
    "nodemon": "^2.0.20"
  }
}

重点注意bin 字段是核心,将 qqlabs 命令绑定到入口文件,实现全局命令调用;当前CLI已内置多模板交互式选择功能,可自行配置模板列表。

3.5 多模板配置规则

可自由增删改模板列表,无需改动核心逻辑,配置规则如下:

  • name:终端展示的模板名称,自定义中文/英文,便于用户识别

  • value:GitHub公开模板仓库地址,固定格式 github:用户名/仓库名#分支名

  • 支持无限拓展模板,直接在 TEMPLATE_LIST 数组内追加配置对象即可

四、本地调试CLI工具

4.1 全局链接本地项目

在CLI项目根目录执行链接命令,将本地CLI注册为全局命令:

1
npm link

执行成功后,终端任意位置都可使用 qqlabs init 命令。

4.2 测试初始化功能

新开终端,进入任意空文件夹,执行CLI命令:

1
2
3
4
5
# 初始化项目
qqlabs init

# 或直接指定项目名
qqlabs init my-new-project

正常流程:输入项目名 → 选择对应模板 → 自动拉取GitHub模板 → 生成本地新项目 → 清除旧git关联,功能无误即可准备发布。

4.3 解除本地链接(后续可用)

1
npm unlink qqlabs

五、发布CLI到npmjs

5.1 检查npm源(必须官方源)

发布前必须切换为npm官方源,淘宝源无法发布:

1
2
3
4
5
6
7
8
# 查看当前源
npm config get registry

# 切换官方源
npm config set registry https://registry.npmjs.org/

# 后续切回淘宝源(可选)
# npm config set registry https://registry.npmmirror.com/

5.2 登录npm账号

终端执行登录命令,输入npmjs账号、密码、邮箱验证码:

1
npm login

登录成功会提示 Logged in as 用户名 on https://registry.npmjs.org/

5.3 正式发布包

确保 package.jsonname 包名全局唯一、版本号正确,执行发布:

1
npm publish

5.4 发布常见问题解决

  • 包名重复报错:修改 package.jsonname 为全新唯一名称,重新发布

  • 版本重复报错:修改 version 版本号(如1.0.1),禁止重复版本发布

  • 权限报错:确认登录账号正确,退出重试npm login

  • 私有包报错:添加 "private": false 到package.json

六、安装使用已发布的CLI

发布成功后,所有人都可通过npm全局安装你的CLI工具:

1
2
3
4
5
# 全局安装
npm install -g @qqlabs/cli

# 使用命令初始化项目
qqlabs init

七、版本迭代更新

后续修改CLI功能后,按以下流程更新发布:

  1. 修改代码功能

  2. 修改 package.json 版本号(小版本迭代:1.0.0 → 1.0.1)

  3. 执行 npm publish 重新发布

  4. 用户更新:npm update -g @qqlabs/cli

八、核心拓展优化(可选)

  1. 自动安装依赖:拉取模板后自动执行 npm install

  2. 自定义分支:支持命令行指定GitHub仓库分支

  3. 错误重试机制:网络失败自动重试拉取模板

总结:本文完成了 多模板GitHub脚手架CLI开发 → 本地调试 → npmjs发布 → 全局安装使用 完整闭环。核心关键点:download-git-repo 实现代码拉取、bin 配置全局命令、发布必须切换npm官方源、包名和版本号全局唯一。

使用 Hugo 构建
主题 StackJimmy 设计