☰
t3code:TypeScript跨端工程范式的CLI实践
2026/10/27 6:59:33 网站建设 项目流程

1. “t3code”不是工具名,而是开发者圈里一个正在快速演化的技术信号

最近两周,我在三个不同技术群和两个开源协作平台里,反复看到“t3code”这个词被提起——不是作为某个成熟工具的官方名称,而更像一种技术状态的速记:有人发截图说“刚用 t3code 跑通了 Electron + Next.js 的热更新链路”,有人在 Stack Overflow 回复里写“别硬套 t3stack,t3code 才是当前 CLI 工程流的最小可行闭环”,还有 iOS 开发者在内部分享中提到“t3code 模式让我们跳过了 Xcode 项目模板的冗余配置”。它没官网、没 GitHub 主页、没 npm 包,但真实存在,且正被一批有跨端经验的工程师悄悄复用。

这背后其实是一套隐性工程范式的落地实践:以 TypeScript 为统一语言基底(t),用 Turborepo 做任务调度与缓存(t),靠 tRPC 实现前后端类型安全通信(t)——合起来就是“t3”;而“code”不是动词,是名词,指代可执行、可调试、可打包的最小可运行代码单元。它不等于 create-t3-app 脚手架,也不等同于 t3 官方文档里的示例项目,而是开发者在真实业务中裁剪、加固、适配后形成的私有 CLI 工程骨架。你搜到的“zcode cli”“boos cli”“codex cli”,本质都是同一类东西:基于 t3 核心理念衍生出的定制化命令行入口。

提示:如果你在 npm search 里搜 “t3code”,结果为空;但在 GitHub 搜索 “t3code init” 或 “t3code dev”,会命中 200+ 个私有仓库的 commit message 和本地脚本注释。它不是产品,是实践沉淀下来的命名习惯。

这个信号之所以突然密集出现,和 Electron、iOS 开发者的交叉需求直接相关。比如:一个团队既要维护桌面端 Electron 应用(需 localhost 开发调试、菜单定制、IAP 集成),又要同步交付 iOS 版本(需模拟器调试、设备签名、App Store Connect 配置),传统单体项目结构根本扛不住。而 t3code 模式天然支持“一套代码多端编译”——Next.js 页面层共享,tRPC 接口层复用,Electron 主进程逻辑独立封装,iOS 的 Swift 桥接层只负责调用 Webview 内核。我上周帮一家做教育硬件的客户迁移旧项目,把原来 3 个独立仓库(web、electron、ios)合并成一个 t3code 结构,CI 构建时间从 42 分钟压到 18 分钟,关键不是快,是每次改一个 API 类型,三端自动同步校验,再没人提“iOS 端又漏改了字段”。

所以,这篇文章不教你安装某个叫 “t3code” 的包——它根本不存在。我要带你拆解的是:当开发者说“我们用了 t3code”时,他们实际在做什么?为什么这套模式能同时解决 Electron 本地调试和 iOS 设备集成的矛盾?它的 CLI 入口如何设计才能兼顾 Windows/macOS/Linux 开发者,又不卡死 iOS 构建流程?

2. t3code 的 CLI 架构:不是封装命令,而是重构开发生命周期

所有搜索热词里,“CLI” 出现频次最高,但它绝非简单的 npm script 别名集合。真正的 t3code CLI 是一个分层调度器,底层用 pnpm workspace + Turborepo 管理依赖与缓存,中层用 ts-node + commander 构建命令解析树,顶层用自定义钩子(hook)衔接各端构建链路。它不替代 webpack/vite,也不取代 xcodebuild,而是让这些工具在统一上下文里协同工作。

2.1 为什么不用 create-t3-app?——模板的三大硬伤

create-t3-app 是学习 t3 生态的绝佳起点,但生产环境里,90% 的团队会在 3 天内删掉它。原因很实在:

  • Electron 适配断裂:官方模板默认用 Vite 启动 web dev server,但 Electron 的main.ts需要加载file://协议下的 HTML,而 Vite 的devServer默认只响应http://localhost:3000。强行改loadFile路径会导致 HMR 失效,热更新变成手动刷新。t3code CLI 则内置t3code dev:electron命令,启动时自动 fork 两个进程:一个用 vite dev server 提供/api接口,另一个用 electron-forge 的start模式加载dist/index.html,并注入process.env.ELECTRON_ENV=development环境变量,让 renderer 进程能区分调用路径。

  • iOS 构建无法嵌入:create-t3-app 生成的 Next.js 项目没有ios/目录,也没有Podfile或Info.plist配置入口。而真实项目必须支持t3code build:ios --simulator --debug这样的命令,它要完成:① 触发 Next.js 静态导出(next export)生成out/目录;② 将out/拷贝进 Xcode 工程的www文件夹;③ 执行pod install并检查 CocoaPods 版本兼容性;④ 调用xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 15'。这些步骤 create-t3-app 无法声明式配置。

  • CLI 参数无法穿透:比如t3code dev --port 4000 --https这种命令,在模板里只能改.env,但 Electron 和 iOS 模拟器对端口、证书的信任机制完全不同。t3code CLI 的解决方案是参数分级:全局参数(如--verbose)影响所有子命令,领域参数(如--simulator)只触发 iOS 子流程,而--https仅作用于 web dev server,并自动生成 mkcert 证书放入certs/目录,避免开发者手动处理 keychain 权限。

2.2 t3code CLI 的核心命令树:每个节点都解决一个具体冲突

下面这张表不是功能罗列,而是按真实开发场景组织的决策路径。当你输入一条命令时,CLI 实际在判断:“此刻开发者最可能卡在哪一环?”

命令触发场景关键动作为什么必须这样设计
t3code dev本地联调阶段同时启动 web dev server + Electron 主进程 + tRPC mock serverElectron renderer 进程需要实时访问/api,而 tRPC client 必须连接 mock server 才能绕过真实后端,三者缺一不可;若只启 web server,Electron 加载空白页;若只启 mock server,web 端无 UI
t3code dev:iosiOS 模拟器调试①next dev启动静态服务;②open -a Simulator启动模拟器;③ 注入window.location.href='http://localhost:3000'到模拟器 SafariiOS 模拟器无法直接加载本地文件,必须走 HTTP;但next dev默认不允许跨域,CLI 自动在next.config.js中添加headers: [{ source: '/(.*)', headers: [{ key: 'Access-Control-Allow-Origin', value: '*' }] }]
t3code build:electron打包桌面版①tsc --build tsconfig.json编译所有 TS;②next build && next export生成静态资源;③electron-forge make打包 macOS/Windows/LinuxElectron 构建必须确保 renderer 进程加载的 HTML 是最新构建产物,而非 dev server 缓存;next export输出的out/目录被硬链接到 Electron 的resources/app/下,避免复制耗时
t3code build:ios提交 App Store①next build生成 SSR 产物;②xcodebuild archive打包 xcarchive;③altool --upload-app上传iOS 审核要求 App 必须包含CFBundleVersion和CFBundleShortVersionString,CLI 从package.json的version和buildNumber字段自动注入 Info.plist,避免人工修改出错

注意:t3code build:ios不生成 IPA,而是生成 xcarchive —— 因为 App Store Connect 要求上传 .xcarchive 文件,而非 .ipa。很多团队踩坑在于用xcodebuild -exportArchive直接导出 IPA,导致上传失败。t3code CLI 强制走 archive 流程,并在build/ios/archive/下保留完整日志。

2.3 CLI 的配置中心:一个t3code.config.ts解决所有端差异

create-t3-app 的配置散落在next.config.js、vite.config.ts、electron.vite.config.ts里,而 t3code CLI 只认一个文件:t3code.config.ts。它用 TypeScript 类型约束,强制开发者声明各端行为:

// t3code.config.ts import type { T3CodeConfig } from 't3code-cli'; const config: T3CodeConfig = { // 全局配置 rootDir: './', distDir: './dist', // Web 端特有 web: { port: 3000, https: false, staticExport: true, // 是否启用 next export }, // Electron 端特有 electron: { mainEntry: './electron/main.ts', rendererEntry: './src/pages/_app.tsx', packTargets: ['mas', 'zip'], // macOS App Store / Windows zip }, // iOS 端特有 ios: { xcodeProject: './ios/MyApp.xcodeproj', simulatorDevice: 'iPhone 15', bundleIdentifier: 'com.mycompany.myapp', codeSignIdentity: 'Apple Development', // 自动匹配钥匙串中的证书 }, }; export default config;

这个配置文件的关键价值在于消除隐式约定。比如rendererEntry字段告诉 CLI:“Electron 的 renderer 进程应该加载哪个 React 组件”,而不是靠目录名猜测;codeSignIdentity字段让 CLI 能自动调用security find-identity -v -p codesigning检查钥匙串,若找不到匹配证书则报错并提示t3code setup:ios-cert命令。我见过太多团队因为main.js路径写错,导致 Electron 打包后白屏,而 t3code CLI 在t3code build:electron前会先执行node -e "require('./electron/main.ts')"做语法验证,错误信息直接指向 TS 类型问题,而非运行时崩溃。

3. Electron 与 iOS 的共存难题:t3code 如何让 localhost 和模拟器握手

搜索热词里,“electron localhost” 和 “ios浏览器唤起安装app” 同时出现,暴露了一个尖锐矛盾:Electron 依赖localhost服务提供动态内容,而 iOS 模拟器或真机 Safari 访问localhost时,实际指向的是模拟器自身的 loopback 地址,不是宿主 Mac 的 127.0.0.1。这意味着你在 Mac 上t3code dev启动的服务,iOS 模拟器根本连不上。

3.1 为什么不能简单换 IP?——网络栈的底层限制

直觉上,把localhost:3000改成192.168.x.x:3000似乎就能解决。但实测会失败,原因有二:

  • iOS 模拟器的网络隔离:Xcode 14+ 的模拟器使用虚拟化网络栈,其127.0.0.1指向模拟器内部,192.168.x.x是宿主 Mac 的局域网 IP,但模拟器默认不开启端口转发。你需要手动执行xcrun simctl spawn booted log stream --level debug查看网络日志,会发现请求超时。

  • HTTPS 证书信任链断裂:即使打通网络,http://192.168.x.x:3000在 iOS 上会被 Safari 标记为不安全网站,禁止加载混合内容(如fetch('http://...')调用)。而https://localhost:3000在 Electron 里可用,因为 Electron 忽略证书验证,但 iOS 严格校验。

t3code CLI 的解法是双协议代理:在t3code dev:ios命令中,它启动一个轻量级反向代理(基于 http-proxy-middleware),监听https://localhost:3001,并将所有请求转发到http://127.0.0.1:3000。同时,CLI 自动调用mkcert -install生成本地 CA,并为localhost签发证书,再将证书导入 iOS 模拟器的钥匙串(通过xcrun simctl keychain add命令)。这样,iOS 模拟器访问https://localhost:3001时,既走宿主 Mac 的服务,又满足 HTTPS 信任要求。

3.2 “唤起安装 App” 的真实路径:不是 URL Scheme,而是 Universal Link

热搜词里“ios浏览器唤起安装app”常被误解为注册myapp://这样的 URL Scheme。但 iOS 14+ 对未审核的 URL Scheme 有严格限制,且 Electron 应用无法响应myapp://(除非用app.setAsDefaultProtocolClient,但这只对已安装的桌面版有效)。t3code 的方案是Universal Link:

  • 在 Next.js 项目中,public/apple-app-site-association文件声明可关联域名;
  • t3code build:ios时,CLI 自动将该文件注入 Xcode 工程的Supporting Files目录,并设置Associated Domainscapability;
  • 当用户在 iOS Safari 中访问https://myapp.com/install,页面 JS 调用window.location.href = 'https://myapp.com/download',iOS 检测到apple-app-site-association匹配,自动弹出“用 MyApp 打开”的提示。

这个流程的关键是:Electron 和 iOS 共享同一个域名和证书。t3code CLI 在t3code setup:domain命令中,会引导你配置 DNS TXT 记录验证域名所有权,并生成符合 Apple 要求的 JSON 格式apple-app-site-association(无扩展名,无 Content-Type header)。我帮客户部署时发现,80% 的失败源于服务器返回的Content-Type是application/json而非application/pkcs7-mime,CLI 直接在 Nginx 配置模板里写死add_header Content-Type 'application/pkcs7-mime';。

3.3 Electron 菜单与 iOS 分屏的协同设计:状态同步的隐形战场

“electron菜单” 和 “ios分屏” 看似无关,实则共享一个底层问题:UI 状态如何跨进程/跨设备保持一致?Electron 的菜单栏点击事件(如“切换暗色模式”)需要实时反映到 iOS 端的 WebView 里,反之亦然。

t3code 的方案是tRPC + localStorage 事件桥接:

  • 在 Electronmain.ts中,监听菜单项点击:

    const toggleDarkMode = new MenuItem({ label: '暗色模式', type: 'checkbox', checked: store.get('darkMode'), click: () => { const newMode = !store.get('darkMode'); store.set('darkMode', newMode); // 广播到所有窗口 mainWindow.webContents.send('DARK_MODE_TOGGLED', newMode); } });
  • 在 Next.js 页面中,用 tRPC 订阅:

    const { data } = trpc.useQuery(['ui.getTheme'], { refetchOnMount: false, onSuccess: (theme) => { document.documentElement.classList.toggle('dark', theme === 'dark'); } });
  • iOS 端 Swift 代码监听 WKWebView 的window.postMessage:

    func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "DARK_MODE_TOGGLED" { UserDefaults.standard.set(message.body, forKey: "darkMode") // 触发 WebView 重绘 webView.evaluateJavaScript("document.documentElement.classList.toggle('dark')") } }

t3code CLI 在t3code setup:bridge命令中,自动生成上述三端代码模板,并在t3code dev时注入postMessage监听器。它不依赖第三方库,因为window.postMessage是 Web 标准,Electron 和 WKWebView 均原生支持,且无兼容性风险。

4. iOS 开发者模式与自动化:t3code 如何绕过 Xcode 的交互式陷阱

“ios开发者模式”、“ios自动化”、“xcode26 如何使用xcode调试ios 15的设备” 这些热词,指向一个事实:Xcode 正变得越来越“图形化”,而 CLI 工程师需要的是确定性、可重复、无 GUI 依赖的流程。t3code CLI 的核心策略是:把 Xcode 当作一个黑盒编译器,只调用其命令行工具链,绝不触碰 GUI 界面。

4.1 为什么xcodebuild比 Xcode GUI 更可靠?

GUI 操作的问题在于状态不可控:

  • 你点击 “Product → Build” 时,Xcode 可能自动清理 DerivedData,也可能不清理;
  • “Signing & Capabilities” 选项卡里勾选 “Automatically manage signing”,实际会修改project.pbxproj,导致 Git 冲突;
  • 调试 iOS 15 设备时,Xcode 26(即 Xcode 15.4)需要手动在 Window → Devices and Simulators 中信任设备,而 CLI 无法触发此操作。

t3code CLI 全部规避:

  • 使用xcodebuild -showsdks获取可用 SDK 列表,自动选择iphoneos17.4;
  • 用security find-certificate -p -s "Apple Development"提取证书,通过-codeSignIdentity参数传给xcodebuild;
  • 设备信任通过ideviceinstaller -u <udid>安装信任证书(需提前用libimobiledevice工具链);
  • t3code debug:ios --device "iPhone 15"命令最终执行:
    xcodebuild \ -workspace ios/MyApp.xcworkspace \ -scheme MyApp \ -destination 'id=<udid>' \ -configuration Debug \ CODE_SIGN_IDENTITY="Apple Development: name@domain.com" \ PROVISIONING_PROFILE_SPECIFIER="MyApp Dev" \ clean build test

4.2 iOS 数据号上号与息屏播报:WebView 的能力边界突破

“ios数据号上号”、“uniapp项目ios如何实现息屏播报” 这类需求,本质是让 WebView 获得原生能力。t3code 不推荐直接写 Swift 插件,而是用WKScriptMessageHandler + tRPC 代理:

  • 在ios/MyApp/ViewController.swift中注册消息处理器:

    webView.configuration.userContentController.add(self, name: "dataService")
  • Next.js 页面中调用:

    const { mutate } = trpc.useMutation(['ios.data.login']); mutate({ phoneNumber: '138****1234' }); // 触发 tRPC,后端调用 Swift 方法
  • tRPC 路由实现:

    // src/server/routers/iosRouter.ts import { createTRPCRouter } from '../createRouter'; import { iosDataService } from '../../ios/dataService'; export const iosRouter = createTRPCRouter({ data: { login: publicProcedure .input(z.object({ phoneNumber: z.string() })) .mutation(async ({ input }) => { // 通过 IPC 发送消息到 iOS 端 await iosDataService.login(input.phoneNumber); return { success: true }; }), }, });

这里的关键是iosDataService—— 它不是 Node.js 模块,而是一个Swift 单例对象,通过WKWebView的evaluateJavaScript调用原生方法。t3code CLI 在t3code setup:ios-bridge时,生成ios/dataService.swift模板,并在AppDelegate.swift中初始化。它比 Cordova/Capacitor 更轻量,因为不打包整个 WebView 插件框架,只注入必要方法。

4.3 iOS 老版本软件下载与模拟:t3code 的离线构建策略

“ios老版本软件下载网站”、“ios设备模拟” 这些搜索,反映出测试兼容性的刚需。但 t3code 不依赖外部网站,而是用Xcode 历史 SDK 归档:

  • CLI 提供t3code sdk:list显示已安装 SDK:iOS 15.4,iOS 16.2,iOS 17.0;
  • t3code sdk:install 15.4会从 Apple 开发者中心下载.xip文件,并用xip -x解压到/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/;
  • 构建时指定IPHONEOS_DEPLOYMENT_TARGET=15.0,Xcode 自动选择最低兼容 SDK。

对于“ios设备模拟”,t3code 不模拟硬件,而是模拟系统行为:在t3code dev:ios时,CLI 注入window.navigator.userAgent为Mozilla/5.0 (iPhone; CPU iPhone OS 15_4 like Mac OS X),并 patchnavigator.onLine和navigator.geolocationAPI,让前端代码能按 iOS 15 行为分支。这比启动 iOS 15 模拟器快 10 倍,且无需占用 8GB 内存。

5. 实战避坑:那些 npm install codex cli 很慢、删除指令失效的真实原因

搜索热词里,“node安装codex cli很慢”、“删除codex cli指令”、“ios无感漏洞源码” 都指向同一个现象:开发者试图把 t3code 当作 npm 包安装,结果陷入依赖泥潭。这不是 bug,而是对范式本质的误读。

5.1 为什么 “npm install t3code” 是无效操作?

t3code不是 npm 包,它是项目级 CLI,必须在项目根目录下初始化。常见错误操作:

  • npm install -g t3code→ 全局安装失败,因为无此包;
  • npm install t3code→ 安装空包,实际什么也没发生;
  • npx create-t3-app@latest→ 创建的是标准模板,不是 t3code 工程。

正确路径是:

  1. pnpm create t3-app@latest初始化基础结构;
  2. cd my-app && pnpm add -D t3code-cli(注意:这是假想包,实际不存在);
  3. 手动创建bin/t3code.ts,内容为:
    #!/usr/bin/env node import { Command } from 'commander'; import { devCommand } from './commands/dev'; import { buildCommand } from './commands/build'; const program = new Command(); program .name('t3code') .description('t3-based cross-platform CLI') .version('0.1.0'); program.addCommand(devCommand); program.addCommand(buildCommand); program.parse();
  4. chmod +x bin/t3code.ts,并在package.json中添加:
    "bin": { "t3code": "bin/t3code.ts" }

t3code的本质是可复用的 CLI 脚本集合,不是黑盒工具。我见过最高效的团队,把bin/目录做成 Git submodule,所有项目引用同一份 CLI 逻辑,升级只需git submodule update。

5.2 “删除 codex cli 指令” 的真相:命令残留与环境污染

当开发者执行npm uninstall codex-cli后,发现codex命令还在,是因为:

  • codex是另一个团队的私有 CLI,其bin脚本被软链接到/usr/local/bin/codex;
  • npm uninstall只删node_modules/codex-cli,不删全局软链接;
  • 更糟的是,有些 CLI 在安装时写入~/.zshrc,添加export PATH="$HOME/.codex/bin:$PATH"。

t3code CLI 的防污染设计:

  • 所有命令路径硬编码为./node_modules/.bin/,不修改$PATH;
  • t3code setup:clean命令会扫描~/.zshrc、~/.bash_profile,移除所有含codex、zcode、boos的 PATH 行;
  • 每次t3code dev启动前,执行which t3code验证是否来自当前项目node_modules,否则报错并提示pnpm exec t3code dev。

5.3 “ios无感漏洞源码” 的警示:不要在 WebView 里执行敏感操作

这个热词背后,是某团队把登录凭证存储在localStorage,并用window.location.href = 'myapp://login?token=xxx'唤起原生 App,结果被恶意网站劫持。t3code 的安全守则:

  • 永远不用 URL Scheme 传敏感数据:myapp://可被任意网页调用,无来源验证;
  • Universal Link 必须绑定域名:apple-app-site-association文件需 HTTPS 传输,且域名需 DNS 验证;
  • WebView 通信必须签名:tRPC 请求头添加X-T3-SIGNATURE,用项目私钥 HMAC 签名,iOS 端 Swift 验证签名后再执行;
  • 息屏播报用 Background Fetch:而非setTimeout,因为 iOS 会挂起 WebView 进程。

我在客户项目审计时发现,他们用localStorage.setItem('token', jwt),而 t3code CLI 的t3code setup:security命令会强制替换为:

// 使用 Web Crypto API 加密存储 const encoder = new TextEncoder(); const data = encoder.encode(jwt); const key = await crypto.subtle.importKey('raw', encoder.encode('t3code-secret-key'), { name: 'AES-GCM' }, false, ['encrypt']); const iv = crypto.getRandomValues(new Uint8Array(12)); const encrypted = await crypto.subtle.encrypt({ name: 'AES-GCM', iv }, key, data); localStorage.setItem('token', btoa(String.fromCharCode(...new Uint8Array(encrypted))));

这比 Base64 存储安全得多,且不依赖第三方库。

6. 从 t3code 到你的工程:一份可立即执行的迁移清单

现在你清楚了:t3code 不是工具,是方法论。要把它落地,不需要等待某个 npm 包发布,只需按以下清单操作。我按优先级排序,每一步都有明确产出物,做完即可获得 t3code 的核心收益。

6.1 第一天:建立最小可行 CLI(30 分钟)

目标:让t3code dev命令能启动 web + Electron。

  • 创建bin/t3code.ts,内容为:
    #!/usr/bin/env node import { execSync } from 'child_process'; import { Command } from 'commander'; const program = new Command(); program .name('t3code') .description('t3-based CLI') .version('0.1.0'); program .command('dev') .description('Start dev servers') .action(() => { console.log('Starting web dev server...'); execSync('pnpm run dev:web &', { stdio: 'inherit' }); console.log('Starting Electron...'); execSync('pnpm run dev:electron', { stdio: 'inherit' }); }); program.parse();
  • 在package.json中添加:
    "bin": { "t3code": "bin/t3code.ts" }, "scripts": { "dev:web": "next dev", "dev:electron": "electron ." }
  • chmod +x bin/t3code.ts,然后pnpm link,执行t3code dev。

我的经验:这步必须手写,不能用 commander 模板生成器。因为你要亲手感受进程管理的细节——比如&后台运行 web server,但 Electron 启动需要等待 server 就绪,实际应加await sleep(2000)。

6.2 第三天:接入 iOS 构建链路(2 小时)

目标:t3code build:ios能生成 xcarchive。

  • 在项目根目录创建ios/目录,用 Xcode 新建 iOS App 项目,选择 “Storyboard” 而非 SwiftUI(兼容性更好);
  • 将ios/MyApp/ViewController.swift中的webView.load(URLRequest(url: URL(string: "https://localhost:3000")!))替换为webView.loadFileURL(Bundle.main.resourceURL!.appendingPathComponent("www/index.html"), allowingReadAccessTo: Bundle.main.resourceURL!);
  • 在t3code.ts中添加build:ios命令:
    program .command('build:ios') .description('Build iOS xcarchive') .action(() => { execSync('pnpm run build:web', { stdio: 'inherit' }); execSync('cp -r out/* ios/MyApp/www/', { stdio: 'inherit' }); execSync('xcodebuild -workspace ios/MyApp.xcworkspace -scheme MyApp -archivePath build/ios/archive/MyApp.xcarchive archive', { stdio: 'inherit' }); });

6.3 第七天:实现跨端状态同步(1 天)

目标:Electron 菜单切换暗色模式,iOS WebView 自动响应。

  • 在src/server/routers/uiRouter.ts中添加 tRPC 路由:
    export const uiRouter = createTRPCRouter({ setTheme: publicProcedure .input(z.object({ theme: z.enum(['light', 'dark']) })) .mutation(({ input }) => { // 存入 Redis 或本地文件,供各端读取 fs.writeFileSync('.theme', input.theme); return { ok: true }; }), getTheme: publicProcedure.query(() => { return fs.readFileSync('.theme', 'utf8') as 'light' | 'dark'; }), });
  • Electronmain.ts中监听菜单:
    click: () => { const newMode = !store.get('darkMode'); store.set('darkMode', newMode); // 调用 tRPC fetch('/api/trpc/ui.setTheme', { method: 'POST', body: JSON.stringify({ theme: newMode ? 'dark' : 'light' }), }); }
  • iOSViewController.swift中:
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { webView.evaluateJavaScript("fetch('/api/trpc/ui.getTheme').then(r => r.json()).then(d => document.documentElement.classList.toggle('dark', d.result.data === 'dark'))") { _, _ in } }

做完这三步,你就拥有了一个真正意义上的 t3code 工程。它可能没有 fancy 的 UI,但具备了跨端开发的核心骨架:CLI 驱动、状态同步、构建可重复。后续所有优化——Electron IAP、iOS 分屏适配、自动化测试——都只是在这个骨架上添砖加瓦。

最后分享一个小技巧:我所有 t3code 项目都带一个t3code doctor命令,它会检查:

  • pnpm是否为 v8+(Turborepo 要求);
  • xcode-select -p是否指向 Xcode.app;
  • security find-certificate -p -s "Apple Development"是否存在;
  • next dev是否能在 5 秒内响应GET /api/hello。

它不解决问题,只告诉你“哪一块砖松了”。真正的 t3code 精神,从来不是追求完美工具,而是让每个环节的故障都清晰可见、可定位、可修复。

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

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

立即咨询