使用 React 从零开始构建服务器端渲染 (SSR)。
由 Mux 赞助的 DEV 全球展示挑战赛:展示你的项目!
Woovi的一项核心功能是我们的支付链接。它让您可以轻松地在网络上的任何地方销售产品,无需网站或其他任何设备。只需发送链接即可收款。
为什么要使用服务器端渲染?
如何确保用户在网络上分享此链接时获得良好的体验?我希望显示与该费用相关的二维码,并且在网络上的任何位置发送该链接时,都能显示与该 HTML 页面相关的 OG 和元标签。
对于客户端渲染的页面,由于无法在访问页面之前存储这些引用,因此无法实现这一点。
这就是我们选择使用 SSR 而非 CSR 来显示支付链接的原因。我们希望确保无论在网络上的哪个位置,当您分享此链接时,都能显示:正确的支付链接标题、作为原始图像的二维码,以及其他动态元数据。
服务器启动
第一步是创建入口点,页面将从这里渲染。在本例中,我们将使用koa框架。
// index.ts
import Router from '@koa/router';
import Koa from 'koa';
import bodyparser from 'koa-bodyparser';
const router = new Router();
const app = new Koa();
router.get('/(.*)', async (ctx) => {
ctx.status = 200;
ctx.body = 'OK';
});
app.use(bodyparser());
app.use(router.routes());
app.use(router.allowedMethods());
export default app;
我们在这里所做的是:创建一个新的端点,用于捕获所有请求并返回一个200包含响应OK体的响应。如果用户访问 `<RequestMail>`/或 `<RequestMail> /foo/bar`,则会得到相同的响应。
现在,要运行服务器并打开一个端口以访问服务器,您可以运行以下代码:
// index.ts
import http from 'http';
const currentHandler = app.callback();
const server = http.createServer(app.callback());
server.listen(4000, (error) => {
console.log(error);
});
现在,我们可以运行所有这些服务器并访问该端口4000。如果您想进行测试,请使用tsup任何您想要的方式构建它,例如ts-node。
渲染用户界面
现在,我们需要一种方法来渲染我们的 React 组件,对吧?所以我们的想法是使用现有的解决方案react-dom/server并进行处理。让我们看看下面的代码:
// index.ts
import Koa from 'koa';
import Router from '@koa/router';
import http from 'http';
import { renderToPipeableStream } from 'react-dom/server';
import { App } from './App';
const router = new Router();
const app = new Koa();
router.get('/(.*)', async (ctx) => {
let didError = false;
try {
// Wraps into a promise to force Koa to wait for the render to finish
return new Promise((_resolve, reject) => {
const { pipe, abort } = renderToPipeableStream(
<App />,
{
bootstrapModules: ['./client.js'],
onShellReady() {
ctx.respond = false;
ctx.status = didError ? 500 : 200;
ctx.set('Content-Type', 'text/html');
pipe(ctx.res);
ctx.res.end();
},
onShellError() {
ctx.status = 500;
abort();
didError = true;
ctx.set('Content-Type', 'text/html');
ctx.body = '<!doctype html><p>Loading...</p><script src="clientrender.js"></script>';
reject();
},
onError(error) {
didError = true;
console.error(error);
reject();
}
},
);
setTimeout(() => {
abort();
}, 10_000);
})
} catch (err) {
console.log(err);
ctx.status = 500;
ctx.body = 'Internal Server Error';
}
});
app.use(router.routes());
app.use(router.allowedMethods());
const server = http.createServer(app.callback());
server.listen(3000, () => {
console.log('Server listening on port 3000');
});
我们在这里所做的是:使用该onShellReady函数将数据块插入到可写流中,并完成响应。它将解析 Suspense 组件并将其显示给最终用户。
我们需要将此流程包装在一个中,Promise以确保 Koa 将等待到 promise 解析完成,这意味着可写流也已解析完成,从而返回正确的 HTML 代码。
组件App就是你的根项目,在这个例子中,我只是像你在这里Hello, world!看到的那样写了一段代码。但你可以插入任何你想要的内容。
您可以在这里看到代码。
综上所述
通过这种简单的设置,您可以拥有一个强大的工具,为我们的最终用户提供更好的体验,包括更好的 SEO、更快的加载速度以及 SSR 在某些特定情况下为我们带来的其他有用功能。
但一个合理的问题是:为什么不使用像Handlebars这样的模板呢?对于 Woovi 内部的使用场景来说,模板帮不了我们,因为我们需要做到两点:复用我们的设计系统,并确保在支付链接中使用 GraphQL。
在 Woovi 内部,我们所有的代码库都使用Relay 客户端框架,并通过 GraphQL 进行管理。为了确保最终用户获得最佳用户体验,我们在支付链接中提供了一些实用功能,例如支付完成后实时更新。所有这些都由 GraphQL 处理,在我们的用例中,模板无法解决这些问题。
本文概述了我们内部如何处理服务器端渲染(SSR)相关事宜。要使代码达到生产就绪状态,还需要逐步完成一些工作。
关于我们
Woovi 是一家初创公司,致力于让消费者能够自由选择支付方式。为了实现这一点,Woovi为商家提供即时支付解决方案,方便他们接收订单。
如果你想迎接像从零开始使用服务器端渲染 + GraphQL 创建强大解决方案这样的挑战,那就加入我们吧!
我们正在 招聘!
文章来源:https://dev.to/woovi/server-side-rendering-ssr-from-scratch-with-react-19jm
