You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何扩展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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 14:38:13