如何扩展tRPC+Fastify配置,实现Pug SSR调用Prismic CMS数据
实现tRPC+Fastify的Pug服务端渲染
问题背景
我正在用tRPC和Fastify开发项目,已经通过API接口/api/home从Prismic CMS获取数据并正常返回。现在想通过Pug模板引擎实现服务端渲染,但不知道怎么扩展现有tRPC配置,让页面能调用已获取的数据。
解决方案步骤
1. 安装模板依赖
先安装Fastify视图插件和Pug引擎:
npm install @fastify/view pug
2. 扩展Fastify类,配置模板引擎
修改lib/fastify/index.ts,新增模板注册方法:
import type { Router } from '@trpc/server'; import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify'; import type { AnyRouterDef } from '@trpc/server/dist/core/router'; import fastify from 'fastify'; import metricsPlugin from 'fastify-metrics'; import * as trpcPlayground from 'trpc-playground/handlers/fastify'; // 新增视图插件引入 import fastifyView from '@fastify/view'; import pug from 'pug'; export interface ServerOptions { dev?: boolean; port?: number; prefix?: string; } export class Fastify { constructor( private readonly port: number, private readonly host: string, dev: boolean, public readonly server = fastify({ logger: dev }) ) {} // 原有方法保持不变... // 新增模板引擎注册方法 public readonly registerViews = async (viewsDir: string) => { await this.server.register(fastifyView, { engine: { pug: pug, }, root: viewsDir, // 可选:配置全局模板变量或布局 options: { globals: { siteName: 'My Site' } } }); }; }
3. 创建Pug模板文件
在项目根目录新建views文件夹,添加首页模板views/home.pug:
html head title= page.data.title body h1= page.data.title .page-content !{page.data.content.html}
4. 添加SSR路由,复用tRPC数据逻辑
新增routes/ssr/home.ts,直接在服务端调用数据查询逻辑(支持两种方式):
import type { FastifyInstance } from 'fastify'; // 方式1:直接复用Prismic客户端逻辑 import { client } from '../../lib/prismic/client'; // 方式2:通过tRPC服务端调用器复用接口逻辑 import type { AppRouter } from '../../index'; import { createCallerFactory } from '@trpc/server'; import { Trpc } from '../../lib/trpc'; import { Api } from '../../api'; // 初始化tRPC调用器(方式2用) const trpc = new Trpc(); const api = new Api(trpc); const createCaller = createCallerFactory(trpc.router)(api.handler); const caller = createCaller({}); export const registerHomeSSRRoute = async (fastify: FastifyInstance) => { fastify.get('/', async (req, reply) => { try { // 方式1:直接调用Prismic // const page = await client.getByUID('page', 'home'); // 方式2:复用tRPC接口逻辑(类型安全,推荐) const page = await caller.home(); if (!page) throw new Error('Home page not found'); // 渲染Pug模板并传入数据 return reply.view('/home.pug', { page }); } catch (error: any) { reply.status(500); return { error: 'Failed to render homepage: ' + error.message }; } }); };
5. 在Server中注册视图和SSR路由
修改server.ts的init方法,添加模板和路由注册:
private readonly init = async () => { if (this.fastifyServer) { return this.fastifyServer; } const fastifyServer = new Fastify( this.env.PORT, this.env.HOST, this.env.NODE_ENV === 'development' ); await fastifyServer.registerMetrics(); await fastifyServer.registerTrpc( this.env.TRPC_ENDPOINT, this.api.handler, this.env.TRPC_PLAYGROUND_ENDPOINT ); // 注册模板引擎 await fastifyServer.registerViews('./views'); // 注册SSR首页路由 const { registerHomeSSRRoute } = await import('./routes/ssr/home'); await registerHomeSSRRoute(fastifyServer.server); return fastifyServer; };
核心说明
- 服务端无需通过HTTP调用自身tRPC接口,直接用
createCaller创建服务端调用器,既能复用现有逻辑,又能保持类型安全。 - 通过
reply.view()方法即可将数据传入Pug模板,完成服务端渲染。
内容的提问来源于stack exchange,提问作者Taste of Leaving
相关产品推荐
相关产品推荐

