22
Module 22: Debugging Real Production Issues (Senior/Enterprise)
Chapter 22 • Advanced
45 min
Debugging Real Production Issues (Senior/Enterprise)
The Real Problem
Scenario: Production is broken. Users see blank screens. Console shows "Failed to load remoteEntry.js". You have 2 hours to fix it.
The Question: How do I debug Module Federation issues in production when remotes fail to load, versions conflict, or shared dependencies break?
This is where experience matters.
The Production Reality
Common Production Issues
- Remote Loading Failures - remoteEntry.js fails to load
- Version Conflicts - Shared dependencies conflict
- CORS Errors - Cross-origin issues
- Source Map Issues - Can't debug in production
- Network Timeouts - Slow or failed network requests
- Memory Leaks - Apps not unloading properly
The Question: How do we debug each issue?
Issue 1: Remote Loading Failures
Symptoms
- Blank screen
- Console error: "Failed to load remoteEntry.js"
- Network tab shows 404 or timeout
Debugging Steps
Step 1: Check Network Tab
typescript.js
// Open Chrome DevTools → Network tab
// Look for remoteEntry.js request
// Check:
// - Status code (404, 500, timeout?)
// - Response headers
// - Request URL (correct?)
Step 2: Verify Remote URL
typescript.js
// Host App - Log remote URLs
console.log('Remote URLs:', {
products: 'products@https://products.example.com/remoteEntry.js',
checkout: 'checkout@https://checkout.example.com/remoteEntry.js'
})
// Manually test URL in browser
// https://products.example.com/remoteEntry.js
// Should return JavaScript file
Step 3: Check Remote Health
typescript.js
// Test remote endpoint
async function testRemote(url: string) {
try {
const response = await fetch(url, { method: 'HEAD' })
console.log('Remote status:', response.status)
console.log('Remote headers:', Object.fromEntries(response.headers))
return response.ok
} catch (error) {
console.error('Remote test failed:', error)
return false
}
}
// Test all remotes
await testRemote('https://products.example.com/remoteEntry.js')
await testRemote('https://checkout.example.com/remoteEntry.js')
Step 4: Check CORS
typescript.js
// CORS error in console?
// Check remote server CORS headers:
// Access-Control-Allow-Origin: *
// Access-Control-Allow-Methods: GET, HEAD
Solution: Add Error Handling
typescript.js
// Host App - Better error handling
loadChildren: () => import('products/ProductsModule')
.then(m => m.ProductsModule)
.catch(err => {
// Log detailed error
console.error('Failed to load Products remote:', {
error: err,
url: 'products@https://products.example.com/remoteEntry.js',
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent
})
// Send to error tracking
errorTracking.trackError(err, {
source: 'remote-loading',
remote: 'products'
})
// Return fallback
return import('./fallback/products-fallback.module')
.then(m => m.ProductsFallbackModule)
})
Issue 2: Version Conflicts
Symptoms
- Runtime errors: "Cannot read property of undefined"
- Type errors in console
- App works in dev, breaks in production
Debugging Steps
Step 1: Check Shared Dependencies
typescript.js
// Check what versions are loaded
console.log('Angular versions:', {
'@angular/core': require('@angular/core/package.json').version,
'@angular/common': require('@angular/common/package.json').version
})
// Check webpack shared scope
console.log('Shared scope:', __webpack_share_scopes__)
Step 2: Verify Webpack Config
typescript.js
// Host App - webpack.config.js
shared: {
'@angular/core': {
singleton: true,
strictVersion: true, // Should be true for Angular
requiredVersion: '^15.0.0' // Check this matches
}
}
Step 3: Check for Multiple Instances
typescript.js
// Debug: Check if multiple instances loaded
if (window.__ANGULAR_CORE__) {
console.warn('Multiple Angular core instances detected!')
console.log('Instances:', window.__ANGULAR_CORE__)
}
Solution: Fix Version Conflicts
typescript.js
// Option 1: Enforce strict versioning
shared: {
'@angular/core': {
singleton: true,
strictVersion: true, // Enforce matching versions
requiredVersion: '^15.0.0'
}
}
// Option 2: Allow version tolerance (risky)
shared: {
'@angular/core': {
singleton: true,
strictVersion: false, // Allow different versions
requiredVersion: '^15.0.0 || ^16.0.0'
}
}
Issue 3: Source Map Issues
Symptoms
- Can't debug in production
- Stack traces show minified code
- Breakpoints don't work
Solution: Enable Source Maps
typescript.js
// webpack.config.js
module.exports = {
devtool: 'source-map', // Or 'hidden-source-map' for production
// Or for production:
devtool: process.env.NODE_ENV === 'production'
? 'hidden-source-map' // Source maps, but not exposed
: 'eval-source-map' // Fast for development
}
Debug Production with Source Maps
typescript.js
// 1. Build with source maps
ng build --source-map
// 2. Upload source maps to error tracking service
// (Sentry, LogRocket, etc.)
// 3. Don't expose source maps publicly
// Use hidden-source-map or upload to private service
Issue 4: Network Timeouts
Symptoms
- Slow loading
- Timeouts in console
- Intermittent failures
Debugging Steps
Step 1: Measure Load Times
typescript.js
// Measure remote load time
async function measureRemoteLoad(name: string, url: string) {
const start = performance.now()
try {
const response = await fetch(url, {
method: 'HEAD',
signal: AbortSignal.timeout(10000) // 10 second timeout
})
const duration = performance.now() - start
console.log(`${name} load time: ${duration}ms`)
return { success: true, duration }
} catch (error) {
const duration = performance.now() - start
console.error(`${name} failed after ${duration}ms:`, error)
return { success: false, duration, error }
}
}
// Measure all remotes
await measureRemoteLoad('products', 'https://products.example.com/remoteEntry.js')
await measureRemoteLoad('checkout', 'https://checkout.example.com/remoteEntry.js')
Step 2: Check CDN Performance
typescript.js
// Test CDN performance
const locations = [
'us-east-1',
'eu-west-1',
'ap-southeast-1'
]
for (const location of locations) {
const url = `https://cdn-${location}.example.com/remoteEntry.js`
await measureRemoteLoad(`CDN ${location}`, url)
}
Solution: Add Timeouts and Retries
typescript.js
// Host App - Timeout with retry
async function loadRemoteWithRetry(
name: string,
url: string,
maxRetries: number = 3
): Promise<any> {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), 10000)
const response = await fetch(url, {
signal: controller.signal
})
clearTimeout(timeoutId)
if (response.ok) {
return await response.text()
}
} catch (error) {
console.warn(`${name} attempt ${attempt} failed:`, error)
if (attempt < maxRetries) {
// Exponential backoff
await new Promise(resolve =>
setTimeout(resolve, 1000 * Math.pow(2, attempt - 1))
)
} else {
throw error
}
}
}
}
Issue 5: Memory Leaks
Symptoms
- Browser slows down over time
- Memory usage increases
- Apps not unloading
Debugging Steps
Step 1: Check Memory Usage
typescript.js
// Chrome DevTools → Memory tab
// Take heap snapshot before navigation
// Navigate to remote
// Take heap snapshot after
// Compare: Look for retained objects
Step 2: Check Event Listeners
typescript.js
// Check for leaked event listeners
// Chrome DevTools → Performance tab
// Record → Navigate → Stop
// Look for event listeners not cleaned up
Solution: Proper Cleanup
typescript.js
// Remote App - Cleanup on destroy
export class ProductsComponent implements OnDestroy {
private subscriptions = new Subscription()
constructor(private eventBus: EventBus) {
// Subscribe
const sub = this.eventBus.on('cart:updated').subscribe(...)
this.subscriptions.add(sub)
}
ngOnDestroy() {
// Cleanup subscriptions
this.subscriptions.unsubscribe()
// Cleanup event listeners
// Cleanup timers
// Cleanup DOM references
}
}
Debugging Tools
Chrome DevTools
- Network Tab - Check remote loading
- Console Tab - Check errors
- Sources Tab - Debug with source maps
- Application Tab - Check localStorage, cookies
- Memory Tab - Check memory leaks
Webpack Bundle Analyzer
bash.js
# Install
npm install --save-dev webpack-bundle-analyzer
# Analyze
npx webpack-bundle-analyzer dist/host-app/stats.json
Module Federation DevTools
typescript.js
// Add to Host App
if (!environment.production) {
// Log Module Federation info
console.log('Module Federation Info:', {
remotes: __webpack_require__.cache,
shared: __webpack_share_scopes__
})
}
Production Debugging Checklist
- [ ] Network tab checked for remote loading
- [ ] Console errors reviewed
- [ ] Source maps enabled (hidden)
- [ ] Error tracking configured
- [ ] Performance monitoring active
- [ ] Memory leaks checked
- [ ] CORS issues resolved
- [ ] Version conflicts identified
Key Takeaways
- Network tab first - Check remote loading
- Console errors - Read error messages carefully
- Source maps - Enable for production debugging
- Error tracking - Log errors automatically
- Performance monitoring - Measure load times
Remember: Debugging production issues requires systematic investigation. Start with network, then console, then code.
The next module: Migration from monolith to micro frontends.
Related Tutorials
Previous: Module 21: Advanced Module Federation Configurations (Senior/Enterprise)
Learn about module 21: advanced module federation configurations (senior/enterprise)
Next: Module 23: Migration from Monolith to Micro Frontends (Senior/Enterprise)
Continue with module 23: migration from monolith to micro frontends (senior/enterprise)