No articles found
Try different keywords or browse our categories
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.
The ‘Angular app not working after build’ is a common production deployment issue that occurs when an Angular application functions correctly in development but fails after building for production. This problem typically stems from differences between development and production build configurations, optimization processes, or environment-specific code.
This comprehensive guide explains what causes this issue, why it happens, and provides multiple solutions to fix it in your Angular projects with clean code examples and directory structure.
What is the Production Build Issue?
The “Angular app not working after build” issue manifests when your application:
- Builds successfully but fails to load in the browser
- Shows blank pages or runtime errors in production
- Works in development but breaks after
ng build --prod - Has different behavior between development and production environments
Common Error Manifestations:
- Blank white screen after build
- JavaScript runtime errors in production
- Assets not loading after build
- Routing issues in production
- Service worker problems
- Lazy loading failures
Understanding the Problem
Production builds differ from development builds in several ways:
- Code optimization and minification
- Tree shaking and dead code elimination
- Different build configurations
- Environment-specific code paths
- Service worker activation
- Asset path differences
Typical Angular Project Structure:
my-angular-app/
├── package.json
├── angular.json
├── src/
│ ├── app/
│ │ ├── app.component.ts
│ │ ├── app.component.html
│ │ ├── app.module.ts
│ │ ├── app-routing.module.ts
│ │ ├── services/
│ │ │ └── data.service.ts
│ │ ├── components/
│ │ │ └── my-component/
│ │ │ ├── my-component.component.ts
│ │ │ └── my-component.component.html
│ │ └── environments/
│ │ ├── environment.ts
│ │ └── environment.prod.ts
│ ├── assets/
│ ├── index.html
│ └── styles.css
├── dist/
│ └── my-app/
│ ├── index.html
│ ├── main.js
│ ├── polyfills.js
│ └── ...
└── node_modules/
Solution 1: Check Production Build Configuration
Ensure your production build configuration is correct.
❌ Incorrect Production Configuration:
// angular.json - Incorrect production configuration
{
"projects": {
"my-app": {
"architect": {
"build": {
"configurations": {
"production": {
"optimization": false, // ❌ Should be true for production
"buildOptimizer": false, // ❌ Should be true for production
"outputHashing": "none", // ❌ Should use hashing for cache busting
"sourceMap": true // ❌ Should be false in production
}
}
}
}
}
}
}
✅ Correct Production Configuration:
angular.json:
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"my-app": {
"projectType": "application",
"schematics": {},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/my-app",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": [
"zone.js"
],
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.css"
],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"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
"serviceWorker": true, // ✅ Enable service worker if needed
"ngswConfigPath": "ngsw-config.json" // ✅ Service worker config
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
}
}
}
}
}
Solution 2: Fix Environment-Specific Code
Ensure environment-specific code works in both development and production.
❌ Environment-Specific Issues:
// src/app/services/data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class DataService {
// ❌ Hardcoded development URL
private apiUrl = 'http://localhost:3000/api';
constructor(private http: HttpClient) { }
getData() {
return this.http.get(this.apiUrl);
}
}
✅ Environment-Aware Code:
environment.ts (Development):
export const environment = {
production: false,
apiUrl: 'http://localhost:3000/api'
};
environment.prod.ts (Production):
export const environment = {
production: true,
apiUrl: 'https://api.myapp.com' // ✅ Production API URL
};
Updated Service:
// src/app/services/data.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class DataService {
private apiUrl = environment.apiUrl; // ✅ Use environment-specific URL
constructor(private http: HttpClient) { }
getData() {
return this.http.get(this.apiUrl);
}
}
Solution 3: Handle Runtime Errors Properly
Implement proper error handling for production environments.
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 {
// Send error to your logging service
console.error('Production Error:', error);
// Example: send to external logging service
// this.loggingService.log(error);
}
}
app.module.ts:
import { NgModule, ErrorHandler } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule } from '@angular/common/http';
import { AppComponent } from './app.component';
import { GlobalErrorHandler } from './services/error-handler.service';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
HttpClientModule
],
providers: [
{ provide: ErrorHandler, useClass: GlobalErrorHandler } // ✅ Global error handler
],
bootstrap: [AppComponent]
})
export class AppModule { }
Solution 4: Fix Asset Path Issues
Ensure asset paths work correctly in production builds.
❌ Incorrect Asset Paths:
<!-- src/index.html - Incorrect asset paths -->
<head>
<!-- ❌ Relative paths may break in production -->
<link rel="stylesheet" href="assets/styles.css">
<link rel="icon" href="assets/favicon.ico">
</head>
✅ Correct Asset Paths:
index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My App</title>
<base href="/"> <!-- ✅ Base href for routing -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="manifest" href="manifest.webmanifest">
<meta name="theme-color" content="#1976d2">
</head>
<body>
<app-root></app-root>
<noscript>Please enable JavaScript to continue using this application.</noscript>
</body>
</html>
assets/ subdirectory structure:
src/assets/
├── images/
│ ├── logo.png
│ └── background.jpg
├── data/
│ └── config.json
└── favicon.ico
Solution 5: Configure Base Href for Routing
Set the correct base href for Angular routing in production.
❌ Without Base Href:
<!-- Without base href, routing may fail in production -->
<head>
<title>My App</title>
<!-- Missing base href -->
</head>
✅ With Base Href:
Build with Base Href:
# Build with specific base href
ng build --base-href="/my-app/"
# Or set in angular.json
# "baseHref": "/my-app/"
angular.json (Base Href Configuration):
{
"projects": {
"my-app": {
"architect": {
"build": {
"options": {
"baseHref": "/" // ✅ Set base href for routing
}
}
}
}
}
}
Solution 6: Fix Lazy Loading Issues
Ensure lazy-loaded modules work correctly in production builds.
feature-routing.module.ts:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { FeatureComponent } from './feature.component';
const routes: Routes = [
{
path: 'feature',
component: FeatureComponent,
data: { preload: true } // ✅ Preload strategy
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class FeatureRoutingModule { }
feature.module.ts:
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FeatureComponent } from './feature.component';
import { FeatureRoutingModule } from './feature-routing.module';
@NgModule({
declarations: [
FeatureComponent
],
imports: [
CommonModule,
FeatureRoutingModule
]
})
export class FeatureModule { }
Solution 7: Implement Proper Service Worker Configuration
Configure service worker for production caching and offline support.
ngsw-config.json:
{
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
}
Working Code Examples
Complete Production-Ready Component:
// src/app/components/production-ready/production-ready.component.ts
import { Component, OnInit, OnDestroy } from '@angular/core';
import { environment } from '../../environments/environment';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-production-ready',
template: `
<div class="production-component">
<h2>Environment: {{ environmentName }}</h2>
<p>Production Mode: {{ isProduction }}</p>
<button (click)="loadData()">Load Data</button>
<div *ngIf="loading">Loading...</div>
<div *ngIf="error" class="error">{{ error }}</div>
<div *ngIf="data">{{ data | json }}</div>
</div>
`,
styles: [`
.production-component { padding: 20px; }
.error { color: red; }
`]
})
export class ProductionReadyComponent implements OnInit, OnDestroy {
environmentName = environment.production ? 'Production' : 'Development';
isProduction = environment.production;
data: any = null;
loading = false;
error: string | null = null;
private subscription = new Subscription();
ngOnInit() {
// Initialize component for production
console.log('Component initialized in', this.environmentName, 'mode');
}
ngOnDestroy() {
// Clean up subscriptions in production
this.subscription.unsubscribe();
}
loadData() {
this.loading = true;
this.error = null;
// Simulate data loading with proper error handling
setTimeout(() => {
try {
if (Math.random() > 0.1) { // 90% success rate
this.data = { message: 'Data loaded successfully' };
} else {
throw new Error('Failed to load data');
}
} catch (error: any) {
this.error = environment.production
? 'An error occurred. Please try again.' // User-friendly message in production
: error.message; // Detailed error in development
} finally {
this.loading = false;
}
}, 1000);
}
}
Production-Ready Service:
// src/app/services/production-service.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError, of } from 'rxjs';
import { catchError, retry } from 'rxjs/operators';
import { environment } from '../environments/environment';
@Injectable({
providedIn: 'root'
})
export class ProductionService {
private apiUrl = environment.apiUrl;
constructor(private http: HttpClient) { }
getData(): Observable<any> {
return this.http.get(this.apiUrl).pipe(
retry(2), // Retry failed requests
catchError((error: HttpErrorResponse) => {
let errorMessage = '';
if (environment.production) {
// Production error handling
errorMessage = 'An error occurred. Please try again.';
} else {
// Development error handling
if (error.error instanceof ErrorEvent) {
errorMessage = `Client Error: ${error.error.message}`;
} else {
errorMessage = `Server Error: ${error.status} - ${error.message}`;
}
}
console.error('API Error:', errorMessage);
return throwError(() => new Error(errorMessage));
})
);
}
}
Best Practices for Production Builds
1. Use Production Environment Variables
// ✅ Always use environment variables for configuration
export const API_CONFIG = {
BASE_URL: environment.apiUrl,
TIMEOUT: environment.production ? 5000 : 10000
};
2. Implement Proper Logging
// ✅ Use conditional logging based on environment
if (!environment.production) {
console.log('Debug info:', data);
}
3. Optimize Bundle Size
# ✅ Use build optimization
ng build --optimization=true --build-optimizer=true
4. Test Production Builds Locally
# ✅ Serve production build locally for testing
ng build --configuration=production
npx http-server dist/my-app
Debugging Production Issues
Step 1: Enable Production Error Logging
// Add error logging in production
if (environment.production) {
window.addEventListener('error', (event) => {
console.error('Production Error:', event.error);
// Send to error tracking service
});
}
Step 2: Check Browser Console
# Open browser developer tools and check console for errors
# Look for JavaScript errors, network failures, or CORS issues
Step 3: Test Production Build Locally
# Build and serve production version locally
ng build --configuration=production
npx http-server dist/my-app
Step 4: Verify Asset Loading
# Check if all assets (CSS, JS, images) are loading correctly
# Look for 404 errors in network tab
Common Production Issues to Avoid
1. Development-Specific Code in Production
// ❌ Don't use development-specific code in production
if (location.hostname === 'localhost') {
// This won't work in production
}
// ✅ Use environment variables instead
if (!environment.production) {
// Development-specific code
}
2. Hardcoded URLs
// ❌ Don't hardcode URLs
private apiUrl = 'http://localhost:3000/api';
// ✅ Use environment variables
private apiUrl = environment.apiUrl;
3. Missing Polyfills
// ✅ Ensure all necessary polyfills are included
// Check browser compatibility requirements
4. Incorrect Base Href
<!-- ✅ Always set correct base href -->
<base href="/">
Performance Considerations
1. Optimize Bundle Size
# Analyze bundle size
npm install -g webpack-bundle-analyzer
ng build --stats-json
npx webpack-bundle-analyzer dist/my-app/stats.json
2. Implement Lazy Loading
// ✅ Use lazy loading for feature modules
const routes: Routes = [
{
path: 'feature',
loadChildren: () => import('./feature/feature.module').then(m => m.FeatureModule)
}
];
3. Use OnPush Change Detection
// ✅ Use OnPush strategy for performance
@Component({
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MyComponent { }
Security Considerations
1. Sanitize User Input
// ✅ Always sanitize user input in production
import { DomSanitizer } from '@angular/platform-browser';
export class MyComponent {
constructor(private sanitizer: DomSanitizer) {}
sanitizeContent(content: string) {
return this.sanitizer.bypassSecurityTrustHtml(content);
}
}
2. Secure API Calls
// ✅ Use HTTPS in production
private apiUrl = environment.production
? 'https://api.myapp.com'
: 'http://localhost:3000/api';
Testing Production Builds
1. Build and Serve Test
# Build for production
ng build --configuration=production
# Serve locally to test
npx http-server dist/my-app
2. End-to-End Testing
# Run e2e tests on production build
ng e2e
3. Performance Testing
# Use Lighthouse for performance testing
npx lighthouse http://localhost:8080
Alternative Solutions
1. Use Different Build Configurations
# Create custom build configurations
ng build --configuration=staging
2. Implement Feature Flags
// Use feature flags for production
export const FEATURES = {
NEW_UI: environment.production ? false : true,
BETA_FEATURES: false
};
Migration Checklist
- Verify production build configuration in angular.json
- Check environment-specific code and variables
- Test production build locally before deployment
- Verify asset paths and base href configuration
- Implement proper error handling for production
- Test lazy loading modules in production build
- Verify service worker configuration (if used)
- Check bundle size and optimize if necessary
- Update documentation for team members
Conclusion
The ‘Angular app not working after build’ issue is typically caused by differences between development and production build configurations, environment-specific code, or optimization-related problems. By following the solutions provided in this guide—whether through proper build configuration, environment management, error handling, or asset path fixes—you can ensure your Angular applications work seamlessly in production environments.
The key is to understand the differences between development and production builds, implement proper environment management, and thoroughly test production builds before deployment. With proper configuration and testing, your Angular applications will function correctly in both development and production environments, providing a reliable user experience.
Remember to always test production builds locally, implement proper error handling, and follow Angular’s best practices for production deployments to ensure your applications are robust and performant in real-world scenarios.
Related Articles
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.
Fix: Angular ExpressionChangedAfterItHasBeenCheckedError Error
Learn how to fix the 'ExpressionChangedAfterItHasBeenCheckedError' in Angular. This comprehensive guide covers change detection, lifecycle hooks, and best practices.
How to Fix Cannot find module '@angular/compiler-cli Error in Angular'
Learn how to fix the 'Cannot find module @angular/compiler-cli' error in Angular projects. This comprehensive guide covers installation, dependencies, and best practices.