如何在Express服务端渲染.jsx组件?应选React路由还是保留EJS?
核心结论
你预期的直接在Express路由中使用res.send(<Example />)的写法无法直接实现:Node.js原生不识别JSX语法,且React组件需要先编译为标准JS代码,搭配客户端运行时、静态资源才能在浏览器中正常渲染。
可选方案
方案1:服务端渲染(SSR)适配Express路由
如果你希望继续沿用Express后端管控路由的逻辑,可以通过轻量SSR配置实现类似EJS的模板渲染效果,步骤如下:
- 配置Babel+Vite/Webpack,完成两项编译工作:将JSX组件编译为Node.js可执行的代码,同时打包出客户端侧需要的JS运行时bundle
- 引入
react-dom/server提供的渲染方法,将React组件转换为HTML字符串 - 把生成的HTML字符串插入基础HTML模板,同时引入客户端bundle的引用,最终通过
res.send返回完整HTML
示例代码:
// 服务端路由代码 import { renderToPipeableStream } from 'react-dom/server'; import Example from './example.jsx'; app.get('/', (req, res) => { const { pipe } = renderToPipeableStream(<Example />, { onShellReady() { res.setHeader('Content-Type', 'text/html'); res.write(` <!DOCTYPE html> <html> <head><title>首页</title></head> <body><div id="root"> `); pipe(res); res.write(` </div> <script src="/static/client-bundle.js"></script> </body></html> `); } }); });
// 客户端入口代码(需要打包为client-bundle.js) import { hydrateRoot } from 'react-dom/client'; import Example from './example.jsx'; hydrateRoot(document.getElementById('root'), <Example />);
该方案需要额外处理静态资源托管、组件数据预取等逻辑,学习成本较高。
方案2:前后端分离+React客户端路由
这是目前React生态最通用的方案,实现成本更低:
- React项目独立开发,所有页面路由通过
react-router-dom实现,编译后生成纯静态的HTML、JS、CSS文件 - Express端仅负责开发对接Mongoose的数据接口,同时托管React编译后的静态资源,所有非接口请求统一返回React的入口index.html,交由客户端路由处理路径匹配
示例代码:
// Express侧代码 import express from 'express'; import path from 'path'; const app = express(); // 托管React编译后的静态资源 app.use(express.static(path.join(__dirname, 'react-build'))); // 数据接口写在静态资源规则之后 app.get('/api/list', async (req, res) => { const data = await YourMongooseModel.find({}); res.json(data); }); // 所有非接口请求返回React入口文件 app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'react-build', 'index.html')); });
方案3:保留EJS,局部引入React
如果项目改动成本有限,不需要全量迁移到React,可以继续使用EJS作为页面模板,仅在交互复杂的模块单独引入React脚本,改动量最小。
选型建议
- 如果项目对SEO要求高、以内容展示为主,建议要么继续使用EJS,要么投入成本配置SSR方案
- 如果项目交互逻辑复杂、SEO要求不高,优先选择前后端分离+React路由的方案,开发效率更高
内容的提问来源于stack exchange,提问作者fub32
相关产品推荐
相关产品推荐

