search
Vue star Featured

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.

person By Gautam Sharma
calendar_today January 2, 2026
schedule 12 min read
Vue Blank Page Build Production Error Frontend Deployment

The ‘Vue app shows blank page after build’ is a common production deployment issue that occurs when Vue applications build successfully but display a blank page when accessed in the browser. This problem typically stems from JavaScript errors, asset loading failures, or configuration issues that prevent the Vue application from mounting properly.

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


What is the Blank Page Issue?

The “Vue app shows blank page after build” issue occurs when:

  • The application builds successfully but shows a blank white screen
  • Vue application fails to mount in the browser
  • JavaScript errors prevent the app from loading
  • Assets fail to load after build
  • Routing configuration issues in production

Common Error Manifestations:

  • Completely blank white page
  • HTML loads but Vue app 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
  • Asset path configuration problems
  • Missing or incorrect base href
  • Build optimization issues
  • Environment-specific code
  • Third-party library conflicts

Typical Vue Project Structure:

my-vue-app/
├── package.json
├── vite.config.js
├── src/
│   ├── main.js
│   ├── App.vue
│   ├── components/
│   │   └── HelloWorld.vue
│   ├── router/
│   │   └── index.js
│   ├── assets/
│   └── styles/
├── public/
├── dist/
└── index.html

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 Error:

Uncaught TypeError: Cannot read property 'mount' of undefined
    at main.js:10

Solution 2: Verify App Mounting in main.js

Ensure the Vue application is properly mounted.

❌ 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)
}

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>

Solution 3: Check Asset Loading Issues

Verify that all assets are loading correctly after build.

❌ 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 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>
    <!-- ✅ Assets will be injected automatically by build process -->
  </head>
  <body>
    <div id="app"></div>
    <!-- ✅ Built files will be auto-injected -->
  </body>
</html>

Solution 4: Configure Base Href for Routing

Set the correct base href for Vue Router in production.

❌ Without Base Href:

// router/index.js - ❌ Missing base configuration
import { createRouter, createWebHistory } from 'vue-router'

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

const router = createRouter({
  history: createWebHistory(), // ❌ No base path specified
  routes
})

export default router

✅ With Base Href:

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

const routes = [
  { path: '/', component: Home },
  { path: '/about', component: About }
]

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

export default router

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'
  }
})

Solution 5: Handle Environment-Specific Code

Ensure environment-specific code doesn’t break production builds.

❌ With Environment Issues:

// src/main.js - ❌ Development-specific code
import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// ❌ Hardcoded development URLs
const API_URL = 'http://localhost:3000/api'

// ❌ Development-only features
if (process.env.NODE_ENV === 'development') {
  // This might cause issues if referenced elsewhere
  app.config.devtools = true
}

app.mount('#app')

✅ With Environment Handling:

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

const app = createApp(App)

// ✅ Use environment variables
const API_URL = process.env.VUE_APP_API_URL || 'https://api.example.com'

// ✅ Safe environment-specific configuration
if (process.env.NODE_ENV === 'development') {
  app.config.performance = true
}

app.mount('#app')

Solution 6: Fix Build Optimization Issues

Address issues caused by build optimization and minification.

❌ With Optimization Issues:

// vite.config.js - ❌ Aggressive optimization causing issues
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()],
  build: {
    minify: 'terser',
    terserOptions: {
      compress: {
        drop_console: true,
        drop_debugger: true
      }
    }
  }
})

✅ With Safe Optimization:

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

export default defineConfig({
  plugins: [vue()],
  build: {
    outDir: 'dist',
    assetsDir: 'assets',
    minify: 'terser',
    terserOptions: {
      compress: {
        // ✅ Be careful with aggressive optimization
        drop_console: false, // ✅ Keep console for debugging
        drop_debugger: false
      }
    },
    rollupOptions: {
      output: {
        // ✅ Optimize chunking safely
        manualChunks: {
          vendor: ['vue', 'vue-router']
        }
      }
    }
  }
})

Solution 7: Implement Proper Error Boundaries

Add error boundaries to catch and handle errors gracefully.

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()
    }
    
    // ✅ Catch errors in child components
    const handleError = (err) => {
      hasError.value = true
      console.error('Error caught by boundary:', err)
    }
    
    return {
      hasError,
      handleReset
    }
  },
  errorCaptured(err) {
    this.handleError(err)
    return false
  }
}
</script>

src/main.js:

import { createApp } from 'vue'
import App from './App.vue'
import ErrorBoundary from './components/ErrorBoundary.vue'

const app = createApp(App)

// ✅ Wrap app in error boundary
app.component('ErrorBoundary', ErrorBoundary)
app.mount('#app')

Working Code Examples

Complete Production-Ready Configuration:

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

// ✅ Production-ready main.js with error handling
const app = createApp(App)

// ✅ Add global error handlers
app.config.errorHandler = (err, instance, info) => {
  console.error('Global 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 })
  }
}

// ✅ Handle unhandled promise rejections
window.addEventListener('unhandledrejection', (event) => {
  console.error('Unhandled promise rejection:', event.reason)
})

app.use(router)
app.mount('#app')

function sendErrorToService(error, context) {
  // ✅ Implementation for sending errors to external service
  console.log('Sending error to service:', error.message)
}

Production-Ready App Component:

<template>
  <div id="app">
    <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>
    <router-view v-else />
  </div>
</template>

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

export default {
  name: 'App',
  setup() {
    const loading = ref(true)
    const error = ref(null)
    const router = useRouter()
    
    const initApp = async () => {
      try {
        // ✅ Initialize app logic here
        await initializeApp()
      } catch (err) {
        error.value = err
        console.error('App initialization error:', err)
      } finally {
        loading.value = false
      }
    }
    
    const initializeApp = async () => {
      // ✅ App initialization logic
      // Load user data, settings, etc.
    }
    
    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

# ✅ Build and test locally before deployment
npm run build
npx serve dist

2. Use Environment Variables

// ✅ Always use environment variables for configuration
const API_URL = process.env.VUE_APP_API_URL

3. Implement Proper Error Handling

// ✅ Add global error handlers
app.config.errorHandler = (err, instance, info) => {
  console.error('Error:', err)
}

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 errors
# Check Network tab for failed requests

Step 2: Verify Build Output

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

Step 3: Test Locally

# Serve production build locally
npx serve dist
# 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.VUE_APP_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.VUE_APP_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

2. Unit Test Error Handling

import { mount } from '@vue/test-utils'
import App from '@/App.vue'

describe('App Error Handling', () => {
  it('should handle initialization errors', () => {
    // Mock error during initialization
    const wrapper = mount(App)
    expect(wrapper.exists()).toBe(true)
  })
})

3. E2E Test Production Build

// Using Cypress or similar tools
// Test the production build to ensure functionality

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.VUE_APP_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 ‘Vue app shows blank page after build’ issue is typically caused by JavaScript errors, asset loading problems, or configuration issues that prevent the Vue 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 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 Vue’s best practices for production deployments. With proper configuration and testing, your Vue applications will load correctly and provide an excellent user experience.

Remember to check browser console errors first, verify app mounting, test production builds locally, and implement robust error handling to create reliable and maintainable Vue 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 build works locally but fails in production Error

Learn how to fix Vue build issues that occur in production but work locally. This comprehensive guide covers environment differences, optimization, and deployment best practices.

January 1, 2026
Tutorials

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.

January 8, 2026
Angular

Fix: Angular app not working after build (production issue)

Learn how to fix Angular applications that don't work after production build. This comprehensive guide covers common production issues, optimization, and best practices.

January 2, 2026