Header Menu Icon
Blog Post Page Background ImageBlog Post Page Background Image
Angular v7 vs. Angular v8Angular v7 vs. Angular v8

Angular v7 vs. Angular v8

New features in Angular 8

The 8.0.0 release of Angular (from 28th May 2019) is finally here and this major version release spans across whole platform, including framework itself, Angular Material and the CLI. This update includes a preview of Ivy (Angular’s new compiler and new rendering pipeline), Web Worker support, differential loading (thanks to this, modern browsers will have startup time significantly faster) and many more (full list of changes can be seen on Angular’s official changelog).

What is Ivy?

An Ivy is a codename for huge work from the Angular team and a foundation for the future of Angular. Ivy is Angular’s next-generation compiler and rendering pipeline. It’s third in line after the original compiler (for Angular 2) and Renderer2 (for Angular 4 and above). Misko Hevery and Kara Erickson (Software Engineers at Google) gave us the first look of Ivy at ngConf-2018. Currently, Ivy is still in Preview mode and is not feature complete, but you can enable it for experimentation and testing. To start a new project with Ivy enabled, use next command with --enable-ivy flag:
$ ng new my-ivy-app ––enable-ivy
And to update an existing project to use Ivy, set the enableIvy option in the angularCompilerOptions in your project's tsconfig.app.json:


    {
      "compilerOptions": { ... },
      "angularCompilerOptions": {
        "enableIvy": true
      }
    }
    

“Ahead-of-time” (AOT) compilation with Ivy is faster and should be used by default. In the angular.json workspace configuration file, set the default build options for your project to always use AOT compilation.

Ivy is going to have smaller and simpler bundles and faster compilations, as quoted by Angular team. Ivy follows the locality principle, where only one file is compiled at a time. When generating the output, it only looks at a component and its template, not its dependencies. This leads to faster compilation and simplification of process. With locality, there’s more opportunity for meta-programming, like higher order components and the ability to dynamically generate modules, components, or pipes. Ivy uses more efficient tree-shaking, removing unused pieces of your code, which results in smaller bundles and faster load times. Ivy breaks things down into smaller, more atomic functions. These atomic functions make the renderer code much more friendly to tree-shaking, because they generate only the code you need from the template you’ve written.

Web worker support

Web workers are a great way to speed up your application if you do any sort of cpu-intensive processing (like image or video manipulation). They allow you to offload work to a background thread, freeing the main thread to update the user interface. You can add a web worker anywhere in your application. If the file that contains your expensive computation is src/app/app.component.ts you can add a Web Worker using command:
$ ng generate webWorker my-worker

Running this command will:

  • configure your project to use Web Workers, if it isn't already.
  • add src/app/app.worker.ts with scaffolded code to receive messages:

    addEventListener('message', ({ data }) => {
      const response = `worker response to ${data}`;
      postMessage(response);
    });
    
  • add scaffolded code to src/app/app.component.ts to use the worker:

    if (typeof Worker !== 'undefined') {
      // Create a new worker
      const worker = new Worker('./app.worker', { type: 'module' });
      worker.onmessage = ({ data }) => {
        console.log('page got message: ${data}');
      };
      worker.postMessage('hello');
    } else {
      // Web Workers are not supported in this environment.
      // You should add a fallback so that your program still executes correctly.
    }    
    

Once you have a web worker, you can use it normally in your application and you will need to refactor your code to use it by sending messages to and from it.

Differential Loading

Differential loading is a process by which the browser chooses between modern or legacy JavaScript code bundle based on its own capabilities. Until now, it was common to compile applications to old ECMAScript 5, since this JavaScript version runs almost on every browser today. This means that both IE 11 and the web crawler behind the Google search engine can execute the program code successfully. However, the new ECMAScript 2015 and its newer versions are more efficient: these versions allow more compact bundles and the browser can also interpret them more efficiently.

To activate differential loading it is necessary to set an upper and a lower bar for the ECMAScript versions you want to support. The upper bar is entered in the tsconfig.json file:


    {
      "compilerOptions": {
        ...
        "module": "esnext",
        "moduleResolution": "node",
        ...
        "target": "es2015",
        ...
      }
    }    
    

When target is set to es2015, Angular CLI will generate and label two bundles.

The lower bar, on the other hand, is defined by a browserslist, file which CLI creates in project root when generating a new project and where you can identify how many browsers has to be supported:


    > 0.5%
    last 2 versions
    Firefox ESR
    not dead
    IE 9-11
    

In the illustrated case, the browserslist points to ECMAScript 5 browsers with the entry IE 9-11, thereby, the CLI determines the lower bar as this version.

The disadvantage of this process becomes obvious here: the time required for the build process is doubled.

The different browsers can now decide which version of the bundles to load. For this, they receive the script references in the index.html additions: those pointing to ECMAScript 5 bundles receive the addition nomodule. This prevents browsers with support for ECMAScript modules, and thereby ECMAScript 2015 and newer, from ignoring the reference. The ECMAScript 2015+ bundles, on the other hand, are implemented by the CLI via type=”module”. Thus, older browsers will ignore these script tags:


      <script src="main-es2015.js" type="module"></script> <!-- ECMAScript 2015+ -->
  
      <script src="main-es5.js" nomodule></script>         <!-- Older browsers (IE 11), ECMAScript 5 -->
    

Thanks to differential loading (as seen below), the bundle sizes can already be optimized immediately.

Creative Suite vs. Creative Cloud Gradient image
Bundle sizes of a hello world application with and without Ivy (source: ngconf 2019 Keynote by Brad Green and Igor Minar)

Lazy Loading

To create a lazy-loaded module in an Angular app before version 8, you had to do the following:


      import { NgModule } from '@angular/core';
      import { RouterModule } from '@angular/router';
      
      @NgModule({
          imports: [
              RouterModule.forChild([{
                  path: '',
                  loadChildren: './lazy/lazy.module#LazyModule'
              }])
          
      })
      export class MyModule { }
    

The value before the hash sign represents the path which leads to the file with the module implementation; the value afterwards stands for the therein contained class. This style of writing also works with Angular 8, but has been deprecated in favor of dynamic ECMAScript imports, as following:


      import { NgModule } from '@angular/core';
      import { RouterModule } from '@angular/router';
      
      @NgModule({
          imports: [
              RouterModule.forChild([{
                  path: '',
                  loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule)
              }])
          
      })
      export class MyModule { }
    

Breaking change in ViewChild and ContentChild

In Angular version 8, there is a breaking change in the usage of ViewChild and ContentChild. While they were used in earlier versions for a component to request an element not inside a structural directive like ngIf or ngFor, the query result was already available in ngOnInit. Otherwise, the program code could access it at the earliest in ngAfterViewInit (or ngAfterContentInit for ContentChild). For elements that were only loaded into the DOM at a later time due to data binding, the program code had to insert ngAfterViewChecked or, respectively, ngAfterContentChecked.

As this behavior was confusing, the component must now specify when the resolution should take place:
@ViewChild('info', { static: false }) paragraph: ElementRef;

If static has the value true, Angular will try to find the element when initializing the component. This only works if it is not in a structural directive. When using static: false, the resolution takes places after initiating or refreshing the view.

How to update?

Updating Angular CLI to version 8 and updating your project to Angular version 8 from version 7 is very easy process, thanks to all the work that has been done in version 8 and the ng update command, which allows you to update specific versions and dependencies.

Here we provided a checklist that you have to go through to successfully update your Angular application from version 7 to 8:

Before Updating

  • If you use the legacy HttpModule and the Http service, switch to HttpClientModule and the HttpClient service. HttpClient simplifies the default ergonomics (you don't need to map to JSON anymore) and now supports typed return values and interceptors.
  • Once you and all of your dependencies have updated to RxJS 6, remove rxjs-compat.
  • If you use the Angular Service worker, migrate any versionedFiles to the files array. The behavior is the same.

During the Update

  • Update to version 8 of the core framework and CLI by running in your terminal:
    $ ng generate webWorker my-worker
  • Replace /deep/ with ::ng-deep in your styles, both are deprecated but using ::ng-deep is preferred until the shadow-piercing descendant combinator is removed from browsers and tools completely.
  • Angular now uses TypeScript 3.4, to update run:
    $ npm update -g typescript
  • Make sure you are using Node 10 or later.
  • If you use ViewChild or ContentChild, you must now specify that change detection should run before results are set (check Breaking change in ViewChild and ContentChild chapter above).
  • If you use Angular Material, update it to version 8 by running in your terminal::
    $ ng update @angular/material

If you're trying to upgrade from a different version than Angular version 7 you can use the official Angular upgrade guide for instructions on how to proceed.

Conclusion

Not counting the Ivy, additions to Angular version 8 aren’t large and they aren’t critical for the most of Angular applications. Having in mind that there aren’t any large breaking changes, you should update your application and in most cases it will run without any changes. With the addition to enable differential loading, you’ll get noticeable performance gains. More importantly, upgrading to Angular 8 will ensure that your application is ready for full featured Ivy. Even though Ivy is currently only an opt-in preview in Angular version 8, this is a good time to start checking for Ivy compatibility and make changes (if needed) before Ivy in Angular 9 or 10 becomes default and the current Angular View Engine is deprecated.

If you have any further questions or comments, please contact us.