React Static Router服务端渲染报错:Unexpected token '<'求助
问题:React SSR结合Express启动时出现SyntaxError: Unexpected token '<'
启动服务器时出现如下错误:
<StaticRouter location={req.url}> ^ SyntaxError: Unexpected token '<' at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:118:18) at callTranslator (node:internal/modules/esm/loader:273:14) at ModuleLoader.moduleProvider (node:internal/modules/esm/loader:278:30) at async link (node:internal/modules/esm/module_job:76:21)
相关代码:
index.js
import React from "react"; import ReactDOM from "react-dom/client"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; import "./index.css"; import "bootstrap/dist/css/bootstrap.min.css"; import reportWebVitals from "./reportWebVitals"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <BrowserRouter> <App /> </BrowserRouter> );
app.jsx
import "./App.css"; import { Routes, Route } from "react-router-dom"; import Navi from "./components/Nav"; import Homepage from "./components/home"; import SignIn from "./components/signin"; import SignUp from "./components/signup"; import ErrorPage from "./components/error"; function App() { return ( <html> <title>Meetings App</title> <body> <div id="app"> <Routes> <Route path="/" element={<Navi />}> <Route index element={<Homepage />}></Route> <Route path="/signup" element={<SignUp />}></Route> <Route path="/signin" element={<SignIn />}></Route> </Route> <Route path="*" element={<ErrorPage />}></Route> </Routes> </div> <script src="./index.js" /> </body> </html> ); } export default App;
server.jsx
import express from "express"; import ReactDOMServer from "react-dom/server"; import { StaticRouter } from "react-router-dom/server"; import App from "../src/App"; const http = require("http"); const app = express(); const server = http.createServer(app); app.get("/", (req, res) => { let html = ReactDOMServer.renderToString( <StaticRouter location={req.url}> <App /> </StaticRouter> ); res.send("<!DOCTYPE html>" + html); }); let PORT = process.env.PORT || 5000; server.listen(PORT, () => { console.log(`server running on port ${PORT}`); });
解决方案
1. 核心问题:Node.js无法直接解析JSX
Node.js默认只能处理纯JavaScript,你的server.jsx中直接使用了JSX语法(<StaticRouter>标签),Node尝试执行时无法识别<符号,导致语法错误。需要用Babel编译服务器端代码。
操作步骤:
- 安装Babel依赖:
npm install @babel/core @babel/node @babel/preset-env @babel/preset-react --save-dev - 在项目根目录创建
.babelrc文件:{ "presets": ["@babel/preset-env", "@babel/preset-react"] } - 修改
package.json中的启动命令,用babel-node运行服务器文件:"scripts": { "start:server": "babel-node path/to/server.jsx" }
2. 修复App组件的结构问题
你的App组件直接返回<html>和<body>标签,会导致SSR渲染后生成嵌套的html结构(服务器已输出<!DOCTYPE html>,App里又返回<html>)。正确做法是:
- App组件只包含应用内容部分,把html、body、title等放在服务器端的模板中。
修改后的app.jsx:
import "./App.css"; import { Routes, Route } from "react-router-dom"; import Navi from "./components/Nav"; import Homepage from "./components/home"; import SignIn from "./components/signin"; import SignUp from "./components/signup"; import ErrorPage from "./components/error"; function App() { return ( <div id="app"> <Routes> <Route path="/" element={<Navi />}> <Route index element={<Homepage />}></Route> <Route path="/signup" element={<SignUp />}></Route> <Route path="/signin" element={<SignIn />}></Route> </Route> <Route path="*" element={<ErrorPage />}></Route> </Routes> </div> ); } export default App;
3. 调整服务器端的HTML模板
服务器端需要完整的HTML结构,同时要引入客户端打包后的文件(浏览器无法直接解析未打包的index.js):
修改后的server.jsx:
import express from "express"; import ReactDOMServer from "react-dom/server"; import { StaticRouter } from "react-router-dom/server"; import App from "../src/App"; import path from "path"; const app = express(); // 静态资源托管,指向客户端打包后的目录 app.use(express.static(path.resolve(__dirname, "../build"))); app.get("*", (req, res) => { const appHtml = ReactDOMServer.renderToString( <StaticRouter location={req.url}> <App /> </StaticRouter> ); const fullHtml = ` <!DOCTYPE html> <html> <head> <title>Meetings App</title> <link rel="stylesheet" href="/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="/index.css"> </head> <body> <div id="root">${appHtml}</div> <script src="/static/js/main.[hash].js"></script> </body> </html> `; res.send(fullHtml); }); const PORT = process.env.PORT || 5000; app.listen(PORT, () => { console.log(`server running on port ${PORT}`); });
4. 客户端打包
确保先打包客户端代码:
npm run build
然后启动服务器:
npm run start:server
内容的提问来源于stack exchange,提问作者struggler
相关产品推荐
相关产品推荐

