Migration to Angular 9

The good and the bad

 

Motivation

Migration process

New features: Angular

New features: TypeScript

Other updated or deprecated API

Show us the benchmarks!

The biggest pain in the ***

What about the Ivy?

Q&A

Motivation

Deadline

Security 

vulnerabilities

Feeling fresh and clean

Migration

process

Set up the newest Angular CLI

Update globally

Configure yarn as the default package manager

yarn global add @angular/cli@9.1.7
# whenever, global config
ng config -g cli.packageManager yarn

# in the root directory of your app, locally
ng config cli.packageManager yarn

Run ng update

It will traverse your code and make changes to compiler's config and update changed APIs.

ng update --force @angular/cli@^9 @angular/core@^9
# install newest dependency of Angular
ng add @angular/localize

Update remaining libraries manually

Load polyfills

angular.json
tsconfig*.json

Disable Ivy (for now?)

Review changes and test

New features

Angular

8 > 9

Ivy

  • Smaller bundle sizes

  • Faster testing

  • Better debugging

  • Improved type checking

  • Improved build errors

New features

TypeScript

3.4 > 3.8

 

Faster build with --incremental

// tsconfig.json
{
  compilerOptions: {
    incremental: true,
    outDir: "./lib"
  },
  include: ["./src"]
}

 Saves information about the project graph from the last compilation. For the next compilation it will use that information to detect the least costly way to type-check and emit changes to your project.

"Omit" type

type Person = {
  name: string;
  age: number;
  location: string;
};

type QuantumPerson = Omit<Person, "location">;

// equivalent to
type QuantumPerson = {
  name: string;
  age: number;
};

Smarter union type checking

type S = { done: boolean; value: number };
type T = { done: false; value: number } | { done: true; value: number };

declare let source: S;
declare let target: T;

// now it's OK, earlier this would fail
target = source;

Improved type-checking for Promises

interface User {
  name: string;
  age: number;
  location: string;
}

declare function getUserData(): Promise<User>;
declare function displayUser(user: User): void;

async function f() {
  displayUser(getUserData());
  //              ~~~~~~~~~~~~~
  // Argument of type 'Promise<User>' is not assignable to parameter of type 'User'.
  //   ...
  // Did you forget to use 'await'?
}

Support for recursive type aliases

// now works
type Json =
  | string
  | number
  | boolean
  | null
  | { [property: string]: Json }
  | Json[];

Optional Chaining

// before
if (foo && foo.bar && foo.bar.baz) {
  // ...
}

// after
if (foo?.bar?.baz) {
  // ...
}

/* also works in case of */

// functions
let phoneNo = this.service.getPhoneNo?.();

// arrays
let firstUser = this.service.users?.[0];

Nullish Coalescing

// before
let x = foo !== null && foo !== undefined ? foo : bar();

// after
let x = foo ?? bar();

// What's the difference between `??` and `||`?
// `??` fallbacks when the value is `null` or `undefined`
// `||` fallbacks when the value is falsy

Support for ECMAScript Private Fields

class Person {
  #name: string;

  constructor(name: string) {
    this.#name = name;
  }

  greet() {
    console.log(`Hello, my name is ${this.#name}!`);
  }
}

let jeremy = new Person("Jeremy Bearimy");
jeremy.#name;
//     ~~~~~
// Property '#name' is not accessible outside class 'Person'
// because it has a private identifier.

Other changed APIs

Updated/deprecated APIs

The biggest pain...

Dev build time - Project "A"

Dev build time - Project "S"

+327%

+261%

+152%

+86%

🍺 Calling a bounty 🍺

Possible solution?

Optimizing global stylesheets

// styles.scss

// before
@import "~bootstrap/scss/bootstrap";

// after
@import "~bootstrap/scss/bootstrap-grid";
@import "~bootstrap/scss/bootstrap-reboot";
@import "~bootstrap/scss/dropdown";
@import "~bootstrap/scss/badge";
@import "~bootstrap/scss/button-group";
@import "~bootstrap/scss/breadcrumb";
@import "~bootstrap/scss/list-group";
@import "~bootstrap/scss/card";
@import "~bootstrap/scss/buttons";
@import "~bootstrap/scss/alert";
@import "~bootstrap/scss/forms";
@import "~bootstrap/scss/type";
@import "~bootstrap/scss/utilities/position";
@import "~bootstrap/scss/utilities/background";
@import "~bootstrap/scss/utilities/text";
@import "~bootstrap/scss/utilities/float";
@import "~bootstrap/scss/utilities/spacing";
@import "~bootstrap/scss/utilities/sizing";
// styles.scss

// before
@import "~@progress/kendo-theme-bootstrap/scss/all";

// after
@import "~@progress/kendo-theme-bootstrap/scss/input";
@import "~@progress/kendo-theme-bootstrap/scss/combobox";
@import "~@progress/kendo-theme-bootstrap/scss/grid";
@import "~@progress/kendo-theme-bootstrap/scss/menu";
@import "~@progress/kendo-theme-bootstrap/scss/datetime";
@import "~@progress/kendo-theme-bootstrap/scss/dropzone";
@import "~@progress/kendo-theme-bootstrap/scss/slider";
@import "~@progress/kendo-theme-bootstrap/scss/calendar";
@import "~@progress/kendo-theme-bootstrap/scss/upload";
@import "~@progress/kendo-theme-bootstrap/scss/tabstrip";
@import "~@progress/kendo-theme-bootstrap/scss/panelbar";
@import "~@progress/kendo-theme-bootstrap/scss/splitter";

Show us the benchmarks!

Benchmarks - Project "A"

+152%

+86%

-33%

-16%

-39%

+32%

-7%

+85%

+25%

-38%

-28%

-54%

Benchmarks - Project "S"

+327%

+261%

+30%

-10%

+123%

+67%

-22%

-31%

What about Ivy?

Angular team itself also encourages to do so for any Angular libraries that are developed. It is due to compatibility reasons (source: https://angular.io/guide/ivy#ivy-and-libraries).

 

Angular team provided the new ngcc (Angular Compatibility Compiler) to pre-compile all Angular libraries to be compatible with Ivy.

 

Ivy will add potentially more unpredictable behaviors to your application, that can be unique to your project and may take time to fix it. I think it's better to do this migration iteratively - changing the Angular version itself comes with many changes as it is.

 

You can enable Ivy for your app individually by setting "enableIvy" : true. Also open the package.json and add new script: "postinstall": "ngcc".

Q&A

Thank you!

✋😎

@kajetansw

kajetan.dev

migrating-to-angular-9

By Kajetan Świątek

migrating-to-angular-9

  • 232