Blog
Contact

Upgrade from Angular 2.RC4 to final with Angular-CLI

Michael Prentice
Oct 22, 2016

I’ve completed the RC4 => 2.1.2 upgrade for one proprietary app and one open source app. Even with experience, this process is far from efficient or problem-free with the various libraries, modules, and systems breaking or otherwise affecting each other.

It’s clear the Angular 2 Release Candidates were actually Alphas and what we’re using now in 2.1.1 is Beta. You could say that the Angular Core is in Release Candidate state currently, but the ecosystem of semi-mandatory modules that make up the platform are mostly in some form of Alpha or Beta.

Let’s get started

If you update your version of the CLI first from beta.10 to beta.19, you may see this error message:

Error message about using an old version of the Angular CLI

Note that there is an updated guide here: https://github.com/angular/angular-cli/wiki/Upgrading-from-Beta.10-to-Beta.14

I also submitted a PR to improve the grammar of this upgrade warning message.

The first step of this helpful guide is to make sure that you are up to Angular RC6 or greater. So you would then find that you need to upgrade from Angular RC4 to the latest which includes the major breaking change of ngModules announced in this blog post. This blog post announcing Angular RC5 includes a really helpful link to a migration guide. Unfortunately, that migration guide (https://angular.io/docs/ts/latest/cookbook/rc4-to-rc5.html) is a 404 on the Angular.io docs site.

Now the task is to find a migration guide that works for RC4 to final

There was a Reddit discussing this lost migration guide, but it doesn’t point to a new location.

There is StackOverflow question that poses this exact question, but it’s first suggested solution appears to be the most time intensive option… review the changelogs for RC5, RC6, RC7, and final for breaking changes and then make adjustments to your project. The second option here is one that I have been considering, generate a new project with the latest angular-cli beta.19 and then pull that configuration into your existing project.

After quite a bit of looking, I didn’t really find something that I was happy with. A few guides hit about 25% of what I needed, but I couldn’t find anything that was much more complete.

Get up to speed with the concepts first

I highly suggest reading the following before starting:

The first is the Angular team blog post that covers the reasons why ngModule exists and how it helps you.

Then the official docs on ngModule cover some key patterns like having a Core Module and Shared Module. It also covers lazy loading modules.

Start with a single ngModule

This step involves just creating a single module and adding everything to it. This makes sense for small to medium-sized projects. If your project is already large, you’ll want to move on to the next step.

Basically this step just involves using the docs links above to create your AppModule and plumb everything together.

Away with the boilerplate!

After you’ve got an ngModule, you’ll need a lot less boilerplate. Unfortunately, you (or angular-cli) already wrote it, so you’ll have to go and remove it now. This includes changing all of your components by removing their directives, providers, pipes, and lots and lots of imports that aren’t needed anymore.

Create a Shared Module

Use the docs on creating a Shared Module and move your application-wide services and common Angular modules (FormsModule, RouterModule, etc.) into this new SharedModule.

Evaluate your project for modularity

Now you’ll want to think about your project and find out if it makes sense to break up specific routes into lazily loaded modules. Ideally, your module that is bootstrapped at the root of your app should be as lean as possible. Once you’ve identified these modules, it’s time to create them and start setting up the lazy loading in the router.

Migrate Angular-CLI

OK, now you’ve setup ngModules and updated your package.json to use @angular/xxx: 2.1.2, you are ready to proceed with the angular-cli migration guide. Carefully follow the guide, and you will be about 90% of the way there.

Many people noticed that their favicon and 404 pages weren’t showing up in dist/ after upgrading. The community filed numerous bugs, but in beta.19 this was fixed. Make the changes below to take advantage of this new feature that allows specifying an array of assets.

angular-cli.json (old)

"assets": "assets",

angular-cli.json (new)

"assets": [
  "assets",
  "elements.html",
  "404.html",
  "favicon.ico",
  "manifest.webapp",
  "icons"
],

Obviously the contents of this array will be specific to your application.

Migrate Angular Material2

Their getting started guide provides the minimal level of help required to get this working. This has changed quite a bit from what was found in the RC5 blog post. There is now a single MaterialModule that you need to load.

src/app/app.module.ts

import { MaterialModule } from '@angular/material';

@NgModule({
  imports: [MaterialModule.forRoot()],

If you are using any of their sliders, you’ll need to import hammer.js with the new angular-cli process.

angular-cli.json

{
  "scripts": ["../node_modules/hammerjs/hammer.js"]
}

Additionally, material2 now has a theming system which you will need to configure for the styling of your UI components to look good (i.e. not be mostly grey). See their theming guide here to set this up.

Migrate Firebase

If you are using the Firebase SDK (required for many features like Firebase Storage that aren’t yet supported in AngularFire2) then the way that you load that library has changed in the angular-cli.

Make sure you don’t also include the @types/firebase definitions in your package.json.

angular-cli.json

{
  "scripts": ["../node_modules/firebase/firebase.js"]
}

Upgrade AngularFire2

Their docs are quite helpful, but they only covered about 95% of what I needed to do. That last 5% was pretty painful as what I got working in angular-cli beta.17 needed more tweaking with beta.19.

For just using AngularFire2 without Firebase Auth, you can do this:

src/app/app.module.ts

import { AngularFireModule } from 'angularfire2';

const firebaseConfig = {
  apiKey: '<your-key>',
  authDomain: '<your-project-authdomain>',
  databaseURL: '<your-database-URL>',
  storageBucket: '<your-storage-bucket>'
};

@NgModule({
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(firebaseConfig)
  ],

If you’re using Firebase Auth, you’ll need a bit more. They cover this in their Auth docs.

I submitted a PR to help make these docs a little more straightforward.

src/app/app.module.ts

import { AngularFireModule, AuthProviders, AuthMethods } from 'angularfire2';

const myFirebaseConfig = {
  apiKey: '<your-key>',
  authDomain: '<your-project-authdomain>',
  databaseURL: '<your-database-URL>',
  storageBucket: '<your-storage-bucket>',
}

const myFirebaseAuthConfig = {
  provider: AuthProviders.Google,
  method: AuthMethods.Redirect
}

@NgModule({
  imports: [
    BrowserModule,
    AngularFireModule.initializeApp(myFirebaseConfig, myFirebaseAuthConfig)
  ],

**Troubleshooting **I needed to do a bit more here to deal with some TypeScript issues. Their existing docs here seemed to be designed for an older version of the angular-cli. I needed to remove @types/firebase from my package.json and use the typedefs from the Firebase SDK.

src/tsconfig.json

"files": [
  "../node_modules/firebase/firebase.d.ts"
]

If you are on the new AngularFire2 beta.6, this step is not needed since these typedefs are included in AngularFire2. Adding them again here will cause many duplicate type errors.

Upgrade Angular2-Google-Maps

The docs here are quite comprehensive and once I followed them, everything seemed to just work. The main change is related to ngModule.

They also fixed some pesky bugs in the latest v0.15.0 release.

src/app/app.module.ts

import { AgmCoreModule } from 'angular2-google-maps/core';

@NgModule({
  imports: [
    BrowserModule,
    AgmCoreModule.forRoot({
      apiKey: 'YOUR_KEY'
    })
  ],

Upgrade Angular2-Polymer

The Vaadin team has done a lot of the tough work to streamline this process. Their documentation can be found here.

As part of this process, I sent them a PR to correct their README’s link to these docs.

One of the key changes here is the way that bootstrapping the Web Components polyfill is accomplished due to changes to the angular-cli. This includes creating a main-polymer.ts file which kicks off the bootstrapping of your Angular application after the WebComponentsReady event is fired.

src/main-polymer.ts

document.addEventListener('WebComponentsReady', () => {
  // Load Angular app
  require('./main.ts');
});

Then you need to update angular-cli’s config to use this new main-polymer.ts as your app’s entry point.

angular-cli.json

"main": "main-polymer.ts",

Another key change from the angular-cli is that loading the webcomponents-lite.min.js file is now easier. I also decided to get it from NPM instead of Bower.

angular-cli.json

{
  "scripts": ["../node_modules/webcomponents.js/webcomponents-lite.js"]
}

Fix issues with Basic Web Components

I found that the key here was to require the Basic Web Component scripts in the main-polymer.ts file defined as part of the Angular2-Polymer configuration above. These web components don’t have type definitions for TypeScript and importing their ES6 modules was a nightmare.

src/main-polymer.ts

document.addEventListener('WebComponentsReady', () => {
  // Load basic web components
  require('../node_modules/basic-arrow-selection');
  require('../node_modules/basic-carousel');
  require('../node_modules/basic-page-dots');

  // Load Angular app
  require('./main.ts');
});

This worked somewhat, but still resulted in errors since the angular-cli doesn’t have an ES6 loader configured (separate from the TypeScript loader) and they don’t allow for customization of the Webpack configuration. This ES6 still ran OK on the latest Firefox, Chrome, and Safari, but it failed on IE11.

Due to this, I ended up removing Basic Web Components from my project and using ngBootstrap’s Carousel instead.

Michael Prentice
Oct 22, 2016