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

如何构建由Node.js(Express)处理URL路由的MERN Stack应用?

整合Express与React并由Node负责路由的实现方案

一、基础项目搭建

先初始化项目并安装依赖:

mkdir react-express-integrated && cd react-express-integrated
npm init -y
# 核心依赖
npm install express react react-dom
# 开发依赖
npm install --save-dev webpack webpack-cli webpack-dev-middleware webpack-hot-middleware babel-loader @babel/core @babel/preset-react html-webpack-plugin

推荐项目结构:

react-express-integrated/
├── src/
│   ├── client/
│   │   ├── components/
│   │   │   ├── Home.jsx
│   │   │   └── About.jsx
│   │   ├── App.jsx
│   │   ├── index.jsx
│   │   └── index.html
│   └── server/
│       └── server.js
├── webpack.config.js
└── package.json

二、Express路由核心配置

在src/server/server.js中,先定义API路由,再将所有非API请求导向React入口页面,实现Node统一路由:

const express = require('express');
const path = require('path');
const app = express();

// 1. 处理API路由(需放在静态文件和兜底路由之前)
app.get('/api/user', (req, res) => {
  res.json({ name: 'Marc', role: 'Developer' });
});

// 2. 生产环境:提供React打包后的静态文件
if (process.env.NODE_ENV === 'production') {
  app.use(express.static(path.join(__dirname, '../../dist')));
}

// 3. 开发环境:启用Webpack热重载
if (process.env.NODE_ENV !== 'production') {
  const webpack = require('webpack');
  const webpackConfig = require('../../webpack.config')({ production: false });
  const compiler = webpack(webpackConfig);

  app.use(require('webpack-dev-middleware')(compiler, {
    publicPath: webpackConfig.output.publicPath
  }));
  app.use(require('webpack-hot-middleware')(compiler));
}

// 4. 兜底路由:所有非API请求返回React入口页面
app.get('*', (req, res) => {
  // 开发环境从Webpack内存读取,生产环境从dist文件夹读取
  const htmlPath = process.env.NODE_ENV === 'production' 
    ? path.join(__dirname, '../../dist/index.html')
    : path.join(__dirname, '../../src/client/index.html');
  res.sendFile(htmlPath);
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Server running on http://localhost:${PORT}`);
});

三、React与Webpack配置

  1. React入口模板src/client/index.html:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>React + Express App</title>
</head>
<body>
  <div id="root"></div>
</body>
</html>
  1. React入口文件src/client/index.jsx:
import React from 'react';
import ReactDOM from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom';
import App from './App';

// 必须使用BrowserRouter,让Node处理路由映射
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);
  1. React路由示例src/client/App.jsx:
import { Routes, Route, Link } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';

function App() {
  return (
    <div style={{ padding: '20px' }}>
      <nav>
        <Link to="/" style={{ marginRight: '15px' }}>首页</Link>
        <Link to="/about">关于</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </div>
  );
}

export default App;
  1. Webpack配置文件webpack.config.js:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = (env) => {
  const isProduction = env.production;

  return {
    entry: isProduction
      ? './src/client/index.jsx'
      : ['webpack-hot-middleware/client?reload=true', './src/client/index.jsx'],
    output: {
      path: path.resolve(__dirname, 'dist'),
      filename: 'bundle.[contenthash].js',
      publicPath: '/',
      clean: true // 生产环境打包时清空dist文件夹
    },
    module: {
      rules: [
        {
          test: /\.(js|jsx)$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              presets: ['@babel/preset-react']
            }
          }
        }
      ]
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: './src/client/index.html',
        minify: isProduction // 生产环境压缩HTML
      }),
      ...(isProduction ? [] : [new webpack.HotModuleReplacementPlugin()])
    ],
    resolve: {
      extensions: ['.js', '.jsx']
    },
    mode: isProduction ? 'production' : 'development',
    devtool: isProduction ? 'source-map' : 'inline-source-map'
  };
};

四、运行脚本配置

在package.json中添加以下脚本:

"scripts": {
  "dev": "NODE_ENV=development node src/server/server.js",
  "build": "webpack --env production",
  "start": "NODE_ENV=production node src/server/server.js"
}
  • 开发环境:执行npm run dev,访问http://localhost:3000即可看到React页面,支持热重载
  • 生产环境:先执行npm run build打包React代码到dist文件夹,再执行npm start启动生产服务器

五、关键注意事项

  • 必须使用BrowserRouter而非HashRouter,否则React路由会绕过Node的路由处理
  • API路由必须放在兜底路由之前,否则API请求会被React页面拦截
  • 开发环境下Webpack-dev-middleware将打包文件存在内存中,不会写入磁盘,提升开发效率

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 14:40:19