本教程将手把手教你开发一款自定义脚手架CLI,实现 通过命令行从GitHub远程拉取模板项目初始化本地项目 的核心功能,并完成最终 发布到npmjs官方仓库 的全流程。全程基于 Node.js 开发,无需后端知识,零基础可实操,内置多模板交互式选择功能。
一、环境准备
开发和发布前需安装基础环境,确保版本达标:
-
Node.js:v14.0+(推荐v16/v18稳定版),自带npm工具
-
Git:用于拉取GitHub仓库代码
-
npm账号:前往 npmjs官网 免费注册
-
GitHub仓库:提前准备一个公开的项目模板仓库(用于CLI拉取初始化)
环境校验命令(终端执行):
1
2
3
|
node -v
npm -v
git --version
|
二、前期准备:配置GitHub模板仓库
我们的CLI核心功能是克隆GitHub模板仓库到本地并初始化项目,首先准备好模板项目:
-
在GitHub新建一个公开仓库,作为项目模板(可自定义Vue/React/Node/空模板)
-
仓库无需复杂配置,保证可公开克隆即可,记录仓库地址,格式:https://github.com/用户名/模板仓库名.git
-
建议去掉仓库默认的 .git 关联(CLI初始化后会重新初始化git,避免模板仓库关联污染新项目)
三、创建CLI脚手架项目(内置多模板选择功能)
3.1 初始化本地CLI项目
新建空文件夹(如 qqlabs-cli),终端进入文件夹,执行初始化:
初始化完成后生成 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注册为全局命令:
执行成功后,终端任意位置都可使用 qqlabs init 命令。
4.2 测试初始化功能
新开终端,进入任意空文件夹,执行CLI命令:
1
2
3
4
5
|
# 初始化项目
qqlabs init
# 或直接指定项目名
qqlabs init my-new-project
|
正常流程:输入项目名 → 选择对应模板 → 自动拉取GitHub模板 → 生成本地新项目 → 清除旧git关联,功能无误即可准备发布。
4.3 解除本地链接(后续可用)
五、发布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账号、密码、邮箱验证码:
登录成功会提示 Logged in as 用户名 on https://registry.npmjs.org/
5.3 正式发布包
确保 package.json 的 name 包名全局唯一、版本号正确,执行发布:
5.4 发布常见问题解决
-
包名重复报错:修改 package.json 的 name 为全新唯一名称,重新发布
-
版本重复报错:修改 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功能后,按以下流程更新发布:
-
修改代码功能
-
修改 package.json 版本号(小版本迭代:1.0.0 → 1.0.1)
-
执行 npm publish 重新发布
-
用户更新:npm update -g @qqlabs/cli
八、核心拓展优化(可选)
-
自动安装依赖:拉取模板后自动执行 npm install
-
自定义分支:支持命令行指定GitHub仓库分支
-
错误重试机制:网络失败自动重试拉取模板
总结:本文完成了 多模板GitHub脚手架CLI开发 → 本地调试 → npmjs发布 → 全局安装使用 完整闭环。核心关键点:download-git-repo 实现代码拉取、bin 配置全局命令、发布必须切换npm官方源、包名和版本号全局唯一。