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

React博客前端部署异常:Vercel白屏、Render栈溢出

全栈博客应用前端部署问题排查与解决

我开发了一个全栈博客应用,后端部署顺利,但前端遇到两个部署问题:

  • 在render.com部署时提示error: stack full
  • 在Vercel部署成功后,页面仅显示一秒就变为白屏
    本地运行完全正常,以下是相关文件内容:

Package.json

{
    "name": "frontend",
    "version": "0.1.0",
    "proxy": "https://blog-main-cw2a.onrender.com/",
    "private": true,
    "dependencies": {
        "@ckeditor/ckeditor5-build-classic": "^32.0.0",
        "@ckeditor/ckeditor5-react": "^4.0.0",
        "@testing-library/jest-dom": "^5.16.1",
        "@testing-library/react": "^12.1.2",
        "@testing-library/user-event": "^13.5.0",
        "axios": "^0.25.0",
        "react": "^17.0.2",
        "react-dom": "^17.0.2",
        "react-icons": "^4.3.1",
        "react-router-dom": "^6.2.1",
        "react-scripts": "5.0.0",
        "uuid": "^8.3.2",
        "web-vitals": "^2.1.4"
    },
    "scripts": {
        "start": "react-scripts start",
        "build": "react-scripts build",
        "test": "react-scripts test",
        "eject": "react-scripts eject"
    },
    "eslintConfig": {
        "extends": [
            "react-app",
            "react-app/jest"
        ]
    },
    "browserslist": {
        "production": [
            ">0.2%",
            "not dead",
            "not op_mini all"
        ],
        "development": [
            "last 1 chrome version",
            "last 1 firefox version",
            "last 1 safari version"
        ]
    }
}

App.js

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import { Outlet } from 'react-router-dom'
import PrivateRoute from './components/Routing/PrivateRoute';
import Home from "./components/GeneralScreens/Home"
import LoginScreen from "./components/AuthScreens/LoginScreen"
import RegisterScreen from "./components/AuthScreens/RegisterScreen"
import ForgotPasswordScreen from "./components/AuthScreens/ForgotPasswordScreen"
import ResetPasswordScreen from "./components/AuthScreens/ResetPasswordScreen"
import AddStory from './components/StoryScreens/AddStory';
import DetailStory from './components/StoryScreens/DetailStory';
import Header from './components/GeneralScreens/Header';
import Footer from './components/GeneralScreens/Footer';
import Profile from './components/ProfileScreens/Profile';
import EditProfile from './components/ProfileScreens/EditProfile';
import ChangePassword from './components/ProfileScreens/ChangePassword';
import NotFound from './components/GeneralScreens/NotFound';
import EditStory from './components/StoryScreens/EditStory';
import ReadListPage from './components/ProfileScreens/ReadListPage';

const App = () => {

      return (
            <Router>

                  <div className="App">

                        <Routes>
                              <Route path="/" element={<LayoutsWithHeader />}>

                                    <Route path='*' element={<NotFound />} />

                                    <Route exact path='/' element={<PrivateRoute />}>
                                          <Route exact path='/' element={<Home />} />
                                    </Route>

                                    <Route exact path="/story/:slug" element={<DetailStory />} />

                                    <Route exact path='/addstory' element={<PrivateRoute />}>
                                          <Route exact path='/addstory' element={<AddStory />} />
                                    </Route>

                                    <Route exact path='/profile' element={<PrivateRoute />}>
                                          <Route exact path='/profile' element={<Profile />} />
                                    </Route>

                                    <Route exact path='/edit_profile' element={<PrivateRoute />}>
                                          <Route exact path='/edit_profile' element={<EditProfile />} />
                                    </Route>

                                    <Route exact path='/change_Password' element={<PrivateRoute />}>
                                          <Route exact path='/change_Password' element={<ChangePassword />} />
                                    </Route>

                                    <Route exact path='/story/:slug/like' element={<PrivateRoute />}>
                                          <Route exact path='/story/:slug/like' element={<DetailStory />} />
                                    </Route>

                                    <Route exact path='/story/:slug/edit' element={<PrivateRoute />}>
                                          <Route exact path='/story/:slug/edit' element={<EditStory />} />
                                    </Route>

                                    <Route exact path='/story/:slug/delete' element={<PrivateRoute />}>
                                          <Route exact path='/story/:slug/delete' element={<DetailStory />} />
                                    </Route>
                                    <Route exact path='/story/:slug/addComment' element={<PrivateRoute />}>
                                          <Route exact path='/story/:slug/addComment' element={<DetailStory />} />
                                    </Route>

                                    <Route exact path='/readList' element={<PrivateRoute />}>
                                          <Route exact path='/readList' element={<ReadListPage />} />
                                    </Route>

                              </Route>

                              <Route exact path="/login" element={<LoginScreen />} />
                              <Route exact path="/register" element={<RegisterScreen />} />

                              <Route exact path="/forgotpassword" element={<ForgotPasswordScreen />} />

                              <Route exact path="/resetpassword" element={<ResetPasswordScreen />} />


                        </Routes>

                  </div>

            </Router>

      );

}

const LayoutsWithHeader = () => {
      return (
            <>
                  <Header />
                  <Outlet />
                  <Footer />
            </>
      );
}

export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import AuthContextProvider from './Context/AuthContext'

ReactDOM.render(
  <React.StrictMode>
    <AuthContextProvider>
       <App />
    </AuthContextProvider>
  </React.StrictMode>,
  document.getElementById('root')
);

文件结构

标准Create React App项目结构,包含components、Context等核心目录,各功能模块按分类存放。


问题排查与修复方案

1. Vercel部署后白屏问题

白屏核心原因是路由配置不符合React Router v6规范,以及生产环境代理失效:

  • 修复路由配置:当前嵌套私有路由的写法会导致渲染逻辑混乱,React Router v6中私有路由应通过父路由嵌套Outlet实现,而非嵌套Route。重构PrivateRoute:
    // components/Routing/PrivateRoute.js
    import { Navigate, Outlet } from 'react-router-dom';
    import { useAuth } from '../../Context/AuthContext';
    
    const PrivateRoute = () => {
      const { isAuthenticated } = useAuth();
      return isAuthenticated ? <Outlet /> : <Navigate to="/login" />;
    };
    
    export default PrivateRoute;
    
    同时修改App.js中的路由结构:
    <Route path="/" element={<LayoutsWithHeader />}>
      <Route path='*' element={<NotFound />} />
      {/* 统一嵌套私有路由 */}
      <Route element={<PrivateRoute />}>
        <Route exact path='/' element={<Home />} />
        <Route exact path='/addstory' element={<AddStory />} />
        <Route exact path='/profile' element={<Profile />} />
        <Route exact path='/edit_profile' element={<EditProfile />} />
        <Route exact path='/change_Password' element={<ChangePassword />} />
        <Route exact path='/story/:slug/like' element={<DetailStory />} />
        <Route exact path='/story/:slug/edit' element={<EditStory />} />
        <Route exact path='/story/:slug/delete' element={<DetailStory />} />
        <Route exact path='/story/:slug/addComment' element={<DetailStory />} />
        <Route exact path='/readList' element={<ReadListPage />} />
      </Route>
      {/* 公开路由 */}
      <Route exact path="/story/:slug" element={<DetailStory />} />
    </Route>
    
  • 生产环境API配置:package.json的proxy仅在开发环境生效,在Vercel后台添加环境变量REACT_APP_API_URL=https://blog-main-cw2a.onrender.com/,并修改axios请求的baseURL为该变量。

2. render.com部署的error: stack full问题

该错误是栈溢出导致,核心原因是路由错误嵌套引发的无限递归:

  • 按照上述React Router v6的正确写法重构路由,消除错误嵌套逻辑。
  • 检查AuthContext中的状态更新逻辑,避免在useEffect中无限制触发状态更新导致无限重渲染。
  • 本地执行npm run build后,用serve -s build启动生产环境测试,提前复现并排查栈溢出问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 16:27:51