Upgrading Angular 4 to Angular 6 without tooling support

The purpose of this post is to describe the steps necessary to upgrade from Angular 4 to Angular 6. Pretty simple task if you read any of the gushing posts on the topic – “Just run the Angular CLI tool ng update and like magic everything will be upgraded for you.” However as I tend to subscribe to the following ethos:

Developers who live by the tooling, die by the tooling

I wanted to understand how this “magic” works under the hood. And there is no better way to understand such things than to actually Do It Yourself!

Initial Dependency Upgrades

Packages

Obviously, the first step in upgrading to v6 is to bump up the dependency & devDependency minimum version numbers in package.json. Angular 6 depends on typescript ^2.7.0 and rxjs ^6.0 hence these need to be updated as well, along with the core Angular packages. To divide and conquer the angular upgrade problem I’ve also added a new dependency rxjs-compat, allowing me to defer migration of my RxJS code from the old chaining style to the new pipeable operators until another day.

Code changes

Compiling with the typescript command line compiler indicated that there was only one breaking change in my codebase – OpaqueToken no longer existed. Fortunately I remembered seeing this in the Angular Upgrade Guide, and the fix is to change over to using InjectionToken instead. Once this change was made all my typescript code compiled perfectly!

Module Loading

This project has its origins in the Angular 2 RC Quickstart repo, which used the SystemJS ES Module Loader. SystemJS has served me well for many previous Angular version upgrades, but things got a bit rough in the jump from v4.x to v6.0.

Given the pain free progress made up to this point, I was almost feeling cocky about getting things to work in the browser. I’d only added a single new dependency in the process, rxjs-compat, so I initially just added this to the packages section of systemjs.config.js, fired up my ASP.NET Core server and pointed my browser at the appropriate URL… fail!

The initial error message was quite helpful, clearly indicating that I needed to define the module location for rxjs/operators too. Rectifying this, I tried again, but this time met with a much more unhelpful error in the browser console:

Error: (SystemJS) Object prototype may only be an Object or null: undefined
TypeError: Object prototype may only be an Object or null: undefined
   at setPrototypeOf (<anonymous>)
   at __extends (http://localhost:5000/js/node_modules/@angular/platform-browser//bundles/platform-browser.umd.js:34:5)
   at eval (http://localhost:5000/js/node_modules/@angular/platform-browser//bundles/platform-browser.umd.js:642:5)
   at Object.eval (http://localhost:5000/js/node_modules/@angular/platform-browser//bundles/platform-browser.umd.js:704:2)

WTF?! Bad enough to have me having flashbacks to the bad old AngularJS days! After several hours, much reading on the web and multiple failed attempts following forum suggestions of dubious veracity I landed on the following changes to system.config.js which seemed to work:

Other articles in this series

  1. Upgrading Angular 4 to Angular 6 without tooling support
  2. Upgrading from HttpModule to HttpClientModule
  3. Upgrading Angular 6 to Angular 8 without tooling support
  4. Upgrading from RxJS code from chainable operators to pipeable operators (TBD)
  5. Merging these changes in to my ASP.NET Core 2 SignalR development branch… gulp! (TBD)