Node.js运行index.mjs反复出现SyntaxError: Invalid or unexpected token错误求助
解决方案
问题根源
Node.js 本身无法解析 JSX 语法(比如 <div>、<ChatButton /> 这类标签),你的 index.mjs 文件同时包含了 Express/WebSocket 服务端代码和 React 客户端组件代码,导致 Node.js 执行时遇到无法识别的 JSX 令牌,触发语法错误。
分步解决
1. 拆分服务端与客户端代码
把 React 相关的代码从 index.mjs 中分离出来,单独放在客户端文件里:
修改后的 index.mjs(仅保留服务端逻辑):
import WebSocket, { WebSocketServer } from "ws"; import http from "http"; import express from 'express'; import { fileURLToPath } from 'url'; import { dirname, join } from 'path'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); const app = express(); const server = http.createServer(app); const wss = new WebSocketServer({ server }); // Keep track of connected clients const clients = new Set(); wss.on('connection', (ws) => { console.log('Client connected'); // Receive and store the username from the client ws.on('message', (message) => { const data = JSON.parse(message); if (data.type === 'username') { ws.username = data.username; // Notify all clients about the updated user list broadcastUserList(); } }); // Add the new client to the set clients.add(ws); // Notify all clients about the updated user list broadcastUserList(); ws.on('message', (message) => { // Parse the message const data = JSON.parse(message); // Check message type switch (data.type) { case 'chat': // Broadcast the chat message to all clients broadcastMessage({ type: 'chat', message: data.message }); break; case 'typing': // Broadcast typing status to all clients broadcastMessage({ type: 'typing', username: data.username, isTyping: data.isTyping }); break; default: break; } }); ws.on('close', () => { console.log('Client disconnected'); // Remove the client from the set clients.delete(ws); // Notify all clients about the updated user list broadcastUserList(); }); }); function broadcastMessage(message) { // Broadcast the message to all clients wss.clients.forEach((client) => { if (client.readyState === WebSocket.OPEN) { client.send(JSON.stringify(message)); } }); } function broadcastUserList() { // Create an array of usernames const userList = Array.from(clients).map((client) => { return { username: client.username, online: client.readyState === WebSocket.OPEN }; }); // Broadcast the updated user list to all clients broadcastMessage({ type: 'userList', userList }); } // Serve static files from Vite's dist folder app.use(express.static(join(__dirname, 'dist'))); // Serve the HTML file app.get('/', (req, res) => { res.sendFile(join(__dirname, 'dist', 'index.html')); }); // Fix port typo: listen on 3000 and log correct URL server.listen(3000, () => { console.log('Server listening on http://localhost:3000'); });
新建 client.jsx(客户端 React 代码):
import React from 'react'; import ReactDOM from 'react-dom/client'; import ChatButton from './ChatButton'; // 注意:这里要使用相对路径,确保 ChatButton 文件存在 const App = () => { return ( <div> {/* Your existing website content */} <h1>Welcome to Your Website</h1> {/* Include the ChatButton component */} <ChatButton /> {/* Other components or content */} </div> ); }; // Render the App component ReactDOM.createRoot(document.getElementById('root')).render(<App />);
2. 使用打包工具编译客户端 JSX
Node.js 不能直接运行 JSX,浏览器也无法直接识别它,所以需要用打包工具(比如 Vite)把 JSX 编译成浏览器能理解的普通 JavaScript:
- 初始化 Vite 项目:
npm create vite@latest . -- --template react
(按提示完成初始化,选择 React 模板)
把刚才创建的
client.jsx替换掉 Vite 生成的src/main.jsx文件,或者调整 Vite 配置指向你的client.jsx。安装依赖并构建客户端代码:
npm install npm run build
这会在项目根目录生成 dist 文件夹,里面是编译好的客户端资源。
3. 启动服务并测试
- 安装服务端依赖(如果还没装):
npm install express ws
- 启动服务:
node index.mjs
- 访问
http://localhost:3000,此时页面会加载编译后的 React 代码,服务端也能正常运行 WebSocket 逻辑。
额外注意事项
- 确保
ChatButton组件文件路径正确(比如./ChatButton.jsx),避免使用裸模块导入。 - 如果之前尝试过 Babel 配置,需要清理无效的配置项,避免冲突。
- 检查
index.html文件中是否包含挂载 React 的<div id="root"></div>元素,Vite 生成的index.html通常已经包含这个元素。
内容的提问来源于stack exchange,提问作者LBlueLockL
相关产品推荐
相关产品推荐

