ngUpgrade hybrid app failing to bootstrap

Loading

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

CheckpointStatus
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

Leave a Reply

Your email address will not be published. Required fields are marked *