Express.js文件中使用JSX语法报SyntaxError错误,寻求解决方法
解决服务端JSX转译「SyntaxError: Unexpected token '<'」问题
核心原因
Node.js默认无法解析JSX语法,即便安装了Babel,若配置缺失或启动方式错误,依然会导致转译失败。结合你用Vite搭建MERN项目的场景,需针对性调整Babel配置或使用Vite原生SSR方案。
具体解决步骤
1. 补全Babel依赖与配置
确保安装必要的Babel预设,并配置正确的转译规则:
- 安装依赖:
yarn add -D @babel/core @babel/preset-env @babel/preset-react @babel/node - 在项目根目录创建
.babelrc文件,添加以下配置:
这里指定{ "presets": [ ["@babel/preset-env", { "targets": { "node": "current" } }], "@babel/preset-react" ] }node: current是让Babel针对当前Node版本转译,避免不必要的兼容代码。
2. 用babel-node正确启动服务
不要直接用node server.js启动,改用babel-node处理转译:
- 在
package.json的scripts中添加启动命令:{ "scripts": { "dev": "babel-node server.js", "build": "babel server.js -d dist", "start:prod": "node dist/server.js" } } - 运行
yarn dev启动开发服务,生产环境需先执行yarn build转译代码,再用yarn start:prod运行。
3. 分离JSX代码到单独文件(推荐)
将包含JSX的渲染逻辑抽成单独的.jsx文件(比如serverRenderer.jsx),再在server.js中导入:
// serverRenderer.jsx import React from 'react' import ReactDOMServer from 'react-dom/server' import { ServerStyleSheets } from '@mui/styles' import { StaticRouter } from 'react-router-dom/server' import { ThemeProvider } from '@mui/material/styles' import MainRouter from './MainRouter' import theme from './theme' export default function renderServerMarkup(req) { const sheets = new ServerStyleSheets() const context = {} const markup = ReactDOMServer.renderToString( sheets.collect( <StaticRouter location={req.url} context={context}> <ThemeProvider theme={theme}> <MainRouter /> </ThemeProvider> </StaticRouter> ) ) return { markup, context } }
然后在server.js中导入使用:
// server.js import express from 'express' import renderServerMarkup from './serverRenderer.jsx' const app = express() app.get('*', (req, res) => { const { markup, context } = renderServerMarkup(req) if (context.url) { return res.redirect(301, context.url) } // 后续返回HTML模板逻辑 })
这样Babel能更准确识别JSX文件并完成转译。
4. 改用Vite原生SSR方案(适配你的项目架构)
既然用了Vite,可直接利用其SSR能力,无需依赖babel-node:
- 在
vite.config.js中开启SSR配置:import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], ssr: { target: 'node' } }) - 创建服务端入口文件(比如
server-entry.js),使用Vite的ssrLoadModule动态加载组件:import express from 'express' import { createServer as createViteServer } from 'vite' async function createServer() { const app = express() const vite = await createViteServer({ server: { middlewareMode: true }, appType: 'custom' }) app.use(vite.middlewares) app.get('*', async (req, res) => { // 加载服务端渲染逻辑 const { render } = await vite.ssrLoadModule('/src/serverRenderer.jsx') const { markup, context } = await render(req) if (context.url) { return res.redirect(301, context.url) } // 获取客户端资源链接 const template = await vite.transformIndexHtml(req.url, '<!DOCTYPE html><div id="root"></div>') const html = template.replace('<div id="root"></div>', `<div id="root">${markup}</div>`) res.send(html) }) app.listen(3000) } createServer()
这种方式更贴合Vite的生态,避免Babel与Vite的配置冲突。
内容的提问来源于stack exchange,提问作者Clinton Scheible
相关产品推荐
相关产品推荐

