☰
t3code:一条命令搞定前端项目初始化和工程规范
2026/10/14 2:02:39 网站建设 项目流程

如果你还在每个新项目都重复“拉模板、删 demo、配 ESLint、装 Husky、写 CI”这一整套流程,t3code 应该能帮上大忙。t3code 是我自己维护的一个命令行工具,核心就一件事:把一套经过上百次提交打磨的工程规范,变成一条命令。新项目从 git init 到可开发状态,压缩到十分钟以内,团队的活也终于可以放在业务代码上,而不是和配置文件纠缠不清。

t3code 目前定位为“前端/全栈项目的初始化与模块管理工具”。你可以用它初始化一个带 TypeScript、ESLint、Prettier、Husky、commitlint 的项目骨架,也可以随时往已有项目里添加组件、页面或配置模块。它解决的并不是“锦上添花”的效率问题,而是几乎每个团队都会遇到的重复劳动问题。无论你是独立开发者,还是小团队里的前端负责人,只要一个月需要启动两个以上项目,就值得试一次。

1. 项目定位:t3code 到底解决了什么

1.1 新项目启动的“脏活清单”

先说说我为什么要写这个工具。之前团队里每次开新项目,都要经历一轮冲流程:创建仓库、复制老项目、删掉业务代码、手动安装依赖、遇到版本冲突再一个个去踩。最难受的是配置文件每个项目都长得不一样,今天这个人加了 rules,明天那个人改了 indent。到了 Code Review 阶段,经常有三分之一的时间在讨论“这里该不该分号”“这个 import 为什么要排后面”。

把这些“脏活”列出来其实很固定:

  • 项目目录初始化,包管理器选型,初始化 git 仓库
  • TypeScript 的 tsconfig 配置,strict 开关和路径别名
  • ESLint 规则集选择,是否走 Next.js / Vue / React 的插件
  • Prettier 格式化配置,和 ESLint 的关系处理
  • Husky 的 git hooks,commitlint 的提交规范
  • CI 的基本流水线,比如 install、lint、typecheck、build
  • 基础目录结构,比如 src/components、src/pages、src/utils 等

这些工作本身不产生业务价值,但你没法不做。靠复制粘贴虽然快,但老项目里的坑和历史包袱也会跟着复制过去,比如某个被注释掉的依赖、某段没人懂的魔改配置。t3code 的解决方案不是“再复制一次”,而是把这些内容变成一份可维护的模板和一组命令,随时重新执行。

1.2 为什么选择 CLI 而不是在线生成器或 GitHub 模板

其实一开始我做过网页版的生成器,但后来彻底放弃了,因为在线生成器有几个硬伤:必须打开浏览器,必须联网,生成之后和本地环境割裂。另一个选择是 GitHub 的 Use this template 按钮,也更常见,但同样有个问题:模板如果更新了,你 fork 出来的项目不会自动跟新,老项目和模板之间的差异要手动 merge,时间一长模板版本又分裂了。

CLI 工具的优势在于它是“本地优先”的,而且天生适合组合。t3code 不只是一个脚手架,还是一个长期陪伴项目的管理端。创建项目时可以这样:

方案可交互性可升级性可离线使用可定制性
在线生成器弱弱否弱
GitHub 模板无弱需 clone弱
CLI 脚手架强强是强

至于为什么用 Node.js 而不是 Go 或 Rust,主要是生态原因。前端团队对 Node 太熟了,维护者不一定要会 Go 才能改 CLI。而且像 commander、prompts、plop 这些库已经非常成熟,没必要重新发明轮子。Node 的启动速度虽然比编译型语言慢,但初始化项目根本不在乎这 100ms。

1.3 目标用户与适用场景

t3code 适合个人开发者和 2~10 人的小团队。原因很简单:大厂往往有自研的前端工程平台,小团队则需要一个轻量但够用的工具。它不适合完全零基础、希望“一键生成完整后台”的人,因为它给的是规范骨架,不是业务代码。t3code 更像是一个“包工头”,帮你把脚手架、代码规范、CI 流水线这些工作安排得明明白白,遇到特殊需求时你仍然需要自己动手。

比如你是一个独立开发者,发布了十几个 npm 包,每个包都需要维护 tsconfig、release 脚本、Github Actions。你在每个仓库里重复配置一遍的时间,足够把 t3code 搞定。再比如刚接手团队,想让大家的工程规范统一起来,与其写一份“前端规范文档”让大家自行遵守,不如直接通过工具把规范固化下来,让每个人执行一条命令就自动获得一致的配置。

2. 核心设计与实现细节

2.1 create / add / upgrade 三条命令的取舍

t3code 的命名参考了常见的 git 风格,用动词作为命令主体。第一版只做了 create,后来发现还有两个更痛的场景:给已有项目补模块、跟随模板升级配置。于是设计成三个子命令:

  • t3code create <project-name>:初始化一个新项目
  • t3code add <module-name>:给当前项目添加一个模块,比如 eslint、prettier
  • t3code upgrade:将项目中的模板配置更新到当前 t3code 版本

create 是所有命令的基础,它会先检测目录是否为空,然后通过 prompts 问几个关键问题,再生成文件、安装依赖。add 命令是后来才加的,因为很多项目需要按需引入能力。默认模板我不再装一堆包,而是只装最小集。想要加测试框架?执行t3code add vitest就会自动加依赖、生成配置文件、追加脚本。

upgrade 是 t3code 和其他脚手架最大的区别。GitHub 模板用久了之后很难同步,t3code 把“模板版本”这个概念引入项目,每次升级时会对比本地的t3code.config.js和默认模板的差异,然后做非破坏性合并。这样即使官方模板更新了,你原来的自定义配置也不会被覆盖。

2.2 模板工程的“配置即代码”

t3code 的模板目录结构大致是这样的:

t3code/ ├── commands/ │ ├── create.js │ ├── add.js │ └── upgrade.js ├── templates/ │ ├── base/ │ │ ├── tsconfig.json.hbs │ │ ├── eslint.config.js.hbs │ │ ├── .prettierrc.hbs │ │ ├── .husky/ │ │ └── .github/workflows/ci.yml.hbs │ ├── module-eslint/ │ ├── module-prettier/ │ └── module-vitest/ ├── utils/ │ ├── installer.js │ ├── merge-config.js │ └── file-writer.js ├── package.json └── t3code.config.js

模板文件使用.hbs后缀,也就是 Handlebars 模板。这样在生成时可以注入变量,比如项目名、作者、包管理器,还能通过{{#if}}控制哪些文件生成,哪些不生成。为什么不用 JSON 配置加字符串拼接?因为代码文件中到处是引号和空格,字符串拼接容易出错;Handlebars 模板可以直接写出真实的代码,维护时打开文件就是完整代码,很直观。

t3code 的核心设计原则是“配置即代码”:所有规范都写进模板,版本跟随 npm 包升级。团队里如果有人想改规范,不应该先去改 20 个项目,而是修改模板工程,发布一个新版本,然后在各项目里执行一次t3code upgrade。这个工作流是可以被 git 记录和审计的,比在群里发通知“大家注意,以后 hooks 规则改成这样”要可靠得多。

2.3 交互设计:从提问到默认值

很多人写 CLI 会忽略交互体验,导致一堆参数记不住。t3code 选择“少问问题”,用默认值覆盖 80% 的场景。比如创建项目时只问四个问题:

  1. 项目类型:基础前端项目 / Next.js / Vue / 库项目
  2. 包管理器:npm / pnpm / yarn
  3. TypeScript:开启(默认)/ 关闭
  4. ESLint:开启(默认)/ 关闭

每个问题都有默认值,直接按回车即可。命令行也支持跳过所有问题,比如t3code create my-app --template next --pm pnpm --yes,这样交互和脚本调用都不耽误。这个设计背后的考虑是:人类记不住五个以上的参数,任何超过三个的必选项都容易引发“算了,我还是手动建吧”。所以让默认值足够合理,提问只是让你在特殊场景下改一次。

实现时用的是prompts,而不是 inquirer,因为 prompts 在终端渲染更好看,也更轻量。代码大概长这样:

import prompts from 'prompts'; export async function askQuestions(options) { if (options.yes) return { ...defaults, ...options }; const response = await prompts([ { type: 'select', name: 'template', message: '选择项目类型', choices: [ { title: 'base', value: 'base', description: '最小前端骨架' }, { title: 'next', value: 'next', description: 'Next.js 全栈应用' }, ], initial: 0, }, { type: 'select', name: 'packageManager', message: '使用哪个包管理器?', choices: ['npm', 'pnpm', 'yarn'], }, ]); return { ...defaults, ...response }; }

用户一旦选过,t3code 会把选择写入本地的.t3code/answers.json,下次执行 add 时就直接读取,不再重复问。这个小细节对老用户很友好,我用了一段时间之后就决定做上去的。

3. 实操过程:从零到项目落地的完整记录

3.1 环境准备与安装

t3code 本身是一个 npm 全局工具,安装命令很简单:

npm i -g t3code

但我更推荐使用npx t3code,理由有两个:第一,不需要全局安装权限,避免 EACCES 问题;第二,工具可以跟随版本更新,始终拿到最新版。npx t3code create my-app会自动下载并执行,省去手动 update 这一步。如果你一定要全局安装,那么建议先确认 Node 版本不低于 18,因为 t3code 内部使用了 Node 18 的很多原生 API,比如fetch和crypto.randomUUID。

安装完之后可以执行:

t3code --version

如果能看到x.x.x,说明安装成功。如果你用的是 npx,那么第一次运行会比后续慢几秒,因为它在下载,这个是正常的。

3.2 初始化一个新项目:5 分钟跑通流程

我以一个真实项目为例,假设创建blog-admin:

npx t3code create blog-admin

执行后依次会出现几个问题,选择 Next.js、pnpm、TypeScript 和 ESLint,输出过程大概是:

✔ 项目类型 · next ✔ 包管理器 · pnpm ✔ 是否开启 TypeScript · true ✔ 是否开启 ESLint · true 正在生成文件... ✔ 目录结构创建完毕 ✔ 依赖安装完成 ✔ git 仓库初始化完成 ✔ husky hooks 已写入 运行以下命令开始开发: cd blog-admin pnpm dev

完成后生成的目录结构如下(只展示关键部分):

blog-admin/ ├── .github/workflows/ci.yml ├── .husky/ │ ├── pre-commit │ └── commit-msg ├── public/ ├── src/ │ ├── components/ │ ├── pages/ │ ├── styles/ │ └── utils/ ├── .eslintrc.json ├── .gitignore ├── .prettierrc.json ├── commitlint.config.js ├── next.config.mjs ├── package.json ├── tsconfig.json └── pnpm-lock.yaml

你注意看:项目里没有.t3code目录?其实是有的,默认隐藏了。里面存放了这一次生成时的选择结果和配置 hash。下次执行t3code upgrade时就是靠这个目录做差异对比。t3code 生成的每个文件顶部都有一段注释,标注了模板版本号和生成时间。这个功能不是为了好看,而是排查问题时能快速定位文件来源。

最后启动项目:

pnpm dev

如果看到页面顺利打开,说明初始化流程已经走通了。这时候做一次 commit,husky 会拦截你的 commit message,提示你按 commitlint 规范提交。这种事第一次会让人愣住,但一旦习惯就会觉得“没它都不自在”。

3.3 给已有项目添加模块的实际操作

假设你在初始化的时候没有开启 ESLint,后来发现团队规范要求必须开。不需要重新创建项目,直接执行:

npx t3code add eslint

add 命令会做三件事:

  • 定位当前项目根目录,找到.t3code/config.json(如果没有就自动创建一个)
  • 读取当前 package.json 的依赖情况,避免重复安装
  • 把templates/module-eslint/下的模板复制到项目,并根据当前项目的框架自动检测加载 React 还是 Vue 插件

如果项目里已经存在.eslintrc.json,t3code 不会盲目覆盖,而是会提示你是否要 merge,并且通过校验器检查新旧版本是否有明显冲突。这种“感知项目现状”的机制很重要,毕竟已有项目不是一张白纸。

同样地,想添加测试框架,执行t3code add vitest;想加 Storybook,执行t3code add storybook。每个模块都是一个独立的模板,可以自由组合。这比在 create 时把一百个模块都装上要好得多,因为实际项目里只有少数模块会被用到,装得越多,升级和排查就越痛苦。

3.4 自定义模板的方法

t3code 允许你在项目中放置一个t3code.config.js来扩展模板。这个文件本身也是模板生成的,结构是:

module.exports = { prompts: [ { name: 'projectName', message: '项目名称', type: 'text', }, ], templateDir: './my-templates', modules: { eslint: { enabled: true, options: { config: 'recommended', }, }, }, hooks: { postCreate: ['git init', 'node scripts/postcreate.js'], }, };

如果你不满意内置的基础模板,可以完全指定自己的模板目录,甚至覆盖内置命令。之所以保留这个接口,是因为每个团队的技术栈、场景各不相同,t3code 不该替所有团队做决定。它要做的是把“重复劳动”压缩到一个可维护的流程中,至于流程内容是什么,用户说了算。

4. 常见问题与排查技巧实录

4.1 模板文件被手动修改后,升级冲突怎么办

这是使用 t3code 过程中最容易被问到的。很多人在项目里会手动改.eslintrc或tsconfig,结果执行t3code upgrade时,工具发现本地文件与模板不一致,不知道听谁的。我的解决方案是“三层合并策略”:

  • 如果本地改动只有一行,工具会自动 merge 到新模板
  • 如果冲突区域大于 3 行,会生成一个.basename.conflict文件,并把冲突打印出来
  • 如果检测到用户曾经通过 t3code add 添加过配置,那么该配置优先级最高,不会覆盖

另外我强烈建议:不要直接修改模板生成的文件。如果你要自定义规范,要么通过t3code add添加模块,要么在项目根目录新建一个.t3code.local.js,通过配置项覆盖默认值。这样下次升级时不会到处冲突。

4.2 依赖安装失败和网络问题

创建项目时最常遇到的报错是ETIMEDOUT或ECONNRESET,特别是首次安装到一半中断。排查思路按下面步骤走:

  1. 确认 Node 版本,执行node -v,如果是 v17 以下,建议升级到 LTS 版本
  2. 查看 npm registry 配置,npm config get registry,不要用奇怪的私有镜像,遇到问题可以直接换回默认源
  3. 尽量使用 pnpm,它比 npm 在依赖目录结构和安装性能上都好不少,t3code 默认也优先推荐 pnpm
  4. 如果仍然失败,可以手动进入项目目录执行pnpm install,单独看安装日志

有一次我排查了半小时,最后发现是 .npmrc 里残留了旧项目的registry地址。这一类问题多半不是 t3code 的 bug,而是本机环境混乱导致的。

4.3 权限问题:运行命令报 EACCES

如果你用的是全局安装,可能在执行t3code时遇到Error: EACCES: permission denied。这个问题的根源是 npm 全局目录没有写权限。不建议直接用sudo修改权限,因为不安全的做法,可能破坏文件所有权。推荐方案是改用npx t3code,绕开全局目录;或者重新配置 npm 的全局前缀到一个用户目录下:

npm config set prefix '~/.npm-global'

然后把~/.npm-global/bin加入 PATH。这样再用npm i -g t3code就不会报权限错误了。

4.4 我踩过的三个坑

第一个坑:一开始把 simplify 和 lint 都配置到模板里,但过于激进,导致生成的项目规则太严格,开发时疯狂报错。后来我调整了策略:ESLint 规则只保留 recommended 级别,格式问题交给 Prettier,不重叠处理,避免两套工具打架。

第二个坑:模板文件用纯字符串拼接生成,引号层层嵌套,看代码像看意大利面。后来我全部改用 Handlebars 模板,同一个模板文件既能服务.js也能服务.ts,只需要在模板里写{{#if typescript}} import ... {{/if}}。

第三个坑:写 upgrade 合并逻辑时漏掉了“用户自定义文件”的情况。某个.babelrc里有手动加的插件,但升级后将模板版本覆盖,插件没了。现在所有 upgrade 只做增量合并,不做全量覆盖,同时会在操作前自动备份到.t3code/backup/。

这四个问题基本覆盖了最常见的使用场景。如果你遇到了其他问题,可以先执行t3code doctor,这个命令会检查环境变量、Node 版本、包管理器版本、当前项目配置文件,通常能直接定位问题所在。

我自己最得意的一点,不是 t3code 的代码多优雅,而是团队新人第一次跑通流程时问的那句:“这就结束了?不再改配置了?”工具的价值不在于它写得多么牛,而在于它被重复使用之后,帮你省下的每一分钟都在慢慢累计。脚手架不是终点,它是一个会跟着团队一起成长的活项目,后面还可以继续加模块、加模板、加更细的规则。如果你和我一样受够了重复初始化,不妨把 t3code 变成你的下一条命令。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询