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

React SSR场景下Node.js无需转译使用ES6模块的方法

如何在无需运行时转译的情况下实现React SSR(使用ES6模块)

核心思路是利用Node.js原生对ES模块的支持,配合TypeScript/Flow在构建阶段处理类型标注和JSX转换(这不属于运行时转译),让最终产出的代码能直接被Node.js执行。

步骤1:开启Node.js的ES模块支持

Node.js从v14.13.0开始原生支持ES模块,只需在项目根目录的package.json中添加一行配置:

{
  "type": "module"
}

之后所有.js文件都会被Node.js当作ES模块处理,直接识别import/export语法,完全不需要babel-node这类运行时转译工具。

步骤2:用TypeScript/Flow处理类型与JSX(构建时完成)

你的需求是仅去除类型标注,保留ES模块语法,所以需要通过TS/Flow的构建工具把带类型的JSX/TSX代码转换成纯ES模块的JavaScript(同时把JSX转成Node.js能识别的React.createElement调用)。

如果用TypeScript:

  1. 配置tsconfig.json关键项:
{
  "compilerOptions": {
    "module": "ESNext",        // 输出ES模块格式
    "target": "ES2020",        // 匹配Node.js支持的ES版本(可根据你使用的Node版本调整)
    "jsx": "react",            // 把JSX转成React.createElement调用
    "outDir": "./dist",        // 编译后的代码输出目录
    "strict": true,            // 可选,开启严格类型检查
    "moduleResolution": "node" // 按照Node.js的模块解析规则处理路径
  },
  "include": ["src/**/*"]
}
  1. 运行编译命令:
tsc

编译完成后,src目录下的组件会被转换成dist目录里的纯ES模块JS文件,已经去掉了类型标注,JSX也转成了可直接执行的代码。

如果用Flow:

  1. 安装必要工具:
npm install --save-dev flow-bin flow-remove-types @babel/core @babel/plugin-transform-react-jsx
  1. 创建.babelrc配置JSX转换:
{
  "plugins": ["@babel/plugin-transform-react-jsx"]
}
  1. 添加编译脚本到package.json:
{
  "scripts": {
    "build": "flow remove-types src/ --out-dir dist/ && babel dist/ --out-dir dist/"
  }
}

这个脚本会先去掉Flow类型标注,再把JSX转成React.createElement调用,最终输出到dist目录的是纯ES模块代码。

步骤3:编写服务端SSR代码(纯ES模块)

服务端代码本身也用ES模块编写,直接导入编译后的React组件进行渲染:

import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
// 导入编译后的ES模块组件(注意要加完整的.js扩展名)
import App from './dist/App.js';

const app = express();

// 静态文件托管(用于客户端hydration的脚本)
app.use(express.static('client/dist'));

app.get('/', (req, res) => {
  // 服务端渲染React组件为HTML字符串
  const appHtml = renderToString(<App />);
  
  // 返回完整的HTML页面,包含SSR内容和客户端激活脚本
  res.send(`
    <!DOCTYPE html>
    <html lang="zh-CN">
      <head>
        <meta charset="UTF-8">
        <title>React SSR Demo</title>
      </head>
      <body>
        <div id="root">${appHtml}</div>
        <!-- 客户端脚本也要是ES模块格式 -->
        <script type="module" src="/App.js"></script>
      </body>
    </html>
  `);
});

app.listen(3000, () => {
  console.log('Server is running at http://localhost:3000');
});

步骤4:处理客户端hydration代码

客户端代码同样需要编译成ES模块格式(和服务端用相同的TS/Flow配置),用于把SSR输出的HTML激活成可交互的React应用:

// client/src/App.jsx
import React from 'react';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

const root = document.getElementById('root');
hydrateRoot(root, <App />);

编译后放到client/dist目录,通过服务端的静态文件托管访问即可。

关键注意事项

  • 文件扩展名:在ES模块中,导入文件必须加上完整的扩展名(比如.js),Node.js不会自动补全。TS/Flow的编译工具会帮你处理这一点,但手动编写的导入要留意。
  • Node.js版本:确保使用v14.13.0或更高版本的Node.js,才能稳定支持ES模块特性。
  • CommonJS依赖兼容:大部分npm包目前还是CommonJS格式,Node.js的ES模块系统可以直接import这些包(比如import express from 'express'),无需额外处理。

这样整个流程下来,服务端运行的是已经构建好的纯ES模块代码,没有任何运行时转译,完全符合你的需求。

内容的提问来源于stack exchange,提问作者garyx

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 10:38:19