When working with an AngularJS + Angular (ngUpgrade) hybrid app, a common issue developers face is the hybrid app failing to bootstrap. Bootstrapping a hybrid app involves initializing both AngularJS and Angular in the same application, and if this isn’t configured properly, the app either crashes silently or throws cryptic errors.
This guide walks you through the possible causes and step-by-step debugging instructions to fix a hybrid Angular app that’s failing to bootstrap.
Step-by-Step Diagnosis and Resolution
1. Verify AngularJS and Angular Compatibility
Key versions matter. Not all versions of Angular are compatible with all versions of AngularJS.
- AngularJS should be 1.7.x or at least 1.6.x
- Angular (Angular 2+) should be 4+, ideally 9+
- Check for matching
zone.js
,rxjs
, and@angular/upgrade
"angular": "~10.0.0",
"angularjs": "1.7.9",
"@angular/upgrade": "~10.0.0"
Mismatch between Angular and AngularJS versions can cause silent failures or throw errors during runtime.
2. Ensure Proper Import of UpgradeModule
In your AppModule
:
import { UpgradeModule } from '@angular/upgrade/static';
@NgModule({
declarations: [ /* ... */ ],
imports: [
BrowserModule,
UpgradeModule, // Required for hybrid bootstrapping
],
})
export class AppModule {
constructor(private upgrade: UpgradeModule) {}
ngDoBootstrap(appRef: ApplicationRef) {
this.upgrade.bootstrap(document.body, ['legacyApp'], { strictDi: true });
}
}
Common Mistake: Forgetting to call upgrade.bootstrap()
or using Angular’s platformBrowserDynamic().bootstrapModule()
instead of manual bootstrapping.
3. Check AngularJS App Module Exists
Your AngularJS module should be registered and loaded before Angular tries to upgrade it:
angular.module('legacyApp', []);
And include the module in angular.json
or index.html
:
<script src="legacy-app.module.js"></script>
Make sure AngularJS files are loaded before Angular.
4. Verify main.ts
Uses ngDoBootstrap
You must not use bootstrapModule(AppModule)
in main.ts
if you’re using ngUpgrade
with manual bootstrapping:
platformBrowserDynamic().bootstrapModule(AppModule); // WRONG for hybrid apps
Instead, Angular will bootstrap itself from ngDoBootstrap()
inside AppModule
.
So your main.ts
should simply import AppModule
and let Angular boot from ngDoBootstrap
.
5. Fix Incorrect strictDi
Usage
AngularJS’s $injector
in strictDi
mode requires all dependencies to be annotated:
this.upgrade.bootstrap(document.body, ['legacyApp'], { strictDi: true });
If you’re getting an error like:
[$injector:strictdi] function() does not use explicit annotation
Then either:
- Add explicit
$inject
annotations in your AngularJS services/controllers - Or set
strictDi: false
temporarily to test
6. Make Sure UpgradeModule.bootstrap()
Is Called Once
Double bootstrapping causes the app to fail silently. Ensure you’re not bootstrapping AngularJS and Angular separately.
Do not call this:
angular.bootstrap(document.body, ['legacyApp']); // Wrong
Only use:
this.upgrade.bootstrap(document.body, ['legacyApp']);
7. Check for DOM Readiness
Sometimes document.body
is not yet ready when upgrade.bootstrap()
runs. Wrap it in a DOM ready check:
document.addEventListener('DOMContentLoaded', () => {
platformBrowserDynamic().bootstrapModule(AppModule);
});
Alternatively, ensure your script is loaded at the end of the body.
8. Fix zone.js
Mismatches
zone.js
must be compatible with your Angular version. Wrong versions lead to unexpected bootstrap errors or digest cycle failures.
Check your package.json:
"zone.js": "~0.10.3"
Use the correct zone.js
version that matches Angular’s requirements.
9. Enable Error Logging
In angular.json
, make sure source maps are enabled for better stack traces:
"build": {
"sourceMap": true
}
Use console.log()
liberally in main.ts
, AppModule
, and AngularJS modules to trace what’s being loaded and executed.
10. Hybrid Component Selector Mismatch
Ensure the root Angular component has the correct selector to match what’s in index.html
.
Example:
<body>
<app-root></app-root> <!-- Must match Angular root component -->
</body>
Angular will fail to bootstrap if the selector isn’t found.
Checklist Summary
Checkpoint | Status |
---|---|
Angular and AngularJS versions are compatible | ✅ |
UpgradeModule imported and used | ✅ |
ngDoBootstrap is implemented | ✅ |
Only upgrade.bootstrap() is used (not angular.bootstrap() ) | ✅ |
strictDi issues are resolved | ✅ |
AngularJS module is declared and loaded correctly | ✅ |
DOM is ready before bootstrapping | ✅ |
zone.js version is compatible | ✅ |
Angular component selector is present in HTML | ✅ |