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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 17:52:29