设置 tRPC 单体仓库
为 tRPC 项目配置单体仓库工作区,将后端、前端和共享类型分开。
设置 tRPC 单体仓库 是 CoddyKit 上的免费 tRPC End-to-End Type Safe APIs 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 tRPC End-to-End Type Safe APIs 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 tRPC End-to-End Type Safe APIs 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
What is a Monorepo?
Welcome to setting up a tRPC project in a monorepo! But what exactly is a monorepo?
- A monorepo is a single repository containing multiple distinct projects.
- Unlike a polyrepo (multiple repos for multiple projects), everything lives together.
- Think of it as a big folder holding many smaller, related projects.
It's a powerful way to manage complex applications.
Why Monorepos for tRPC?
Monorepos offer unique advantages when working with tRPC:
- Shared Types: Easily share TypeScript types between your frontend and backend.
- Atomic Commits: Changes to the API and its consuming client can be committed together.
- Simplified Refactoring: Rename a type in one place, and your editor updates everywhere.
- Consistent Tooling: Share configurations for linters, formatters, and build tools.
This approach makes end-to-end type safety even more robust.
Choosing a Monorepo Tool
To manage a monorepo effectively, you'll need a workspace manager. These tools help link your internal packages.
Popular options include:
- pnpm Workspaces: Efficient, uses symlinks for dependencies.
- Yarn Workspaces: A common choice, built into Yarn.
- Nx: A powerful build system and monorepo tool.
- Turborepo: Focuses on fast builds and caching.
For this lesson, we'll use pnpm Workspaces due to its simplicity and efficiency.
Initializing the Monorepo
First, create a new directory for your monorepo and initialize a `package.json`.
Then, create a `pnpm-workspace.yaml` file to define your workspace roots. This tells pnpm where to find your sub-projects.
mkdir trpc-monorepo
cd trpc-monorepo
pnpm init
# pnpm-workspace.yaml
packages:
- 'packages/*'Structuring the 'packages' Folder
The `packages` directory will contain all your individual projects (or 'apps'). We'll typically have:
- server: Your tRPC backend.
- client: Your frontend application (e.g., React, Next.js).
- shared: A package for common utilities, types, and Zod schemas shared by `server` and `client`.
Let's create these basic directories.
mkdir -p packages/server
mkdir -p packages/client
mkdir -p packages/sharedSetting up the 'server' Package
Inside `packages/server`, we'll set up a basic Node.js project. It needs its own `package.json` and `tsconfig.json`.
The `tsconfig.json` will specify compilation options for your backend code.
// packages/server/package.json
{
"name": "server",
"version": "1.0.0",
"main": "src/index.ts",
"scripts": {
"dev": "ts-node-dev src/index.ts"
},
"dependencies": {
"@trpc/server": "latest",
"cors": "latest",
"express": "latest"
},
"devDependencies": {
"typescript": "latest",
"ts-node-dev": "latest"
}
}
// packages/server/tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true,
"skipLibCheck": true,
"outDir": "dist"
}
}Setting up the 'client' Package
Similarly, `packages/client` will house your frontend application. This example shows a basic React setup, but it could be Next.js or any other framework.
It will also have its own `package.json` and `tsconfig.json`.
// packages/client/package.json
{
"name": "client",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "vite"
},
"dependencies": {
"@trpc/client": "latest",
"@trpc/react-query": "latest",
"react": "latest",
"react-dom": "latest",
"@tanstack/react-query": "latest"
},
"devDependencies": {
"typescript": "latest",
"vite": "latest",
"@vitejs/plugin-react": "latest"
}
}
// packages/client/tsconfig.json
{
"compilerOptions": {
"target": "ESNext",
"useDefineForClassFields": true,
"lib": ["DOM", "DOM.Iterable", "ESNext"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx"
},
"include": ["src"],
"references": [{ "path": "../shared" }]
}Creating the 'shared' Package
The `packages/shared` directory is crucial for tRPC monorepos. It will contain types and definitions that both your `server` and `client` need.
This ensures end-to-end type safety by having a single source of truth for your API contract.
// packages/shared/package.json
{
"name": "shared",
"version": "1.0.0",
"main": "src/index.ts",
"types": "src/index.ts"
}
// packages/shared/tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"module": "CommonJS",
"strict": true,
"declaration": true,
"outDir": "dist"
},
"include": ["src"]
}Linking Shared Types
Now that we have our `shared` package, we need to tell `server` and `client` about it.
We add `"shared": "workspace:*"` to the `dependencies` of both `server` and `client`'s `package.json` files.
Then, run `pnpm install` at the monorepo root to link them up.
// packages/server/package.json (snippet)
"dependencies": {
"@trpc/server": "latest",
"shared": "workspace:*" // Add this line!
}
// packages/client/package.json (snippet)
"dependencies": {
"@trpc/client": "latest",
"shared": "workspace:*" // Add this line!
}
pnpm installPractical Example: Sharing a Type
Let's see how sharing types works. We'll define a `User` type in `shared` and use it in a mock backend and frontend snippet.
This demonstrates the core benefit: defining types once and using them everywhere.
// packages/shared/src/index.ts
export type User = {
id: string;
name: string;
email: string;
};
// packages/server/src/index.ts (mock)
import { User } from 'shared';
const getUser = (): User => ({
id: '123',
name: 'Alice',
email: 'alice@example.com'
});
console.log(getUser().name);
// packages/client/src/App.tsx (mock)
import { User } from 'shared';
const displayUser = (user: User) => {
console.log(`User: ${user.name}`);
};
const currentUser: User = {
id: '456',
name: 'Bob',
email: 'bob@example.com'
};
displayUser(currentUser);Monorepo Setup Check
You've learned about setting up a tRPC monorepo. Which of the following is NOT a primary benefit of using a monorepo for a tRPC project?
Recap: tRPC Monorepo Setup
You've successfully explored how to set up a tRPC monorepo!
- We defined a monorepo as a single repository for multiple projects.
- Learned its benefits for tRPC, especially shared types.
- Used `pnpm Workspaces` to structure `server`, `client`, and `shared` packages.
- Understood how to link these packages to share code and types.
This foundation is key for building scalable and type-safe tRPC applications!
常见问题解答
「设置 tRPC 单体仓库」课时是免费的吗?
是的 — 「设置 tRPC 单体仓库」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 tRPC End-to-End Type Safe APIs 课程的其余内容,请升级到 CoddyKit PRO。 tRPC End-to-End Type Safe APIs 课程共包含 4 节课。
「设置 tRPC 单体仓库」这节课中我会学到什么?
为 tRPC 项目配置单体仓库工作区,将后端、前端和共享类型分开。 你通过在浏览器中直接运行的动手代码来练习 tRPC End-to-End Type Safe APIs,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 tRPC End-to-End Type Safe APIs 需要有经验吗?
无需任何先前经验。CoddyKit 上的 tRPC End-to-End Type Safe APIs 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「设置 tRPC 单体仓库」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 tRPC End-to-End Type Safe APIs 课中编写并运行代码吗?
能。每节 tRPC End-to-End Type Safe APIs 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 设置 tRPC 单体仓库
- 代码共享与复用
- 扩展 tRPC 功能
- 版本化与发布共享的 tRPC 包