Update to Angular Version 8 now!

Juri Strumpflohner - Aug 5 '19 - - Dev Community

This post has originally been published on https://juristr.com/blog/2019/06/angular-v8. Go to juristr.com/blog for more content


Let's dive into the latest Angular version 8 that just got released. We'll quickly explore what's new, why you should update, how that works and what you should watch out for.

Before you start, there's also an official post about the release from the Angular team:

Check out my related post about "Lazy Load Angular Components"

During the upgrade you will get a notification with a link to more details.

You can read up all the details at https://angular.io/guide/static-query-migration.

If the Angular CLI is not able to automatically infer whether to use the static or dynamic resolution, it'll add a corresponding comment and warning on the console

To summarize, what is it all about?

Assume you have the following:

<div foo></div>
Enter fullscreen mode Exit fullscreen mode

In your code you'd use a @ViewChild such as

@ViewChild(Foo) foo: Foo;
Enter fullscreen mode Exit fullscreen mode

(where Foo is some Angular directive)

Usually it's always safe to assume foo will be populated after the ngAfterViewInit (or ngAfterContentInit for content queries with @ContentChild). However, some of them were also accessible already in the onInit directly. The reason is that the compiler behind the scenes categories them in

  • static queries available immediately
  • dynamic queries available only at runtime

Our code example above would be an example of a static query because <div foo> it is immediately available. We could safely access it in the ngOnInit. On the other side, assume we change the code like

<div foo *ngIf="isVisible"></div>
Enter fullscreen mode Exit fullscreen mode

In such case, it would only become available once isVisible evaluates to true, which might happen at any time while executing the app. Such queries are dynamic queries.

The main problem is that this wasn't explicit. Hence, when upgrading to v8, the code migration will automatically transform your code to

// query results available in ngOnInit
@ViewChild('foo', {static: true}) foo: ElementRef; 

// query results available in ngAfterViewInit
@ViewChild('foo', {static: false}) foo: ElementRef;
Enter fullscreen mode Exit fullscreen mode

TypeScript upgrade

By upgrading to Angular 8 you'll also upgrade to TypeScript 3.4. If you're curious about the new features here's the corresponding documentation.

As a result after the upgrade (even though that completes successfully), you may get errors. Most probably they are due to better type inference which reveal new potential typing issues.

Other Deprecations

Check out the new deprecation guide on the official site. Still have questions? Open an issue in the Angular CLI repository if it's related to the upgrade or on the Angular repository if it's framework related. Or simply ping me on Twitter 😃

FAQ - Potential upgrade issues

Rerun migrations

What if you did the Angular upgrade, but for whatever reason some of the code transformations didn't complete successfully. You end up having Angular 8 (or whatever version you're upgrading) already in your node_modules folder and package.json.

Generally speaking, my suggestion is to use Git. Create a migration branch, which allows you to easily go back and forth during the upgrade. Commit after each step so you've got a backup on the way.

Other than that, the Angular CLI also gives you the possibility to run the migration again, even though you already have the latest version in your package.json. Just execute

// re-run CLI schematics
$ ng update @angular/cli --from 7 --to 8 --migrate-only

// re-run Angular core schematics
$ ng update @angular/core --from 7 --to 8 --migrate-only
Enter fullscreen mode Exit fullscreen mode

Material Upgrade: FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory

When I upgraded Angular material with ng update @angular/material on our fairly large monorepo, I got the following exception.

<--- Last few GCs --->

[85884:0x103802200]   712051 ms: Scavenge 2004.6 (2047.9) -> 2004.5 (2047.9) MB, 4.1 / 0.0 ms  (average mu = 0.199, current mu = 0.181) allocation failure
[85884:0x103802200]   712072 ms: Scavenge 2006.3 (2048.9) -> 2004.6 (2048.4) MB, 3.8 / 0.0 ms  (average mu = 0.199, current mu = 0.181) allocation failure
[85884:0x103802200]   712077 ms: Scavenge 2005.6 (2049.4) -> 2005.6 (2049.9) MB, 4.3 / 0.0 ms  (average mu = 0.199, current mu = 0.181) allocation failure


<--- JS stacktrace --->

==== JS stack trace =========================================

    0: ExitFrame [pc: 0x100e146e6]
Security context: 0x08b76239a2f1 <JSObject>
    1: stringSlice(aka stringSlice) [0x8b725f97839] [buffer.js:~568] [pc=0x1d077761a16a](this=0x08b76f0804d1 <undefined>,0x08b765580f19 <Uint8Array map = 0x8b742025759>,0x08b786894e49 <String[#4]: utf8>,0,1073870)
    2: toString [0x8b7623f02f9] [buffer.js:~622] [pc=0x1d0777ee3789](this=0x08b765580f19 <Uint8Array map = 0x8b742025759>,0x08b786894e49 <String[#4]:...

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0x100075bd5 node::Abort() [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 2: 0x100076316 node::errors::TryCatchScope::~TryCatchScope() [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 3: 0x1001697d7 v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 4: 0x10016976c v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 5: 0x1005480d5 v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 6: 0x1005491c3 v8::internal::Heap::CheckIneffectiveMarkCompact(unsigned long, double) [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 7: 0x100546bc3 v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 8: 0x10054487f v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/Users/jstrumpflohner/.nvm/versions/node/v12.4.0/bin/node]
 ...
[1]    85884 abort      ng update @angular/material @angular/cdk @angular/cdk-experimental
Enter fullscreen mode Exit fullscreen mode

This is a common issue when the node process needs more memory. To solve this, pass the max_old_space_size option to the node process, like this:

$ node --max_old_space_size=8000 ./node_modules/.bin/ng update @angular/material @angular/cdk
Enter fullscreen mode Exit fullscreen mode

Ngrx: Type 'Observable' is not assignable to type 'Observable'

Another strange error I got when upgrading my NX based monorepo from v7 to v8 was the following:

ERROR in libs/r3-core/src/lib/+state/app-config/app-config.effects.ts(22,5): error TS2322: Type '(action: LoadAppConfig, state: AppConfigPartialState) => Observable<AppConfigLoaded>' is not assignable to type '(a: LoadAppConfig, state?: AppConfigPartialState) => void | Action | Observable<Action>'.
  Type 'Observable<AppConfigLoaded>' is not assignable to type 'void | Action | Observable<Action>'.
    Type 'Observable<AppConfigLoaded>' is not assignable to type 'Observable<Action>'.
      Types of property 'source' are incompatible.
        Type 'import("/Users/jstrumpflohner/myapp/node_modules/rxjs/internal/Observable").Observable<any>' is not assignable to type 'import("/Users/jstrumpflohner/myapp/node_modules/@nrwl/angular/node_modules/rxjs/internal/Observable").Observable<any>'.
          Types of property 'operator' are incompatible.
            Type 'import("/Users/jstrumpflohner/myapp/node_modules/rxjs/internal/Operator").Operator<any, any>' is not assignable to type 'import("/Users/jstrumpflohner/myapp/node_modules/@nrwl/angular/node_modules/rxjs/internal/Operator").Operator<any, any>'.
              Types of property 'call' are incompatible.
                Type '(subscriber: import("/Users/jstrumpflohner/myapp/node_modules/rxjs/internal/Subscriber").Subscriber<any>, source: any) => import("/Users/jstrumpflohner/myapp/node_modules/rxjs/internal/types").TeardownLogic' is not assignable to type '(subscriber: import("/Users/jstrumpflohner/myapp/node_modules/@nrwl/angular/node_modules/rxjs/internal/Subscriber").Subscriber<any>, source: any) => import("/Users/jstrumpflohner/myapp/node_modules/@nrwl/angular/node_modules/rxjs/internal/types").TeardownLogic'.
                  Types of parameters 'subscriber' and 'subscriber' are incompatible.
                    Property '_parentOrParents' is missing in type 'Subscriber<any>' but required in type 'Subscriber<any>'.
Enter fullscreen mode Exit fullscreen mode

This seems due to an incompatibility between RxJS and Ngrx v7 in a certain version. Upgrading to Ngrx v8 might solve the issue (I didn't try though). In my case downgrading RxJS to ~6.4.0 helped.

$ yarn add rxjs@~6.4.0
Enter fullscreen mode Exit fullscreen mode

or

$ npm i rxjs@~6.4.0 --save
Enter fullscreen mode Exit fullscreen mode
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .