search
Tutorials star Featured

Fix: Build succeeded but site shows blank page in React Angular Vue

Complete guide to fix blank page issues after successful builds in React, Angular, and Vue applications. Learn how to debug and resolve blank page errors with practical solutions.

person By Gautam Sharma
calendar_today January 8, 2026
schedule 15 min read
React Angular Vue Blank Page Build Production Error Frontend Deployment Debugging

The ‘build succeeded but site shows blank page’ error is a common issue developers face when their applications build successfully but display a blank white screen when accessed in the browser. This frustrating problem occurs across React, Angular, and Vue applications and typically stems from JavaScript errors, asset loading failures, or configuration issues that prevent the application from mounting properly.

This comprehensive guide explains what causes this issue, why it happens, and provides multiple solutions to fix it in your React, Angular, and Vue projects with clean code examples and directory structure.


What is the Blank Page Issue?

The “build succeeded but site shows blank page” issue occurs when:

  • The application builds successfully in the terminal
  • No build errors are reported
  • The site deploys but shows a completely blank white screen
  • JavaScript errors prevent the app from initializing
  • Assets fail to load after build
  • Routing configuration issues in production

Common Error Manifestations:

  • Completely blank white page after deployment
  • HTML loads but application doesn’t mount
  • Console errors preventing app initialization
  • Assets (CSS, JS) not loading after build
  • Routing issues in production environment

Understanding the Problem

Blank page issues typically occur due to:

  • JavaScript runtime errors in production
  • Asset path configuration problems
  • Missing or incorrect base href
  • Build optimization issues
  • Environment-specific code differences
  • Third-party library conflicts
  • Service worker problems

Solution 1: Check Browser Console for Errors

The first step is to identify the root cause by checking browser console errors.

❌ Without Error Checking:

// ❌ Don't ignore console errors
// Build succeeds but app shows blank page
// No visible errors in build output

✅ With Proper Error Checking:

Check Console:

# Open browser developer tools
# Check Console tab for JavaScript errors
# Look for Vue mounting errors
# Check Network tab for failed asset requests

Example Console Errors:

React: Uncaught TypeError: Cannot read property 'mount' of undefined
Angular: Uncaught Error: Bootstrap at least one component
Vue: Uncaught TypeError: Cannot read property 'createApp' of undefined

Solution 2: React - Fix Blank Page Issues

React App Mounting Issues

❌ Without Proper Mounting:

// src/index.js - ❌ Missing proper mounting
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

// ❌ App not mounted properly
// Missing ReactDOM.render or createRoot call

✅ With Proper Mounting:

For React 18+:
// src/main.jsx
import React from 'react';
import { createRoot } from 'react-dom/client';
import App from './App';

const container = document.getElementById('root');
const root = createRoot(container);

// ✅ Properly mount React app
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// ✅ Add error handling for production
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
For React 17 and below:
// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

// ✅ Mount to existing DOM element
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React Asset Path Issues

❌ With Asset Path Issues:

<!-- public/index.html - ❌ Wrong asset paths -->
<head>
  <!-- ❌ Relative paths may break in production -->
  <link rel="stylesheet" href="src/styles/main.css">
  <script src="src/main.js"></script>
</head>

✅ With Correct Asset Paths:

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="theme-color" content="#000000">
    <meta name="description" content="Web site created using create-react-app">
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
    <title>React App</title>
  </head>
  <body>
    <!-- ✅ Ensure app element exists -->
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

React Environment Configuration

package.json:

{
  "name": "my-react-app",
  "version": "1.0.0",
  "homepage": ".", // ✅ Use relative paths for GitHub Pages
  "private": true,
  "dependencies": {
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  }
}

Solution 3: Angular - Fix Blank Page Issues

Angular App Module Configuration

❌ Incorrect App Module:

// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  // ❌ Missing bootstrap configuration
})
export class AppModule { }

✅ Correct App Module:

// src/app/app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent] // ✅ Bootstrap the main component
})
export class AppModule { }

Angular Main.ts Configuration

❌ Without Proper Bootstrapping:

// src/main.ts - ❌ Missing error handling
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule);

✅ With Error Handling:

// src/main.ts
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => {
    // ✅ Handle bootstrap errors
    console.error('Bootstrap error:', err);
    
    // ✅ Show user-friendly error in production
    if (process.env.NODE_ENV === 'production') {
      document.body.innerHTML = '<div style="padding: 20px; text-align: center;">Application failed to load. Please try again later.</div>';
    }
  });

Angular Build Configuration

angular.json:

{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "configurations": {
            "production": {
              "optimization": true, // ✅ Enable optimization
              "outputHashing": "all", // ✅ Enable hashing
              "sourceMap": false, // ✅ Disable source maps
              "namedChunks": false, // ✅ Disable named chunks
              "extractLicenses": true, // ✅ Extract licenses
              "vendorChunk": false, // ✅ Disable vendor chunk
              "buildOptimizer": true, // ✅ Enable build optimizer
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.prod.ts"
                }
              ]
            }
          }
        }
      }
    }
  }
}

Solution 4: Vue - Fix Blank Page Issues

Vue App Mounting Issues

❌ Without Proper Mounting:

// src/main.js - ❌ Missing proper mounting
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// ❌ App not mounted to DOM element
// Missing app.mount('#app') call

✅ With Proper Mounting:

main.js:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import { router } from './router'

const app = createApp(App)

// ✅ Mount to existing DOM element
app.use(router)
app.mount('#app')

// ✅ Add error handling for production
app.config.errorHandler = (err, instance, info) => {
  console.error('Vue Error:', err)
  console.error('Component:', instance)
  console.error('Info:', info)
  
  // ✅ Send error to logging service in production
  if (process.env.NODE_ENV === 'production') {
    sendErrorToService(err, { component: instance, info })
  }
}

function sendErrorToService(error, context) {
  // ✅ Implementation for sending errors to external service
  console.log('Sending error to service:', error.message)
}
public/index.html:
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="/favicon.ico">
    <title>My Vue App</title>
  </head>
  <body>
    <!-- ✅ Ensure app element exists -->
    <div id="app"></div>
    <!-- built files will be auto injected -->
  </body>
</html>

Vue Router Configuration

router/index.js:

// router/index.js
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  { path: '/', component: () => import('../views/Home.vue') },
  { path: '/about', component: () => import('../views/About.vue') }
]

const router = createRouter({
  history: createWebHistory(
    process.env.NODE_ENV === 'production' ? '/my-app/' : '/' // ✅ Set base path
  ),
  routes
})

export default router

Solution 5: Common Asset Path Issues

Fix Public Path Configuration

For React (Webpack):

// webpack.config.js
module.exports = {
  // ... other config
  output: {
    publicPath: process.env.NODE_ENV === 'production' ? '/my-app/' : '/' // ✅ Set public path
  }
};

For Vue (Vite):

// vite.config.js
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  base: process.env.NODE_ENV === 'production' ? '/my-app/' : '/', // ✅ Configure base path
  build: {
    outDir: 'dist',
    assetsDir: 'assets'
  }
})

For Angular (angular.json):

{
  "projects": {
    "my-app": {
      "architect": {
        "build": {
          "options": {
            "baseHref": "/" // ✅ Set base href for routing
          }
        }
      }
    }
  }
}

Solution 6: Environment-Specific Code Handling

React Environment Handling:

// src/config/api.js
const API_BASE_URL = process.env.NODE_ENV === 'production' 
  ? 'https://api.myapp.com' 
  : 'http://localhost:3000';

export default API_BASE_URL;

Angular Environment Handling:

// src/environments/environment.prod.ts
export const environment = {
  production: true,
  apiUrl: 'https://api.myapp.com'
};

Vue Environment Handling:

// src/config/api.js
export const API_CONFIG = {
  baseURL: process.env.NODE_ENV === 'production' 
    ? 'https://api.myapp.com' 
    : 'http://localhost:3000'
};

Solution 7: Implement Error Boundaries and Fallbacks

React Error Boundary:

// src/components/ErrorBoundary.js
import React from 'react';

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null, errorInfo: null };
  }

  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  componentDidCatch(error, errorInfo) {
    this.setState({
      error: error,
      errorInfo: errorInfo
    });

    // ✅ Log error to service in production
    if (process.env.NODE_ENV === 'production') {
      console.error('Error caught by boundary:', error, errorInfo);
    }
  }

  render() {
    if (this.state.hasError) {
      return (
        <div className="error-boundary">
          <h2>Something went wrong.</h2>
          <details style={{ whiteSpace: 'pre-wrap' }}>
            {this.state.error && this.state.error.toString()}
            <br />
            {this.state.errorInfo.componentStack}
          </details>
          <button onClick={() => window.location.reload()}>
            Reload Page
          </button>
        </div>
      );
    }

    return this.props.children;
  }
}

export default ErrorBoundary;

Angular Global Error Handler:

// src/app/services/error-handler.service.ts
import { Injectable, ErrorHandler } from '@angular/core';
import { environment } from '../environments/environment';

@Injectable()
export class GlobalErrorHandler implements ErrorHandler {
  handleError(error: any): void {
    // Log error in development
    if (!environment.production) {
      console.error('Error:', error);
    }

    // Send error to logging service in production
    if (environment.production) {
      this.logError(error);
    }

    // Re-throw the error
    throw error;
  }

  private logError(error: any): void {
    console.error('Production Error:', error);
  }
}

Vue Error Boundary:

<!-- src/components/ErrorBoundary.vue -->
<template>
  <div v-if="hasError">
    <h2>Something went wrong.</h2>
    <button @click="handleReset">Try again</button>
  </div>
  <slot v-else />
</template>

<script>
import { ref } from 'vue'

export default {
  name: 'ErrorBoundary',
  setup() {
    const hasError = ref(false)

    const handleReset = () => {
      hasError.value = false
      window.location.reload()
    }

    const handleError = (err) => {
      hasError.value = true
      console.error('Error caught by boundary:', err)
    }

    return {
      hasError,
      handleReset
    }
  },
  errorCaptured(err) {
    this.handleError(err)
    return false
  }
}
</script>

Working Code Examples

Complete Production-Ready React Component:

// src/App.js
import React, { useState, useEffect } from 'react';
import ErrorBoundary from './components/ErrorBoundary';

function App() {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // Initialize app
    const initApp = async () => {
      try {
        // App initialization logic
        await initializeApp();
      } catch (err) {
        setError(err);
        console.error('App initialization error:', err);
      } finally {
        setLoading(false);
      }
    };

    initApp();
  }, []);

  if (loading) return <div className="loading">Loading...</div>;
  if (error) return <div className="error">Error: {error.message}</div>;

  return (
    <ErrorBoundary>
      <div className="app">
        <header className="app-header">
          <h1>My App</h1>
        </header>
        <main>
          {/* Your app content */}
        </main>
      </div>
    </ErrorBoundary>
  );
}

export default App;

Complete Production-Ready Angular Component:

// src/app/app.component.ts
import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-root',
  template: `
    <div class="app" *ngIf="!loading && !error">
      <header class="app-header">
        <h1>My App</h1>
      </header>
      <main>
        <!-- Your app content -->
      </main>
    </div>
    <div class="loading" *ngIf="loading">Loading...</div>
    <div class="error" *ngIf="error">Error: {{ error }}</div>
  `,
  styles: [`
    .app { padding: 20px; }
    .loading, .error { padding: 20px; text-align: center; }
    .error { color: red; }
  `]
})
export class AppComponent implements OnInit {
  loading = true;
  error: string | null = null;

  ngOnInit() {
    this.initApp();
  }

  async initApp() {
    try {
      // App initialization logic
      await this.initializeApp();
    } catch (err: any) {
      this.error = err.message;
    } finally {
      this.loading = false;
    }
  }

  async initializeApp() {
    // Your initialization logic here
  }
}

Complete Production-Ready Vue Component:

<template>
  <div v-if="loading" class="loading">
    Loading...
  </div>
  <div v-else-if="error" class="error">
    <h2>Error loading application</h2>
    <p>{{ error.message }}</p>
    <button @click="retryLoad">Retry</button>
  </div>
  <div v-else id="app">
    <header class="app-header">
      <h1>My App</h1>
    </header>
    <main>
      <!-- Your app content -->
    </main>
  </div>
</template>

<script>
import { ref, onMounted } from 'vue'

export default {
  name: 'App',
  setup() {
    const loading = ref(true)
    const error = ref(null)

    const initApp = async () => {
      try {
        // App initialization logic
        await initializeApp()
      } catch (err) {
        error.value = err
        console.error('App initialization error:', err)
      } finally {
        loading.value = false
      }
    }

    const initializeApp = async () => {
      // Your initialization logic here
    }

    const retryLoad = () => {
      error.value = null
      loading.value = true
      initApp()
    }

    onMounted(() => {
      initApp()
    })

    return {
      loading,
      error,
      retryLoad
    }
  }
}
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}

.loading, .error {
  padding: 20px;
  text-align: center;
}

.error {
  color: #e74c3c;
}

.error button {
  margin-top: 10px;
  padding: 8px 16px;
  background-color: #3498db;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
</style>

Best Practices for Production Builds

1. Always Test Production Builds Locally

# ✅ React
npm run build
npx serve -s build

# ✅ Angular
ng build --configuration=production
npx http-server dist/my-app

# ✅ Vue
npm run build
npx serve dist

2. Use Environment Variables

// ✅ Always use environment variables for configuration
const API_URL = process.env.REACT_APP_API_URL || process.env.VUE_APP_API_URL || 'https://api.example.com';

3. Implement Proper Error Handling

// ✅ Add global error handlers
window.addEventListener('error', (event) => {
  console.error('Global error:', event.error);
});

4. Optimize Bundle Size Safely

# ✅ Analyze bundle size
npm run build --analyze

Debugging Steps

Step 1: Check Console Errors

# Open browser dev tools
# Check Console tab for JavaScript errors
# Check Network tab for failed asset requests

Step 2: Verify Build Output

# Check if build files exist
ls -la dist/  # or build/
# Verify index.html exists and has correct content
cat dist/index.html

Step 3: Test Locally

# Serve production build locally
npx serve dist  # or npx serve build
# Or use Python: python -m http.server -d dist

Step 4: Check Asset Loading

# In browser dev tools Network tab
# Check if CSS and JS files are loading
# Look for 404 errors

Common Mistakes to Avoid

1. Hardcoded Development URLs

// ❌ Don't hardcode URLs
const API_URL = 'http://localhost:3000/api'

// ✅ Use environment variables
const API_URL = process.env.API_URL

2. Missing App Mounting

// ❌ Don't forget to mount the app
const app = createApp(App)
// Missing app.mount('#app')

3. Incorrect Base Href

// ❌ Wrong base href
history: createWebHistory('/wrong-path/')

4. Development-Only Code in Production

// ❌ Don't include development-only code
if (process.env.NODE_ENV === 'development') {
  // This might cause issues if referenced elsewhere
}

Performance Considerations

1. Optimize for Production

// ✅ Use production-optimized configurations
build: {
  minify: 'terser',
  sourcemap: false
}

2. Implement Code Splitting

// ✅ Use dynamic imports for code splitting
const routes = [
  {
    path: '/dashboard',
    component: () => import('./views/Dashboard.vue')
  }
]

Security Considerations

1. Sanitize Environment Variables

// ✅ Validate environment variables
const API_URL = process.env.API_URL
if (!API_URL || !API_URL.startsWith('https://')) {
  throw new Error('Invalid API URL')
}

2. Secure Sensitive Information

// ✅ Don't expose sensitive data in client-side code
// Use environment variables for configuration, not secrets

Testing Production Builds

1. Build and Serve Test

# Build for production
npm run build

# Serve locally to test
npx serve dist  # or build directory

2. Unit Test Error Handling

// Test error handling in your components
// Ensure error boundaries work correctly

Alternative Solutions

1. Use Different Build Modes

# Create staging build for testing
npm run build --mode staging

2. Implement Feature Flags

// Use feature flags for production vs development features
const FEATURES = {
  DEBUG_PANEL: process.env.DEBUG === 'true'
}

Migration Checklist

  • Verify app mounts to correct DOM element
  • Check browser console for errors
  • Test production build locally
  • Verify asset paths work correctly
  • Ensure environment variables are configured
  • Check routing configuration
  • Implement proper error handling
  • Update documentation for team members

Conclusion

The ‘build succeeded but site shows blank page’ issue is typically caused by JavaScript errors, asset loading problems, or configuration issues that prevent the application from mounting properly. By following the solutions provided in this guide—whether through proper error checking, correct app mounting, asset path configuration, or environment handling—you can ensure your React, Angular, and Vue applications work reliably in production environments.

The key is to always test production builds locally, implement proper error handling, use environment variables consistently, and follow best practices for production deployments. With proper configuration and testing, your applications will load correctly and provide an excellent user experience across all frameworks.

Remember to check browser console errors first, verify app mounting, test production builds locally, and implement robust error handling to create reliable and maintainable applications that work consistently across all environments.

Gautam Sharma

About Gautam Sharma

Full-stack developer and tech blogger sharing coding tutorials and best practices

Related Articles

Vue

Fix: Vue app shows blank page after build

Learn how to fix Vue applications that show blank pages after production build. This comprehensive guide covers common causes, debugging, and best practices.

January 2, 2026
Angular

Fix: Angular Production Mode Errors - Debug Production-Only Issues

Complete guide to fix Angular errors that occur only in production mode. Learn how to debug and resolve production-specific issues with practical solutions, optimization strategies, and best practices for Angular deployment.

January 8, 2026
Tutorials

Fix: HTTPS required but site loading HTTP - Mixed Content Error Guide

Complete guide to fix mixed content errors when HTTPS is required but site loads HTTP resources. Learn how to resolve HTTP to HTTPS issues with practical solutions for React, Angular, and Vue applications.

January 8, 2026