No articles found
Try different keywords or browse our categories
How to Solve React Blank Page After Deploy & Build Error Tutorial
Learn how to fix React blank page errors after deployment. Complete guide with solutions for production builds and deployment optimization.
The React blank page after deploy error is a common issue developers face when their React application appears empty or blank after deployment. This problem occurs due to various factors including build configuration issues, asset loading problems, and environment-specific code.
This comprehensive guide provides complete solutions to resolve the blank page error with practical examples and deployment optimization techniques.
Understanding the Blank Page Error
React applications may appear blank after deployment due to several reasons:
- Asset loading failures (CSS, JS files not loading)
- JavaScript errors preventing app initialization
- Incorrect public path configuration
- Environment variable issues
- Build optimization problems
- CORS and security policy violations
Common Symptoms:
- White/blank screen after deployment
- Console errors related to assets or modules
- App container exists but no content renders
- JavaScript errors preventing initialization
Common Causes and Solutions
1. Asset Loading Issues
The most common cause is assets not loading properly in production.
❌ Problem Scenario:
// This works locally but fails after deploy due to incorrect paths
function BadAssetComponent() {
return (
<div>
{/* ❌ Relative paths may break after deploy */}
<img src="./assets/logo.png" alt="Logo" />
<link rel="stylesheet" href="./styles/main.css" />
</div>
);
}
✅ Solution: Use Public URL and Proper Paths
// Correct approach - use public URL for assets
function GoodAssetComponent() {
return (
<div>
{/* ✅ Use public URL for assets */}
<img src={`${process.env.PUBLIC_URL}/logo.png`} alt="Logo" />
{/* ✅ Or import directly */}
<img src={logoImage} alt="Logo" />
</div>
);
}
// Import images properly
import logoImage from './assets/logo.png';
// For CSS, ensure it's properly imported in index.js
// import './styles/main.css';
2. JavaScript Errors in Production
Errors that don’t appear in development can cause blank pages in production.
❌ Problem Scenario:
// This might work in development but fail in production
function BadComponent() {
const [data, setData] = useState(null);
useEffect(() => {
// ❌ This might fail in production due to API differences
fetch('/api/data')
.then(response => response.json())
.then(setData);
}, []);
// ❌ This will cause issues if data is null
return <div>{data.items.map(item => <p key={item.id}>{item.name}</p>)}</div>;
}
✅ Solution: Proper Error Handling
// Correct approach - handle errors and null states
function GoodComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
setLoading(true);
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
setData(result);
} catch (err) {
setError(err.message);
console.error('Fetch error:', err);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
if (!data) return <div>No data available</div>;
return (
<div>
{data.items && data.items.map(item => (
<p key={item.id}>{item.name}</p>
))}
</div>
);
}
Solution 1: Proper Build Configuration
Configure your build process correctly for deployment.
Package.json Configuration:
{
"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",
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
},
"devDependencies": {
"gh-pages": "^4.0.0"
}
}
Environment Configuration:
# .env.production
REACT_APP_API_URL=https://api.myapp.com
REACT_APP_ENV=production
GENERATE_SOURCEMAP=false
Public Folder Structure:
public/
├── index.html
├── favicon.ico
├── logo.png
├── manifest.json
└── robots.txt
Index.html Configuration:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<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" />
<!-- ✅ Use relative paths -->
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
Solution 2: Proper Asset Management
Handle assets correctly for production deployment.
// components/AssetManager.js
import React, { useState, useEffect } from 'react';
import logo from '../assets/logo.png'; // ✅ Import images directly
function AssetManager() {
const [imageLoaded, setImageLoaded] = useState(false);
const [imageError, setImageError] = useState(false);
const handleImageLoad = () => {
setImageLoaded(true);
};
const handleImageError = () => {
setImageError(true);
console.error('Failed to load image');
};
return (
<div>
{/* ✅ Handle image loading states */}
{!imageLoaded && !imageError && <div>Loading image...</div>}
{imageError && <div>Image failed to load</div>}
<img
src={logo}
alt="Logo"
onLoad={handleImageLoad}
onError={handleImageError}
style={{ display: imageLoaded ? 'block' : 'none' }}
/>
{/* ✅ Use public URL for dynamic assets */}
<img
src={`${process.env.PUBLIC_URL}/dynamic-image.jpg`}
alt="Dynamic"
/>
</div>
);
}
// For CSS assets, import in component or index.js
// import '../styles/Component.css';
Solution 3: Error Boundaries and Fallbacks
Implement error boundaries to catch and handle errors gracefully.
// 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);
// logErrorToService(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;
}
}
// App.js with error boundary
import React from 'react';
import ErrorBoundary from './components/ErrorBoundary';
import MainContent from './components/MainContent';
function App() {
return (
<ErrorBoundary>
<MainContent />
</ErrorBoundary>
);
}
export default App;
Solution 4: Proper API Configuration
Handle API calls correctly for different environments.
// utils/api.js
const API_BASE_URL = process.env.REACT_APP_API_URL || 'http://localhost:3001/api';
class ApiClient {
constructor() {
this.baseURL = API_BASE_URL;
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
headers: {
'Content-Type': 'application/json',
...options.headers,
},
...options,
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('API request failed:', error);
throw error;
}
}
get(endpoint) {
return this.request(endpoint, { method: 'GET' });
}
post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data),
});
}
}
export default new ApiClient();
// Component using API client
import React, { useState, useEffect } from 'react';
import api from '../utils/api';
function DataComponent() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const result = await api.get('/data');
setData(result);
} catch (err) {
setError(err.message);
} finally {
setLoading(false);
}
};
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>;
return <div>{data && <pre>{JSON.stringify(data, null, 2)}</pre>}</div>;
}
Solution 5: Build Optimization and Debugging
Optimize your build and implement proper debugging.
// utils/build-debug.js
export const debugBuild = () => {
if (process.env.NODE_ENV === 'production') {
// ✅ Disable console logs in production
console.log = () => {};
console.error = () => {};
console.warn = () => {};
} else {
// ✅ Enable detailed logging in development
console.log('Development mode - detailed logging enabled');
}
};
// utils/performance.js
export const measurePerformance = (name, fn) => {
if (process.env.NODE_ENV === 'development') {
const start = performance.now();
const result = fn();
const end = performance.now();
console.log(`${name} took ${end - start} milliseconds`);
return result;
}
return fn();
};
// App.js with build debugging
import React, { useEffect } from 'react';
import { debugBuild } from './utils/build-debug';
function App() {
useEffect(() => {
debugBuild();
}, []);
return <div>Your App Content</div>;
}
Solution 6: Deployment-Specific Configurations
Configure different settings for various deployment platforms.
For Netlify:
# netlify.toml
[build]
command = "npm run build"
publish = "build"
environment = { NODE_VERSION = "18" }
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
[context.production.environment]
REACT_APP_ENV = "production"
GENERATE_SOURCEMAP = "false"
For Vercel:
// vercel.json
{
"builds": [
{
"src": "package.json",
"use": "@vercel/static-build",
"config": {
"distDir": "build"
}
}
],
"routes": [
{
"src": "/(.*)",
"dest": "/index.html"
}
],
"env": {
"REACT_APP_API_URL": "https://api.myapp.com"
}
}
For GitHub Pages:
# .github/workflows/deploy.yml
name: Deploy to GitHub Pages
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: '18'
- run: npm ci
- run: |
npm run build
echo "myapp.com" > build/CNAME
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
cname: myapp.com
Solution 7: Testing Production Builds
Test your production build locally before deployment.
// scripts/test-deploy.js
const { spawn } = require('child_process');
const path = require('path');
function testProductionBuild() {
console.log('Building production version...');
const buildProcess = spawn('npm', ['run', 'build'], {
cwd: process.cwd(),
stdio: 'inherit'
});
buildProcess.on('close', (code) => {
if (code === 0) {
console.log('Build successful! Testing locally...');
// Serve the build locally
const serveProcess = spawn('npx', ['serve', '-s', 'build'], {
cwd: process.cwd(),
stdio: 'inherit'
});
serveProcess.on('error', (error) => {
console.error('Failed to serve build:', error.message);
});
console.log('Serving build at http://localhost:3000');
console.log('Press Ctrl+C to stop');
} else {
console.error('Build failed!');
process.exit(1);
}
});
}
// Run the test
testProductionBuild();
// Jest configuration for production testing
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
moduleNameMapper: {
'\\.(css|less|scss|sass)$': 'identity-obj-proxy',
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/__mocks__/fileMock.js',
},
testMatch: [
'**/__tests__/**/*.{js,jsx}',
'**/?(*.)+(spec|test).{js,jsx}',
],
};
Solution 8: Console Error Monitoring
Implement error monitoring for production environments.
// utils/error-monitoring.js
class ErrorMonitor {
constructor() {
this.environment = process.env.NODE_ENV;
this.appVersion = process.env.REACT_APP_VERSION || 'unknown';
}
logError(error, context = {}) {
const errorData = {
message: error.message,
stack: error.stack,
context,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href,
environment: this.environment,
version: this.appVersion,
};
if (this.environment === 'production') {
// ✅ Send to error tracking service
this.sendToErrorService(errorData);
} else {
// ✅ Log to console in development
console.error('Error logged:', errorData);
}
}
sendToErrorService(errorData) {
// Example: Send to a logging service
fetch('/api/errors', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(errorData),
}).catch(err => {
console.error('Failed to send error to service:', err);
});
}
}
export default new ErrorMonitor();
// Component using error monitoring
import React, { useEffect } from 'react';
import errorMonitor from '../utils/error-monitoring';
function MonitoredComponent() {
useEffect(() => {
const handleError = (error) => {
errorMonitor.logError(error, { component: 'MonitoredComponent' });
};
window.addEventListener('error', (event) => {
handleError(event.error);
});
return () => {
window.removeEventListener('error', handleError);
};
}, []);
return <div>Component with error monitoring</div>;
}
Solution 9: Performance and Bundle Analysis
Analyze your bundle to identify potential issues.
// webpack.config.js for analysis
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
// ... other config
plugins: [
// ... other plugins
...(process.env.ANALYZE_BUNDLE === 'true' ? [new BundleAnalyzerPlugin()] : []),
],
};
// package.json scripts for analysis
{
"scripts": {
"analyze": "ANALYZE_BUNDLE=true npm run build",
"analyze:prod": "ANALYZE_BUNDLE=true npm run build && npx serve -s build"
}
}
Performance Considerations
Optimized Production Build:
// Production-optimized patterns
function ProductionOptimizedComponent() {
const [state, setState] = useState({
data: [],
loading: false,
error: null
});
// ✅ Use functional updates to prevent race conditions
const updateState = useCallback((updater) => {
setState(prev => ({
...prev,
...updater(prev)
}));
}, []);
// ✅ Memoize expensive operations
const processedData = useMemo(() => {
return state.data.map(item => ({
...item,
processed: true
}));
}, [state.data]);
return (
<div>
{state.loading && <div className="loading">Loading...</div>}
{state.error && <div className="error">Error: {state.error}</div>}
<ul>
{processedData.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
}
Security Considerations
Secure Production Practices:
// Secure production practices
function SecureProductionComponent() {
const [userInput, setUserInput] = useState('');
const handleInputChange = (e) => {
// ✅ Sanitize user input before processing
const sanitizedInput = e.target.value
.replace(/[<>]/g, '') // Basic XSS prevention
.substring(0, 1000); // Limit input length
setUserInput(sanitizedInput);
};
// ✅ Secure API calls with proper headers
const secureApiCall = useCallback(async () => {
try {
const response = await fetch('/api/secure-endpoint', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify({ data: userInput }),
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
return result;
} catch (error) {
console.error('Secure API call failed:', error);
throw error;
}
}, [userInput]);
return (
<div>
<input
value={userInput}
onChange={handleInputChange}
placeholder="Enter secure input..."
/>
</div>
);
}
Common Mistakes to Avoid
1. Hardcoded Development URLs:
// ❌ Don't do this
function BadUrlComponent() {
useEffect(() => {
fetch('http://localhost:3001/api/data') // ❌ Hardcoded dev URL
.then(response => response.json())
.then(setData);
}, []);
}
2. Missing Error Handling:
// ❌ Don't do this
function BadErrorHandling() {
useEffect(() => {
// ❌ No error handling - will crash in production
fetch('/api/data').then(response => response.json()).then(setData);
}, []);
}
3. Incorrect Public Path:
// ❌ Don't do this
function BadAssetComponent() {
return (
<img src="/absolute/path/logo.png" alt="Logo" /> // ❌ May break on subdirectories
);
}
Alternative Solutions
Using React DevTools:
// Production-optimized component for DevTools
function ProductionOptimizedComponent() {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then(response => response.json())
.then(setData)
.catch(error => {
console.error('Production error:', error);
// Fallback to default data
setData({ error: true });
});
}, []);
return (
<div data-testid="production-component">
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
</div>
);
}
Feature Detection:
// Check for production features
function ProductionFeatureChecker() {
const [isProduction, setIsProduction] = useState(false);
useEffect(() => {
setIsProduction(process.env.NODE_ENV === 'production');
}, []);
return (
<div>
{isProduction ? 'Production Mode' : 'Development Mode'}
</div>
);
}
Troubleshooting Checklist
When encountering a blank page after deployment:
- Check Browser Console: Look for JavaScript errors
- Verify Asset Loading: Ensure CSS and JS files are loading
- Test API Endpoints: Confirm API calls work in production
- Review Environment Variables: Verify all env vars are set
- Check Build Process: Ensure build completes without errors
- Validate Public Path: Confirm asset paths are correct
- Test Locally: Serve production build locally first
Conclusion
The React blank page after deploy error occurs due to various factors including asset loading issues, JavaScript errors, and configuration problems. By implementing proper build configurations, error handling, and deployment practices, you can ensure your React applications work seamlessly in production environments.
The key to resolving this issue is thorough testing of production builds, proper error handling, and ensuring all assets and API calls work correctly in the deployed environment. Whether you’re deploying to Netlify, Vercel, GitHub Pages, or custom servers, the solutions provided in this guide will help you create robust, production-ready React applications.
Remember to always test your builds locally, implement proper error boundaries, and use environment-appropriate configurations to ensure consistent behavior across all deployment environments.
Related Articles
How to Fix React app works locally but not after build Error
Learn how to fix React apps that work locally but fail after build. Complete guide with solutions for production deployment and build optimization.
How to Fix Vite build works locally but fails in production Error
Learn how to fix Vite builds that work locally but fail in production. Complete guide with solutions for deployment and build optimization.
How to Fix React Router 404 Error on Page Refresh Error
Learn how to fix React Router 404 errors on page refresh. Complete guide with solutions for client-side routing and server configuration.