创建一个专属的 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 ...
随机推荐
- cloudpickle —— Python分布式序列化的专用模块
给出cloudpickle的GitHub地址: https://github.com/cloudpipe/cloudpickle =================================== ...
- 高考志愿填报指南:使用AI阅读工具ChatDOC搭建专业、好用、免费的AI高考志愿填报系统
高考志愿填报指南:使用 ChatDOC 搭建专业.好用.免费的 AI 高考志愿填报系统 不说废话,直接上干货.针对高考志愿填报,这篇文章能为你提供以下内容:高考志愿填报专业数据.高考志愿填报分析思路. ...
- 面试必问之kafka
问题1:消息队列的作用 1. 解耦 快递小哥手上有很多快递需要送,他每次都需要先电话一一确认收货人是否有空.哪个时间段有空,然后再确定好送货的方案.这样完全依赖收货人了!如果快递一多,快递小哥估计的忙 ...
- 基于druid和spring的动态数据库以及读写分离
转
spring与druid可以实现动态数据源,夸库查询,读写分离等功能.现在说一下配置: 1.需要配置多个spring数据源 spring-data.xml <!-- 动态数据源 --> & ...
- 一款运行于windows上的linux命令神器-Cmder(已经爱不释手)
一.前言 很多工程师都习惯了使用linux下一些命令,再去用Windows的 cmd 简直难以忍受. 要在windows上运行linux命令,目前比较流行的方式由: GunWin32.Cygwin.W ...
- IoTSharp:基于 .NET 8.0 的开源物联网平台
前言 想要快速了解物联网的世界吗?如果你对物联网(IoT)感兴趣,或者正打算开发自己的物联网项目.可以试试 IoTSharp,一个基于 .NET 的开源平台. 无论你是初学者还是有经验的大佬,IoTS ...
- AI产品经理的探索:技能、机遇与未来展望
Ai时代的产品经理 随着人工智能(AI)的飞速发展,AI已经从一个前沿技术概念逐步演变为驱动各行业创新的核心力量.从智能助手到自动驾驶,从个性化推荐系统到图像识别,AI正在以不可思议的速度改变着我们的 ...
- Go plan9 汇编: 打通应用到底层的任督二脉
原创文章,欢迎转载,转载请注明出处,谢谢. 0. 前言 作为一个严肃的 Gopher,了解汇编是必须的.本汇编系列文章会围绕基本的 Go 程序介绍汇编的基础知识. 1. Go 程序到汇编 首先看一个简 ...
- 【图文教程】云服务器上,Linux安装VSFTPD组件及遇到的问题
服务器做迁移,从AXX云迁移到Txx云上,迁移的话,需要把图片服务器也迁移过去.之前使用的是VSFTPD这次也还用这个吧.这里就记录下FTP服务器安装及遇到的问题. 1:安装VSFTP组件 使用yum ...
- OpenTelemetry 实战:gRPC 监控的实现原理
前言 最近在给 opentelemetry-java-instrumentation 提交了一个 PR,是关于给 gRPC 新增四个 metrics: rpc.client.request.size: ...