作为一个前端,基本上每次初始化项目都会用到脚手架,通过一些脚手架可以快速的搭建一个前端的项目并集成一些所需的功能模块,避免自己每次都手动一个一个去安装。安装各个包的这个过程其实没啥营养,通过封装一个脚手架来跳过这个步骤,把精力聚焦到功能研发上。

由于最近自己在写项目都是相同的技术栈: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

execSyncNode.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 环境中需要安装 commanderprompts 两个库,不然会报错。

当通过 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的更多相关文章

  1. 如何用 React Native 创建一个iOS APP?

    诚然,React Native 结合了 Web 应用和 Native 应用的优势,可以使用 JavaScript 来开发 iOS 和 Android 原生应用.在 JavaScript 中用 Reac ...

  2. (4opencv)如何基于GOCW,创建一个实时视频程序

    直接使用提供的代码框架进行修改,是最快得到效果的方法:但是这样的灵活性较差,而且真正的程序员从来都不会停滞在这一步:我们需要的是"将框架解析到最小化.理清楚每个构建之间的关系",只 ...

  3. VS2017创建一个 ASP.NET Core2.0 应用,并搭建 MVC 框架

    https://testerhome.com/topics/11747 1.使用最新版本的VS2017,并安装.NET Core2.0中相关开发工具   2.打开VS2017,点击文件-新建-项目,选 ...

  4. 使用PHP来简单的创建一个RPC服务

    RPC全称为Remote Procedure Call,翻译过来为"远程过程调用".主要应用于不同的系统之间的远程通信和相互调用. 比如有两个系统,一个是PHP写的,一个是JAVA ...

  5. Vue Create 创建一个新项目 命令行创建和视图创建

    Vue Create 创建一个新项目 命令行创建和视图创建 开始之前 你可以先 >>:cd desktop[将安装目录切换到桌面] >>:vue -V :Vue CLI 3.0 ...

  6. 使用vue-cli创建一个vue项目

    安装vue-cli npm install -g @vue/cli 1, 使用vue创建一个项目 vue create luffy 2, 安装所需的插件 npm install vue-router ...

  7. Angular学习笔记—创建一个angular项目

    开始项目前,你需要先安装node和npm,然后执行npm install -g @angular/cli安装Angular CLI. 如何安装node.js和npm npm使用介绍 1.安装angul ...

  8. 使用PHP创建一个socket服务端

    与常规web开发不同,使用socket开发可以摆脱http的限制.可自定义协议,使用长连接.PHP代码常驻内存等.学习资料来源于workerman官方视频与文档. 通常创建一个socket服务包括这几 ...

  9. 创建一个vue-cli项

    一.vue cli脚手架 Vue 提供了一个官方的cli,为单页面应用 (SPA) 快速搭建繁杂的脚手架,通过这个工具我们就可以很方便的来创建一个基于vue的项目. 二.安装一些必要的东西node.n ...

  10. Cordova之如何用命令行创建一个项目(完整示例)

    原文:Cordova之如何用命令行创建一个项目(完整示例) 1. 创建cordova项目 (注意:当第一次创建或编译项目的时候,可能系统会自动下载一些东西,需要一些时间.) 在某个目录下创建cordo ...

随机推荐

  1. java多线程之自定义线程池

    1.背景 线程池.....大家常用.... 自己搞一个,顺便练习一下多线程编程 2.自定义线程代码 2.1.拒绝策略接口 @FunctionalInterface public interface M ...

  2. maven配置阿里云镜像与修改默认仓库地址

    1.背景 通常来说maven的默认镜像很慢,我们需要一个国内镜像,拉取jar包的时候从国内下载, 当然阿里云镜像是很好的一个候选 2.安装 官网下载一个maven解压即可使用 3.修改配置 第一步,找 ...

  3. php curl访问https 域名接口一直报错的问题

    这两天一直在对接一个https的接口 通过本地postman完美链接后再服务器一直报错 出现问题:linux 下 curl可以正常访问 但是PHP请求一直返回false 测试方法:var_dump(c ...

  4. 解决 Docker CE 在无根模式(rootless)下无法通过 IPv6 拉取映像的问题

    折腾一天快把我逼疯了 本来 Docker 对 IPv6 的支持就不好,再来个 rootless,雪上加霜 首先,我们要区分 Docker Engine 和 里面的 Image. 拉取映像是 Docke ...

  5. 2. 从0开始学ARM-CPU原理,基于ARM的SOC讲解

    关于ARM的一些基本概念,大家可以参考我之前的文章: <到底什么是Cortex.ARMv8.arm架构.ARM指令集.soc?一文帮你梳理基础概念[科普]> 关于ARM指令用到的IDE开发 ...

  6. uni-app 小程序 前置摄像头

    在小程序拍照的话,uni.chooseImage()可以直接调取摄像头拍照,而如果要调用前置摄像头,这个api就没有提供了. 在查找官方文档发现,可以通过camera有提供这么一个组件,页面内嵌的区域 ...

  7. 13 Python面向对象编程:装饰器

    本篇是 Python 系列教程第 13 篇,更多内容敬请访问我的 Python 合集 Python 装饰器是一种强大的工具,用于修改或增强函数或方法的行为,而无需更改其源代码.装饰器本质上是一个接收函 ...

  8. Innodb 单表索引查询和连接查询效率分析

    一.MySQL查询访问方法 mysql执行查询语句的方式叫做访问方法或访问类型,这些访问类型具体为 const.ref.range.index.all等. 同一个查询语句可以使用多种不同的访问方法来执 ...

  9. C#整合Ollama实现本地LLMs调用

    前言 近两年AIGC发展的非常迅速,从刚开始的只有ChatGPT到现在的很百家争鸣.从开始的大参数模型,再到后来的小参数模型,从一开始单一的文本模型到现在的多模态模型等等.随着一起进步的不仅仅是模型的 ...

  10. Goby 漏洞发布|泛微 e-cology v10 appThirdLogin 权限绕过漏洞【漏洞复现】

    漏洞名称:泛微 e-cology v10 appThirdLogin 权限绕过漏洞 English Name:Weaver e-cology v10 appThirdLogin Permission ...