Dual boot with Angular and AngularJS

Important

The source code for this course can be found on GitHub. Each step has it’s own branch, instructions for how to checkout the correct code for each step are in the Project Setup lecture.

Dual boot with Angular and AngularJS

The wait is finally over. In this step we are going to start the actual process of migration from AngularJS to Angular by introducing the concept of Dual Booting. So lets get started!

Dual Booting

During the process of migration you will run both AngularJS and Angular in the same application, at the same time. This concept is known as dual booting, and in this lecture we will see how we can get both the legacy and modern Angular frameworks to co-exist and work together within the same application.

Angular dependencies

Add the following dependency information to the package.json file’s dependencies section to include the required Angular dependencies in our application:

Note

The code below is using Angular 5, use whatever is the latest version of Angular at the time of your migration.
...
"dependencies": {
  "@angular/animations": "^5.0.0",
  "@angular/common": "^5.0.0",
  "@angular/compiler": "^5.0.0",
  "@angular/compiler-cli": "^5.0.0",
  "@angular/core": "^5.0.0",
  "@angular/forms": "^5.0.0",
  "@angular/http": "^5.0.0",
  "@angular/platform-browser": "^5.0.0",
  "@angular/platform-browser-dynamic": "^5.0.0",
  "@angular/platform-server": "^5.0.0",
  "@angular/router": "^5.0.0",
  "@angular/upgrade": "^5.0.0",
  "angular-in-memory-web-api": "~0.5.0",
  "core-js": "^2.4.1",
  "rxjs": "^5.5.0",
  "web-animations-js": "^2.3.1",
  "zone.js": "^0.8.4",
   ...
},
...

Tip

  • Adding a ^ prefix to a version will always install the most recent major version. For example, ^5.0.0 will match any 5.x.x release including 5.3.0, but will hold off on 6.x.x.

  • On the other hand, the ~ prefix will match the most recent minor version. For example, 0.5.0 will match all 0.5.x versions but will miss 1.x.x.

Follow this up with an npm install to install all the newly added dependencies.

Polyfills

A polyfill is a workaround code (or plugin) that provides older browsers compatibility for features the developer, expect the browser to provide natively.

To provide polyfill support to our application, create a file named polyfills.ts in src/app/ and place the following code in it:

Listing 1. pollyfills.ts
// This file includes polyfills needed by Angular and is loaded before
// the app. You can add your own extra polyfills to this file.
import 'core-js/es6/symbol';
import 'core-js/es6/object';
import 'core-js/es6/function';
import 'core-js/es6/parse-int';
import 'core-js/es6/parse-float';
import 'core-js/es6/number';
import 'core-js/es6/math';
import 'core-js/es6/string';
import 'core-js/es6/date';
import 'core-js/es6/array';
import 'core-js/es6/regexp';
import 'core-js/es6/map';
import 'core-js/es6/set';
import 'core-js/es6/reflect';

import 'core-js/es7/reflect';
import 'zone.js/dist/zone';

Tip

You may remove any of the above imports if you are certain your browser can provide the same functionality natively.

Next, add the following import to the main.ts file:

import './polyfills.ts';

Bootstraping Angular and AngularJS

Bootstrapping is an essential process in Angular — it is where the application is loaded when Angular comes to life.

Our current implementation uses the ngApp directive to auto-bootstrap our AngularJS application. But as we move towards dual booting, we need to replace this with a manual bootstrapping method to have more control over the application initialization process.

Lets go ahead and remove the ng-app directive from our index.html file:

<html lang="en" ng-app="codecraft">
...

Your index.html file should now look like this:

<html lang="en">
...

Now, we can bootstrap our application to dual boot in Angular and AngularJS by adding the following code to the main.ts file:

import {NgModule} from '@angular/core';
import {BrowserModule} from '@angular/platform-browser';
import {UpgradeModule} from '@angular/upgrade/static';
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';

@NgModule({
  imports: [
    BrowserModule,
    UpgradeModule
  ]
})

export class AppModule {
  // Override Angular bootstrap so it doesn't do anything
  ngDoBootstrap() {
  }
}

// Bootstrap using the UpgradeModule
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
  console.log("Bootstrapping in Hybrid mode with Angular & AngularJS");
  const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
  upgrade.bootstrap(document.body, ['codecraft']);
});

There’s a lot going on here, so lets breakdown this code to understand what’s happening.

Imports

import {NgModule} from '@angular/core'; (1)
import {BrowserModule} from '@angular/platform-browser'; (2)
import {UpgradeModule} from '@angular/upgrade/static'; (3)
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; (4)
1 The NgModule is a core module that is required in Angular applications.
2 The BrowserModule provides services specific to the browser platform.
3 The UpgradeModule exports providers that will be used for upgrading and downgrading services and components in a hybrid application.
4 The platformBrowserDynamic is a function used to bootstrap an Angular application.

NgModule

(1)
@NgModule({
  imports: [
    BrowserModule,
    UpgradeModule
  ]
})

(2)
export class AppModule {
  // Override Angular bootstrap so it doesn't do anything
  ngDoBootstrap() {
  }
}
1 A bare minimum NgModule importing the BrowserModule, and the UpgradeModule.
2 AppModule class with an empty ngDoBootstrap method override to prevent Angular from bootstrapping itself.

Bootstrapping with Angular

// Bootstrap using the UpgradeModule
platformBrowserDynamic().bootstrapModule(AppModule)

This code snippet uses the platformBrowserDynamic to bootstrap our AppModule in Angular. Typically, this line is sufficient to bootstrap Angular applications, but in our case, we need to hook into the response, which will allow us to bootstrap the rest of our application in AngularJS as shown below:

// Bootstrap using the UpgradeModule
platformBrowserDynamic().bootstrapModule(AppModule).then(platformRef => {
  console.log("Bootstrapping in Hybrid mode with Angular & AngularJS");
  const upgrade = platformRef.injector.get(UpgradeModule) as UpgradeModule;
  upgrade.bootstrap(document.body, ['codecraft']);
});

This is essentially equivalent to the ng-app tag that we had initially in our index.html file.

Fixing warnings

After you complete the above steps, executing npm run build may display a couple of warnings similar to this:

WARNING in ./node_modules/@angular/core/esm5/core.js
6458:15-102 Critical dependency: the request of a dependency is an expression
 @ ./node_modules/@angular/core/esm5/core.js
 @ ./src/app/main.ts

A quick fix for this would be to add the following code to the webpack.config.js file.

  1. Add the following require statments at the top of the file:

      const path = require('path');
      const webpack = require('webpack');
  2. Add the following plugins array to the list of exports:

      plugins: [
          new webpack.ContextReplacementPlugin(
              // if you have anymore problems tweet me at @gdi2290
              // The (\\|\/) piece accounts for path separators for Windows and MacOS
              /(.+)?angular(\\|\/)core(.+)?/,
              path.join(__dirname, 'src'), // location of your src
              {} // a map of your routes
          )
      ]

If you would like a deep dive into this issue and understand whats going on, you can read about it in this github issue thread.

Verification

If all goes well and the application is accessible on localhost, your browser’s console should display the following console.log statement:

Bootstrapping in Hybrid mode with Angular & AngularJS

This is in fact, the same log line that we have added during the bootstrapping process of Angular and AngularJS which confirms that you are now running in dual booting mode.


Caught a mistake or want to contribute to the book? Edit this page on GitHub!


Learn Angular For FREE

I've released my 700 page Kick Starter funded Angular book for FREE