创建一个专属的 CLI
作为一个前端,基本上每次初始化项目都会用到脚手架,通过一些脚手架可以快速的搭建一个前端的项目并集成一些所需的功能模块,避免自己每次都手动一个一个去安装。安装各个包的这个过程其实没啥营养,通过封装一个脚手架来跳过这个步骤,把精力聚焦到功能研发上。
由于最近自己在写项目都是相同的技术栈:Nextjs + TailwindCSS + TypeScript + ShadcnUI ,有时候如果忘记了 ShadcnUI 安装的命令的话,还得去 ShadcnUI 官网 去查看先关的文档。正好最近在看前端工程化相关的内容,简单封装一个 cli ,为了以后给 DevNow 来扩展一些内容模版做些基建。说 · 感觉就逼格就上来了。
顺便给自己的开源博客项目打个广告,欢迎大家体验、star:
DevNow 是一个精简的开源技术博客项目模版,支持 Vercel 一键部署,支持评论、搜索等功能,欢迎大家体验。
1. 初始化
新建一个 cli 文件夹 用来存放我们相关的内容。
|-- cli
|-- index.js
我们主要的 cli 内容都在 index.js 中,接下来我们来实现一下。先来看完整代码如下:
#!/usr/bin/env node
const { Command } = require('commander');
const { execSync } = require('child_process');
const prompts = require('prompts');
const program = new Command();
let projectPath = '';
async function initProject() {
console.log('欢迎使用项目初始化工具!');
const opts = program.opts();
// 询问用户输入和选择
const response = await prompts([
{
type: 'text',
name: 'projectName',
message: '请输入项目名称:',
validate: (name) => (name ? true : '项目名称不能为空'),
initial: projectPath
},
{
type: 'select',
name: 'template',
message: '请选择项目模板:',
choices: [
{ title: 'JavaScript', value: 'javascript' },
{ title: 'TypeScript', value: 'typescript' }
],
initial: opts.ts ? 1 : 0 // 默认 TypeScript
},
{
type: 'select',
name: 'tailwindCSS',
message: 'Would you like to use Tailwind CSS?',
choices: [
{ title: 'No', value: false },
{ title: 'Yes', value: true }
],
initial: opts.tailwind ? 1 : 0 // 默认 TypeScript
},
{
type: 'select',
name: 'eslint',
message: 'Would you like to use eslint',
choices: [
{ title: 'No', value: false },
{ title: 'Yes', value: true }
],
initial: opts.eslint ? 1 : 0 // 默认 eslint
},
{
type: 'select',
name: 'shadcnUI',
message: 'Would you like to use Shadcn/ui?',
choices: [
{ title: 'No', value: false },
{ title: 'Yes', value: true }
],
initial: opts.shadcnUI ? 1 : 0 // 默认 shadcnUI
}
]);
// 项目初始化命令拼接
const templateFlag = (response.template || opts.ts) === 'typescript' ? '--typescript' : '';
const eslintFlag = response.eslint || opts.eslint ? '--eslint' : '';
const tailwindCSS = response.tailwindCSS || opts.tailwind ? '--tailwind' : '';
try {
// 执行 Next.js 初始化命令
console.log(`正在创建项目:${response.projectName}...`);
execSync(
`pnpm create next-app@latest ${response.projectName} ${templateFlag} ${eslintFlag} ${tailwindCSS} --turbopack --app --src-dir --import-alias "@/*"`,
{ stdio: 'inherit' }
);
// 切换到项目目录
process.chdir(response.projectName);
// 安装 shadcn/ui
if (response.shadcnUI || opts.shadcnUI) {
console.log('安装 shadcn/ui...');
execSync('pnpm dlx shadcn@latest init -d', { stdio: 'inherit' });
}
console.log('项目初始化完成!');
console.log(`请运行以下命令进入项目并启动开发服务器:`);
console.log(` cd ${response.projectName}`);
console.log(` pnpm dev`);
} catch (error) {
console.error('项目创建失败:', error.message);
}
}
// 定义 CLI 命令
program
.name('create-next-app')
.description('创建一个 Next.js 项目')
.argument('<project-name>', '项目名称')
.option('--ts, --typescript', 'Initialize as a TypeScript project. (default)')
.option('--tailwind', 'Initialize with Tailwind CSS config. (default)')
.option('--eslint', 'Initialize with ESLint config.')
.option('--shadcnUI', 'Enable ShadcnUi.')
.action((name) => {
projectPath = name;
initProject();
});
// 解析命令行参数
program.parse(process.argv);
1.1 execSync
execSync 是 Node.js 的内置模块 child_process 中的一个同步执行命令的方法。它会在当前进程中运行指定的系统命令,并返回结果。
1.2 Commadner.js
Commander.js 完整的 node.js 命令行解决方案。编写代码来描述你的命令行界面。 Commander 负责将参数解析为选项和命令参数,为问题显示使用错误,并实现一个有帮助的系统。
// 定义 CLI 命令
program
.name('create-next-app')
.description('创建一个 Next.js 项目')
.argument('<project-name>', '项目名称')
.option('--ts, --typescript', 'Initialize as a TypeScript project. (default)')
.option('--tailwind', 'Initialize with Tailwind CSS config. (default)')
.option('--eslint', 'Initialize with ESLint config.')
.option('--shadcnUI', 'Enable ShadcnUi.')
.action((name) => {
projectPath = name;
initProject();
});
// 解析命令行参数
program.parse(process.argv);
这段代码通过 commander.js 定义了一个功能丰富的 CLI 工具,允许用户通过不同的选项初始化一个定制化的 Next.js 项目。 parse(process.argv) 是核心步骤,用来解析命令行中的参数并执行对应的逻辑。
我们通过 --help 可以看到一些可选的配置参数等等内容。

1.3 prompts
prompts 是一个轻量级、用户友好的交互式 CLI 库,用于在命令行中向用户提出问题并收集输入。它支持多种类型的提示,比如文本输入、选择、多选、确认等,允许开发者灵活地设计命令行应用的交互体验。
通过使用 prompts 库,我们可以在 CLI 中实现类似 Next.js 的交互体验,这样可以在初始化项目时根据需要选择不同的选项,体验会更好一点。
const response = await prompts([
{
type: 'text',
name: 'projectName',
message: '请输入项目名称:',
validate: (name) => (name ? true : '项目名称不能为空'),
initial: projectPath
},
{
type: 'select',
name: 'template',
message: '请选择项目模板:',
choices: [
{ title: 'JavaScript', value: 'javascript' },
{ title: 'TypeScript', value: 'typescript' }
],
initial: opts.ts ? 1 : 0 // 默认 TypeScript
},
{
type: 'select',
name: 'tailwindCSS',
message: 'Would you like to use Tailwind CSS?',
choices: [
{ title: 'No', value: false },
{ title: 'Yes', value: true }
],
initial: opts.tailwind ? 1 : 0 // 默认 TypeScript
},
{
type: 'select',
name: 'eslint',
message: 'Would you like to use eslint',
choices: [
{ title: 'No', value: false },
{ title: 'Yes', value: true }
],
initial: opts.eslint ? 1 : 0 // 默认 eslint
},
{
type: 'select',
name: 'shadcnUI',
message: 'Would you like to use Shadcn/ui?',
choices: [
{ title: 'No', value: false },
{ title: 'Yes', value: true }
],
initial: opts.shadcnUI ? 1 : 0 // 默认 shadcnUI
}
]);
这里通过配置了一些选项,结合了 command 初始化命令行的默认选项,效果如下:

1.4 执行代码
try {
// 执行 Next.js 初始化命令
console.log(`正在创建项目:${response.projectName}...`);
execSync(
`pnpm create next-app@latest ${response.projectName} ${templateFlag} ${eslintFlag} ${tailwindCSS} --turbopack --app --src-dir --import-alias "@/*"`,
{ stdio: 'inherit' }
);
// 切换到项目目录
process.chdir(response.projectName);
// 安装 shadcn/ui
if (response.shadcnUI || opts.shadcnUI) {
console.log('安装 shadcn/ui...');
execSync('pnpm dlx shadcn@latest init -d', { stdio: 'inherit' });
}
console.log('项目初始化完成!');
console.log(`请运行以下命令进入项目并启动开发服务器:`);
console.log(` cd ${response.projectName}`);
console.log(` pnpm dev`);
} catch (error) {
console.error('项目创建失败:', error.message);
}
这里就是主要的执行内容,通过前面的配置参数来定制化执行,首先是 Nextjs 相关内容,可以看到我默认了一些配置,这些看个人的需求了,感觉这些东西默认的会更好。最后就是根据配置参数判断是否要安装 ShadcnUI .
其实到这里 CLI 的基本内容就完事了,我们可以在本地执行 node index.js cli-test --tailwind 去测试下。
注意:
本地 Node 环境中需要安装commander和prompts两个库,不然会报错。当通过 npx create-next-app 等命令初始化项目时,你不需要担心 commander 等依赖的安装。工具本身已经打包好了这些依赖,并通过 npx 或 pnpm dlx 临时加载执行,简化了使用流程。
2. 发布
这里简单记录下吧,这个应该很多人已经会了,
2.1 npm init
首先通过 npm init 初始化,通过提示可以生成一些配置文件,这个时候项目结构应该是:
|-- cli
|-- index.js
|-- package.json
package.json 主要内容如下:
{
"dependencies": {
"commander": "^12.1.0",
"prompts": "^2.4.2"
},
"name": "create-devnow-app",
"version": "0.0.6",
"description": "create devnow app",
"main": "./index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "LaughingZhu",
"license": "MIT",
"bin": {
"create-devnow-app": "./index.js"
}
}
确保你的 package.json 文件中定义了正确的 bin 配置。这样才能执行。
2.2 登录
npm login
2.3 发布
npm publish
使用自己专属的 CLI
pnpm dlx create-devnow-app@latest my-app

大功告成,这样在后续就可以直接使用了,如果业务中需要其他的一些配置的话,可以通过相同的方式集成,比如 T3 这个项目,就集成了 TRPC 等内容到脚手架中,可以方便快速构建一个全栈的项目。
创建一个专属的 CLI的更多相关文章
- 如何用 React Native 创建一个iOS APP?
诚然,React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用.在 JavaScript 中用 Reac ...
- (4opencv)如何基于GOCW,创建一个实时视频程序
直接使用提供的代码框架进行修改,是最快得到效果的方法:但是这样的灵活性较差,而且真正的程序员从来都不会停滞在这一步:我们需要的是"将框架解析到最小化.理清楚每个构建之间的关系",只 ...
- VS2017创建一个 ASP.NET Core2.0 应用,并搭建 MVC 框架
https://testerhome.com/topics/11747 1.使用最新版本的VS2017,并安装.NET Core2.0中相关开发工具 2.打开VS2017,点击文件-新建-项目,选 ...
- 使用PHP来简单的创建一个RPC服务
RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".主要应用于不同的系统之间的远程通信和相互调用. 比如有两个系统,一个是PHP写的,一个是JAVA ...
- Vue Create 创建一个新项目 命令行创建和视图创建
Vue Create 创建一个新项目 命令行创建和视图创建 开始之前 你可以先 >>:cd desktop[将安装目录切换到桌面] >>:vue -V :Vue CLI 3.0 ...
- 使用vue-cli创建一个vue项目
安装vue-cli npm install -g @vue/cli 1, 使用vue创建一个项目 vue create luffy 2, 安装所需的插件 npm install vue-router ...
- Angular学习笔记—创建一个angular项目
开始项目前,你需要先安装node和npm,然后执行npm install -g @angular/cli安装Angular CLI. 如何安装node.js和npm npm使用介绍 1.安装angul ...
- 使用PHP创建一个socket服务端
与常规web开发不同,使用socket开发可以摆脱http的限制.可自定义协议,使用长连接.PHP代码常驻内存等.学习资料来源于workerman官方视频与文档. 通常创建一个socket服务包括这几 ...
- 创建一个vue-cli项
一.vue cli脚手架 Vue 提供了一个官方的cli,为单页面应用 (SPA) 快速搭建繁杂的脚手架,通过这个工具我们就可以很方便的来创建一个基于vue的项目. 二.安装一些必要的东西node.n ...
- Cordova之如何用命令行创建一个项目(完整示例)
原文:Cordova之如何用命令行创建一个项目(完整示例) 1. 创建cordova项目 (注意:当第一次创建或编译项目的时候,可能系统会自动下载一些东西,需要一些时间.) 在某个目录下创建cordo ...
随机推荐
- python多进程multiprocessing模块的变量传递问题:父进程中的numpy.array对象隐式序列化到子进程后的inplace操作的问题
参考: https://docs.python.org/zh-cn/3/library/multiprocessing.html cloudpickle -- Python分布式序列化的专用模块 ...
- Windows系统下硬盘S.M.A.R.T硬盘检测工具——硬盘检测工具(CrystalDiskInfo)
CrystalDiskInfo是由日本人hiyohiyo个人开发的小工具,能全面详细直观的检查硬盘的健康状态及各种参数. 绿色版软件. 官方下载地址: https://crystalmark.info ...
- [SDOI2010] 城市规划 题解
前言 题目链接:洛谷. 题意简述 树套环上求至少间隔两个位置的最大独立集. (树套环,即树上每个结点都是一个结点或环) 题目分析 将题目拆解成树上 DP 和环上 DP 即可.用 tarjan 缩点就行 ...
- .NET 7 + Vue 权限管理系统 小白快速上手
前言 今天给大家推荐一个超实用的开源项目<.NET 7 + Vue 权限管理系统 小白快速上手>,DncZeus的愿景就是做一个.NET 领域小白也能上手的简易.通用的后台权限管理模板系统 ...
- 100ASK_IMX6ULL arm板子如何移植刷卡器
最近为了在arm板子上移植刷卡器,比较简单,但也遇到了坑,现在和大家分享下. 购买刷卡器 某宝很多,应该选哪一种呢? 一口君一共买了4种刷卡器,有2种可以用,还有2种不能用. 下图为最方便的一款,一口 ...
- 安装 Oh My Posh
Oh My Posh Oh My Posh 官网 安装 winget install JanDeDobbeleer.OhMyPosh -s winget Oh My Posh 更新很快,有时会被杀毒软 ...
- 阿里云 SLS 模糊查询日志
查询包含test前缀的词 1. 访问 https://sls.console.aliyun.com/lognext/profile 2. 在Project列表中找到对应的sls日志Project 3. ...
- 【YashanDB知识库】字段加上索引后,SQL查询不到结果
[标题]字段加上索引后,SQL查询不到结果 [问题分类]索引功能使用 [关键字]索引,SQL查询,时间类型,vachar字符类型 [问题描述]字段加上索引后,SQL查询不到结果. [问题原因分析]当前 ...
- 编译和分发 Chez Scheme 应用程序
参考 Building and Distributing Applications. 假设源码由两个文件组成,A.ss 和 B.ss,其中 A.ss 依赖 B.ss.下面我们将其编译为可供分发的二进制 ...
- pgsql 查询及更新json字段的某个属性
pgsql 查询及更新json字段的某个属性 一.查询json字段中的某个属性 查询 t_user 表中json 字段 info 中的 name 属性 select info ->> 'n ...