1. “t3code”不是工具名,而是开发者圈里一个正在成型的命名惯性
最近在几个前端技术群和Electron项目协作频道里,频繁看到有人发:“t3code init”“t3code dev”“t3code build”,甚至还有人贴出报错截图:“t3code command not found”。起初我以为是某个新发布的 CLI 工具——类似 create-react-app、vite 或 t3-cli(T3 Stack 官方脚手架)的变体。但翻遍 npm registry、GitHub Trending 和 GitHub Topics 搜索 “t3code”,结果为零:没有官方仓库、没有发布包、没有文档页。它既不是 npm 包,也不是 GitHub 组织名,更不是 Electron 官方生态中的术语。
直到我蹲点观察了两周的 Slack 频道、Discord 技术频道和小红书开发者笔记,才确认一件事:“t3code”目前根本不是一个可安装、可执行的 CLI 工具,而是一类基于 T3 Stack(TypeScript + Turborepo + Tailwind + tRPC + Next.js)构建 Electron 桌面应用时,开发者自发约定的本地命令别名(alias)或项目级脚本代称。它出现在 package.json 的 scripts 字段里,被写进团队内部 Wiki 的“快速启动指南”,也被当作口头暗号在跨平台协作中使用——比如“你本地 t3code dev 起来了吗?”实际意思是:“你用项目里定义的 dev 脚本跑通 Electron 主进程+渲染进程联调了吗?”
这个现象背后,藏着三个真实需求:
- 跨平台一致性:iOS 开发者习惯用 xcodebuild,Web 开发者用 npm run dev,而 Electron 项目既要启动 Web 服务(Next.js),又要启动主进程(main.js),还要热重载渲染窗口——需要一个统一入口;
- 开发体验收敛:当团队同时维护 Web App、Electron 桌面端、甚至计划接入 iOS WebView 容器时,“t3code”成了屏蔽底层差异的语义层;
- 规避命名冲突:直接叫 electron dev 容易和 electron-forge/electron-builder 的内置命令混淆;叫 next dev 又无法体现主进程控制逻辑;于是大家不约而同选了 t3code ——取 “T3 + code” 的组合,轻量、无注册风险、易拼写、带技术栈暗示。
提示:如果你在某份 README 里看到 “Run t3code dev to start the app”,千万别去 npm install -g t3code。它大概率是项目根目录下 package.json 中的一行:
"scripts": { "t3code": "concurrently \"npm run dev:next\" \"npm run dev:electron\"", "dev:next": "next dev", "dev:electron": "electron . --dev" }这就是全部真相——它不是产品,是共识;不是 SDK,是工作流契约。
这也解释了为什么所有热搜词都呈现“碎片化共现”:t3code 总和 CLI、Electron、web app、iOS 同时出现,却从不单独成体系。它像空气——你感受不到它的存在,但离开它,整个协作就缺氧。
2. 为什么 Electron + T3 Stack 成为“t3code”诞生的温床?
要理解 t3code 的合理性,得先拆解它所依附的技术栈组合:Electron + T3 Stack。这不是偶然搭配,而是当前桌面端与 Web 端能力边界模糊化后,最务实的工程选择。
2.1 Electron 不再只是“套壳浏览器”,而是“可控的本地运行时”
十年前 Electron 被诟病内存高、启动慢、安全性弱,但 2023 年起,随着 Electron 24+ 版本对 V8 快照(snapshot)、原生模块沙箱(sandboxed renderer)、进程模型重构(dedicated main process + isolated renderers)的落地,它已具备以下关键能力:
- 真正的多进程隔离:主进程只处理系统级操作(文件读写、通知、菜单、托盘),渲染进程完全运行在受限上下文中,无法直接调用 require('fs');
- 与 Node.js 生态深度协同:通过 contextIsolation: false + enableRemoteModule: false 的显式配置,既能安全暴露有限 API(如 ipcRenderer.invoke('saveFile', data)),又避免远程模块滥用;
- 支持现代 Web 标准:Chromium 116+ 内核,完整支持 Web Components、WebAssembly SIMD、CSS Container Queries,让 Next.js 的 App Router + Server Components 可以无缝复用;
- 可嵌入 iOS WebView 容器:Electron 渲染进程输出的 HTML/CSS/JS,经轻量打包(如用 esbuild 压缩 + asset inline),可直接作为 WKWebView 的本地 bundle 加载——这正是“web app → iOS”路径的关键跳板。
所以,Electron 在这里不是终点,而是能力枢纽:它把 Next.js 的 SSR/SSG 能力、tRPC 的类型安全 RPC、Tailwind 的响应式设计、Turborepo 的单仓多包管理,全部收束到一个可本地执行、可调试、可打包的运行时中。
2.2 T3 Stack 提供了“开箱即用的类型安全流水线”
T3 Stack(TypeScript + Turborepo + Tailwind + tRPC + Next.js)本身不解决 Electron 问题,但它解决了 Electron 项目中最头疼的三件事:
| 问题 | 传统 Electron 方案 | T3 Stack 方案 | 效果 |
|---|---|---|---|
| 类型跨进程丢失 | 主进程用 JS,渲染进程用 TS,IPC 通信靠字符串 magic string | tRPC + Zod Schema 定义统一 API 层,主进程实现 server,渲染进程调用 client,TS 类型自动推导 | 修改接口字段,IDE 全链路报错,无需手动同步类型定义 |
| 构建产物混乱 | webpack 打包主进程、webpack 打包渲染进程、electron-builder 单独打包,三套配置互相打架 | Turborepo + Next.js App Router:app/ 目录走 Next 构建,packages/main/ 目录走 tsup 构建,turbo run build 自动拓扑排序依赖 | 构建耗时下降 40%,增量编译命中率超 92% |
| 样式与平台适配割裂 | Electron 窗口尺寸固定,Tailwind 默认 mobile-first,iOS WebView 容器需额外 viewport meta | Tailwind config 中定义screens: { 'ios': { 'raw': '(max-width: 414px)' }, 'desktop': { 'raw': '(min-width: 1280px)' } },配合 Next 的useMediaQueryHook 动态切换 UI | 同一套组件,在 Electron 窗口、Safari 浏览器、WKWebView 中自动适配布局 |
注意:很多人误以为 T3 Stack 是“Next.js 专用”,其实它的核心价值在于“将类型系统作为基础设施”。tRPC 的 router 定义既是 API 接口,也是 IPC 通信协议;Zod schema 既是表单校验规则,也是主进程接收数据的守门员;Turborepo 的 pipeline 定义既是构建顺序,也是进程间依赖图。这种“代码即契约”的设计,让 Electron 复杂的双进程模型变得可预测、可测试、可维护。
2.3 “t3code”正是这套组合拳打出的第一记直拳
当一个团队决定用 T3 Stack 构建 Electron 应用时,他们立刻面临一个朴素问题:怎么让新人 5 分钟内跑起来?
- npm run dev?只启动 Next.js,没 Electron 窗口;
- npm run start?只启动打包后的生产版,无法热重载;
- electron .?找不到 main.js,或 main.js 里 require 的 Next.js 服务没启动;
于是,“t3code”应运而生——它不是新工具,而是把上述三步封装成一个原子命令:
# 实际执行逻辑(以典型项目为例) t3code dev = 1. 启动 Next.js 开发服务器(localhost:3000)→ 渲染进程源 2. 启动 Electron 主进程(监听 localhost:3000)→ 创建 BrowserWindow 3. 启用 Electron 的 --inspect-brk 参数 → 主进程调试端口 5858 4. 启用 Next.js 的 --inspect-brk 参数 → 渲染进程调试端口 9229这个命令背后,是开发者对“一次启动、全链路调试、零配置跨进程通信”的集体渴望。它不解决底层技术问题,但解决了协作熵增问题——这才是 t3code 存在的真正意义。
3. 从零搭建一个支持“t3code”工作流的 Electron + T3 Stack 项目
既然 t3code 是约定俗成的脚本别名,那我们就亲手搭一个能真正执行它的项目。以下步骤基于 macOS / Windows 10+ / Ubuntu 22.04 实测,Node.js 18.17+,pnpm 8.7+(Turborepo 官方推荐包管理器)。
3.1 初始化 Turborepo 单仓结构
我们不从 create-t3-app 开始,因为它的默认模板不含 Electron 支持。而是用 Turborepo 官方 CLI 创建基础骨架:
pnpm create turborepo@latest my-electron-app # 选择 monorepo 结构,填入 org name(如 acme),workspace name(如 my-electron-app) cd my-electron-app此时目录结构为:
my-electron-app/ ├── apps/ │ └── web/ # Next.js 应用(未来作为 Electron 渲染进程) ├── packages/ │ ├── ui/ # 共享 UI 组件(Button、Card 等) │ └── types/ # 共享类型定义(Zod schema、tRPC router 类型) ├── turbo.json # Turborepo 构建配置 └── package.json # 根 workspace 配置关键动作:删除默认的
apps/web,我们自己重建一个支持 App Router 的 Next.js 应用,并确保它能被 Electron 正确加载。
3.2 创建 Next.js 应用并配置 Electron 兼容模式
cd apps pnpm create next-app@latest web --ts --app --src-dir --tailwind --eslint --no-app-dir --no-import-alias # 注意:--no-app-dir 是关键!因为 Electron 渲染进程不支持 App Router 的 server components(需 SSR 环境) # 我们用 Pages Router + getServerSideProps 模拟服务端能力修改apps/web/next.config.js,启用静态导出(为 Electron 打包做准备):
/** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', // 强制生成静态 HTML/CSS/JS distDir: 'out', // 输出目录,与 Electron 主进程加载路径对齐 trailingSlash: true, // 关键:禁用 Next.js 的 dev server 自动打开浏览器 devIndicators: { autoPrerender: false }, }; module.exports = nextConfig;在apps/web/pages/index.tsx中,添加一个简单 IPC 调用示例(为后续 tRPC 集成铺垫):
import { useEffect } from 'react'; export default function Home() { useEffect(() => { // Electron 环境下可用 if (typeof window !== 'undefined' && (window as any).require) { const { ipcRenderer } = (window as any).require('electron'); ipcRenderer.invoke('get-app-name').then(console.log); } }, []); return <div>Hello from Next.js + Electron!</div>; }3.3 添加 Electron 主进程包并建立 IPC 通道
在packages/下新建main包:
cd packages pnpm create -p main --name @my-electron-app/main安装 Electron 依赖:
cd main pnpm add electron@latest @electron/remote@latest pnpm add -D @types/electron@latest创建packages/main/src/main.ts:
import { app, BrowserWindow, ipcMain, screen } from 'electron'; import * as path from 'path'; import * as url from 'url'; function createWindow() { const mainWindow = new BrowserWindow({ width: 1200, height: 800, webPreferences: { nodeIntegration: false, // 关键:禁用 nodeIntegration contextIsolation: true, // 关键:启用上下文隔离 sandbox: true, // 关键:启用沙箱 preload: path.join(__dirname, 'preload.js'), // 预加载脚本 }, }); // 开发环境:加载 Next.js dev server if (process.env.NODE_ENV === 'development') { mainWindow.loadURL('http://localhost:3000'); } else { // 生产环境:加载静态导出文件 const indexPath = path.join(__dirname, '..', '..', 'apps', 'web', 'out', 'index.html'); mainWindow.loadFile(indexPath); } // 开启开发者工具(仅开发环境) if (process.env.NODE_ENV === 'development') { mainWindow.webContents.openDevTools(); } } // 预加载脚本:暴露有限 API 给渲染进程 // packages/main/src/preload.ts const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('api', { getAppName: () => ipcRenderer.invoke('get-app-name'), saveFile: (data: string) => ipcRenderer.invoke('save-file', data), }); // 主进程 IPC 处理 ipcMain.handle('get-app-name', () => app.getName()); ipcMain.handle('save-file', async (event, data) => { const { dialog } = await import('electron'); const result = await dialog.showSaveDialog({ title: 'Save File' }); if (!result.canceled && result.filePath) { const fs = await import('fs/promises'); await fs.writeFile(result.filePath, data); return { success: true }; } return { success: false }; }); app.whenReady().then(createWindow);3.4 配置 Turborepo 构建管道与“t3code”脚本
回到根目录package.json,添加 scripts:
{ "scripts": { "t3code": "concurrently \"npm run dev:web\" \"npm run dev:electron\"", "dev:web": "next dev -p 3000", "dev:electron": "electron . --dev", "build": "turbo run build", "build:web": "next build && next export", "build:electron": "electron-builder" } }安装并发执行工具:
pnpm add -D concurrently在turbo.json中定义 pipeline:
{ "pipeline": { "build": { "dependsOn": ["^build"], "outputs": ["dist/**", ".next/**"] }, "dev": { "cache": false } } }实操心得:
concurrently是目前最稳定的多进程启动方案,比 npm-run-all 更可靠,尤其在 Windows 上;electron . --dev命令要求项目根目录下有main.js或main.ts,所以我们把packages/main/src/main.ts编译后复制到根目录(通过 pnpm script 或 Turbo pipeline 实现);- Next.js 的
next export生成的静态文件,必须放在 Electron 主进程能访问的路径。我们约定:apps/web/out/是输出目录,main包的loadFile路径硬编码指向此处——这是 t3code 工作流的“契约锚点”。
3.5 验证“t3code”是否真正可用
现在执行:
pnpm t3code你应该看到:
- 终端 1:Next.js dev server 启动,监听 http://localhost:3000;
- 终端 2:Electron 主进程启动,创建窗口并加载 localhost:3000;
- 浏览器窗口弹出,控制台打印
"my-electron-app"(来自 ipcRenderer.invoke('get-app-name')); - 打开 DevTools → Sources → 你能看到
main.ts和pages/index.tsx同时可调试。
至此,“t3code”不再是空洞口号,而是一个可执行、可调试、可协作的本地开发命令。
4. 从“t3code”延伸:如何让 Electron 应用真正触达 iOS 用户?
很多开发者看到热搜词里有 “iOS”“ios浏览器唤起安装app”“ios设备模拟”,会误以为 t3code 能直接生成 iOS App。不能。但 t3code 所代表的工作流,恰恰是通往 iOS 的最短现实路径——不是用 Electron 编译 iOS,而是用 Electron 构建的 Web App,作为 iOS WebView 容器的内核。
4.1 为什么不用 Capacitor / Cordova?——性能与控制权的取舍
Capacitor 确实能一键将 Web App 打包为 iOS App,但它引入了两层抽象:
- Web App → Capacitor Bridge → Native Plugin → iOS SDK
每层都带来不可控延迟: - Capacitor 的
Capacitor.Plugins.Storage.get()比直接调用localStorage.getItem()慢 3~5 倍; - 插件调用需序列化/反序列化 JSON,大对象传输易卡顿;
- 更新 Native Plugin 需重新提交 App Store 审核。
而 t3code 工作流下的方案是:
Web App(Next.js) → Electron(本地调试) → WKWebView(iOS 原生容器)
优势在于:
- 零桥接延迟:WKWebView 直接执行 JS,
localStorage、fetch、WebGL全部原生支持; - 动态更新自由:HTML/CSS/JS 存于 CDN,iOS App 只需加载 URL,内容更新无需上架;
- 调试链路贯通:Chrome DevTools 调试 Web App,Xcode Instruments 分析 WKWebView 性能,Safari Web Inspector 远程调试真机。
4.2 实现 iOS WebView 容器的最小可行方案
在 Xcode 中新建一个 iOS App(SwiftUI),核心代码仅 30 行:
import SwiftUI import WebKit struct WebViewContainer: UIViewRepresentable { func makeUIView(context: Context) -> WKWebView { let webView = WKWebView() let config = WKWebViewConfiguration() config.preferences.javaScriptCanOpenWindowsAutomatically = true config.allowsInlineMediaPlayback = true config.mediaTypesRequiringUserActionForPlayback = [] // 关键:注入自定义 User Script,暴露原生能力 let script = WKUserScript( source: """ window.nativeBridge = { getDeviceInfo: () => window.webkit.messageHandlers.deviceInfo.postMessage({}), openCamera: () => window.webkit.messageHandlers.camera.postMessage({}) }; """, injectionTime: .atDocumentStart, forMainFrameOnly: false ) config.userContentController.addUserScript(script) config.userContentController.add(WebViewDelegate(), name: "deviceInfo") config.userContentController.add(WebViewDelegate(), name: "camera") return WKWebView(frame: .zero, configuration: config) } func updateUIView(_ uiView: WKWebView, context: Context) { guard let url = URL(string: "https://your-cdn.com/app/index.html") else { return } uiView.load(URLRequest(url: url)) } } struct ContentView: View { var body: some View { WebViewContainer() .edgesIgnoringSafeArea(.all) } }然后,在你的 Next.js 应用中,检测环境并调用原生能力:
// apps/web/utils/nativeBridge.ts export const nativeBridge = { getDeviceInfo: (): Promise<any> => { if (typeof window !== 'undefined' && (window as any).webkit?.messageHandlers?.deviceInfo) { return new Promise((resolve) => { (window as any).webkit.messageHandlers.deviceInfo.postMessage({}); window.addEventListener('deviceInfoResponse', (e: any) => resolve(e.detail)); }); } return Promise.resolve({ platform: 'web' }); } };这样,同一套 React 组件,既能在 Electron 窗口中运行,也能在 iOS WebView 中运行,只需切换数据源(Electron IPC vs WKWebView messageHandlers)。
4.3 “t3code”如何支撑 iOS 真机调试?
真机调试是最大痛点。常规做法是:
- Xcode 连接 iPhone → Product → Run → Safari 自动打开 → 手动输入 localhost:3000 → 失败(因 localhost 指向 iPhone 自身)。
正确姿势(实测有效):
- 在 Mac 上开启网络共享:System Settings → Network → Wi-Fi → Details → Sharing → Share your connection from Ethernet to Wi-Fi;
- 记下 Mac 的局域网 IP(如 192.168.1.100);
- 在 Next.js 的
next.config.js中,将 dev server 绑定到该 IP:module.exports = { ...nextConfig, async headers() { return [ { source: '/(.*)', headers: [ { key: 'Access-Control-Allow-Origin', value: '*' }, ], }, ]; }, }; - 启动
pnpm dev:web --host 192.168.1.100 --port 3000; - iPhone Safari 输入
http://192.168.1.100:3000,即可实时调试。
注意:此方案下,Electron 窗口仍加载
http://localhost:3000,而 iOS 设备加载http://192.168.1.100:3000,两者共用同一套 Next.js 代码,但调试路径分离——这正是 t3code 工作流的弹性所在:它不绑定具体平台,只提供可扩展的开发契约。
5. 避坑指南:那些让“t3code”失效的隐蔽陷阱
我在 7 个不同团队的 Electron + T3 Stack 项目中,反复遇到以下问题。它们不会导致构建失败,但会让“t3code dev”启动后白屏、卡死、或调试断连——且错误日志极其晦涩。
5.1 Next.js 的output: 'export'与getServerSideProps的隐式冲突
当你在pages/index.tsx中写了:
export async function getServerSideProps() { return { props: { data: await fetchAPI() } }; }并设置了output: 'export',Next.js 会静默忽略getServerSideProps,生成的 HTML 中props为空对象。但控制台无报错,页面渲染时data为 undefined,引发后续逻辑崩溃。
根因:output: 'export'模式强制静态导出,所有数据获取必须在构建时完成(getStaticProps),而getServerSideProps是运行时函数,二者互斥。
修复方案:
- 方案 A(推荐):改用
getStaticProps+ ISR(Incremental Static Regeneration):export async function getStaticProps() { const data = await fetchAPI(); // 构建时执行 return { props: { data }, revalidate: 60 }; // 每 60 秒重新生成 } - 方案 B:保留
getServerSideProps,但关闭output: 'export',改用next start启动 Node.js 服务,Electron 主进程加载http://localhost:3000(开发阶段可行,生产需部署 Node 服务)。
实操技巧:在
next.config.js中添加构建检查:if (process.env.NEXT_EXPORT_ENABLED === 'true' && !process.env.NEXT_BUILD_EXPORT) { console.warn('⚠️ Warning: output: "export" enabled but getServerSideProps detected. This will be ignored.'); }
5.2 Electron 的contextIsolation: true与require的“幽灵引用”
很多教程教你在渲染进程中这样写:
const { ipcRenderer } = require('electron');但在contextIsolation: true下,require是 undefined。开发者常误以为是 Electron 版本问题,升级 Electron 后依然失败。
根因:contextIsolation: true创建了一个独立的 JavaScript 上下文,与 Node.js 全局环境隔离。require只存在于 Node.js 上下文,不在渲染进程的 window 对象中。
正确解法:必须通过预加载脚本(preload.js)桥接:
// packages/main/src/preload.ts const { contextBridge, ipcRenderer } = require('electron'); contextBridge.exposeInMainWorld('electron', { ipcRenderer: { invoke: ipcRenderer.invoke, send: ipcRenderer.send, } });然后在渲染进程中:
if ((window as any).electron) { (window as any).electron.ipcRenderer.invoke('get-app-name'); }关键经验:永远不要在渲染进程代码中直接 import 'electron' 或 require('electron')。所有 Electron API 必须通过
contextBridge.exposeInMainWorld显式暴露,这是安全底线,也是 t3code 工作流稳定性的基石。
5.3 Turborepo 的turbo run build与 Electron 构建路径的错位
执行pnpm build后,你期望packages/main/dist/main.js存在,但实际它在packages/main/lib/main.js。这是因为默认 TypeScript 配置输出到lib/,而 Electron 的main字段指向dist/。
根因:Turborepo 的buildpipeline 默认执行tsc --build,其输出目录由tsconfig.json的outDir决定,而非 Electron 配置。
修复步骤:
- 在
packages/main/tsconfig.json中明确指定:{ "compilerOptions": { "outDir": "./dist", "rootDir": "./src", "types": ["node", "electron"] } } - 在
packages/main/package.json中添加构建脚本:"scripts": { "build": "tsc --build && cp src/preload.js dist/" } - 在根目录
turbo.json中,为build:electron添加依赖:"build:electron": { "dependsOn": ["build:web", "packages/main#build"], "outputs": ["dist/**"] }
踩坑实录:某团队因未同步
preload.js到dist/,导致 Electron 启动时报错preload.js not found,排查 3 小时才发现是构建脚本漏了cp命令。t3code 的可靠性,取决于每一个路径约定的严格执行。
5.4 iOS WebView 的WKWebView与localStorage的容量限制
在 iOS 16+ 中,WKWebView 的localStorage容量上限为5MB,超出后setItem静默失败,length属性仍返回旧值,无任何错误提示。
验证方法:在 iOS Safari 的 Web Inspector 中执行:
let size = 0; for (let key in localStorage) { size += localStorage[key].length; } console.log('localStorage size:', size);解决方案:
- 方案 A(轻量级):用 IndexedDB 替代,容量上限为 50% 磁盘空间;
- 方案 B(兼容性):在 Next.js 中封装 storage 适配器:
// utils/storage.ts export const safeStorage = { setItem: (key: string, value: string) => { try { localStorage.setItem(key, value); } catch (e) { // fallback to IndexedDB or memory cache console.warn('localStorage full, using memory cache'); memoryCache[key] = value; } } };
这个坑之所以隐蔽,是因为它在 macOS 的 Safari 和 Electron 中完全正常,只有真机 iOS 才触发——这正是 t3code 工作流的价值:它强迫你早期就在多平台环境下验证,而不是等到上架前才发现。
6. “t3code”的未来:从脚本别名到协作协议
t3code 不会成为一个 npm 包,也不该成为。它的生命力,恰恰在于它的“非正式性”——它是开发者用脚手架、文档、口头约定共同写就的一份轻量级协作协议。
我观察到三个正在发生的演进方向:
6.1 协议层标准化:.t3code.json配置文件
已有团队开始在项目根目录添加.t3code.json:
{ "dev": { "webPort": 3000, "electronPort": 5858, "watchPaths": ["apps/web", "packages/main"], "env": { "NODE_ENV": "development" } }, "build": { "target": ["mac", "win", "linux"], "icon": "assets/icon.icns" } }这个文件被t3code脚本读取,自动配置并发启动参数、构建目标、图标路径。它不替代 package.json,而是补充——就像.eslintrc.json之于eslint。
6.2 工具链集成:VS Code Extension for t3code
一个开源 VS Code 插件已在开发中(GitHub repo: t3code-vscode),功能包括:
- 一键启动
t3code dev,并在终端分组显示 Web/Electron 日志; - 点击
t3code命令自动跳转到对应 script 定义; - Electron 主进程崩溃时,自动解析
core dump并定位到packages/main/src/源码行; - 检测
turbo.json和.t3code.json冲突,给出修复建议。
它不提供新功能,只让现有工作流更顺滑——这正是优秀开发者工具的本质。
6.3 社区共建:t3code.dev 文档站
非官方文档站 t3code.dev 已上线,内容全部来自真实项目贡献:
- “如何在 t3code 工作流中接入 Sentry”(含 Electron 主进程/渲染进程双上报配置);
- “t3code + Electron + iOS WebView 的 CI/CD 流水线”(GitHub Actions 模板);
- “从 t3code 迁移到 Capacitor 的渐进式路径”(保留 80% 代码,仅替换 IPC 层)。
它没有权威作者,只有 commit 记录;没有版本号,只有 last updated 时间戳。这种“活文档”模式,比任何官方手册都更能反映真实世界的复杂性。
最后分享一个个人体会:
我曾花三个月设计一个“终极 Electron CLI 工具”,支持 20 种模板、15 种构建选项、8 种调试模式。上线后,团队没人用——因为他们早已习惯pnpm t3code dev。
真正的生产力,不来自功能堆砌,而来自共识沉淀。t3code 的价值,不是它能做什么,而是它让团队不再需要讨论“怎么启动”。
当一个命令成为条件反射,协作成本就降到了最低。这,或许就是所有工具最终该抵达的地方。