Here comes angular 8, it includes a preview of Ivy, support for service workers, differential loading, and several other finishing touches.
Manfred Steyer explains the most important changes in the newest release.
As planned, there were no surprises: the framework and CLI can be updated using ng update, and new functions are a nice addition in accordance with the motto “evolution instead of revolution”.
In this article, the author talks about the most important new features of Angular 8 and Angular CLI 8. Examples used in this article can be found on
GitHub .
')
Under the cut:
- First look at ivy
- Web workers
- Differential load
- Lazy loading of modules
- Breaking Changes in ViewChild and ContentChild
- New features ngUpgrade
First look at ivy
The next big news that the Angular community is waiting for is Ivy, a new compiler, as well as a new rendering engine. Ivy can generate much smaller bundles, incremental compilations, and is also the basis for future innovations in Angular.
Since many of the basic parts of Angular have been changed, the Angular team has paid particular attention to compatibility with previous versions: after switching to Ivy, existing applications should work the same way as before. At best, you will get significantly smaller bandages. This is not disinterested, as more than 600 applications on Google are officially based on Angular - the real number is rumored to be much higher.
With Angular 8, a preliminary version of Ivy is available for testing. The goal of this version is to get fast feedback. Therefore, the angular team recommends that you do not use Ivy right now, but continue using the classic view engine (Fig. 1).

Thanks to the differential download (as seen below), the size of the bundle can be optimized right now.
As Brad Green, technical director of Angular team at Google, at ngconf 2019, Ivy will significantly improve the size of packages in compatibility mode in combination with differential loading. Thus, daredevils can already test the future API Ivy. This mode, in particular, has great potential for optimization. The API is still marked private. Looking at its classes and functions, you can say: they begin with a special symbol.
If you already want to try Ivy, you can create a new project with the enable-ivy key:
ng new ivy-project --enable-ivy
This key tells the CLI to save the following entry in the tsconfig.app.json configuration:
"angularCompilerOptions": { "enableIvy": true }
This entry can also be added manually after upgrading to version 8 to test an existing application using Ivy.
To run the application in debug mode, it is recommended to use AOT:
ng serve --aot
In addition, you should pay attention to the size of the application created using ng build. With angular 9, Ivy should be activated by default. Until then, the Angular team plans to continue working to ensure compatibility with older versions.
Web workers
JavaScript is single-threaded by definition. Because of this, time-consuming tasks, such as querying data, are usually performed asynchronously. Needless to say, this does not help in complex calculations. They are especially becoming more common with extensive JavaScript solutions, so we support almost all web browsers for web workers. These are scripts that are launched by the browser in a separate thread. Communication with the stream on the browser tab is done via messages.
Although web workers have no relation to Angular per se, they should be taken into account when building. The goal is to provide one package for each web worker. This task is performed by the new CLI.
To demonstrate the new feature, I’ll show a JavaScript implementation of the so-called “N
queens problem ”
problem . ”The idea is to place one queen in a row on a chessboard without being able to threaten each other. This means that there must not be another queen in the same row, column, or diagonal.

The algorithm for calculating all possible solutions on a chessboard is considered computationally complex. Although the calculations for an ordinary eight-row and eight-column chessboard are quite fast, conventional computers have reached the limit, with a board size of 12 x 12. The board solution of 27 x 27 is a current record. For this task, Russian supercomputers were used.
To translate this calculation into a background, we must first create a web worker using the CLI:
ng generate worker n-queens
This instruction creates a file not only for the worker, but also for the configuration files needed for the build process and the entries in the existing files. If the same folder contains a component with the same name with a common file extension .component.ts, CLI will also add code to interact with the web worker.
The worker itself consists of a listener for the event:
import nQueens from './n-queens'; addEventListener('message', ({ data }) => { const result = nQueens(data.count); postMessage(result, undefined); });
The event is executed when the main thread sends a message to the worker. The parameter contains information sent from the main stream. In this case, it is limited to the count property, which sets the size of the chessboard. After calculating the function nQueens, which is omitted here, the eventListener sends the result back to the main thread via postMessage. Thus, the browser starts the message event.
The Worker class is used in the component that is used to interact with the worker script:
const count = parseInt(this.count, 10); const worker = new Worker('../logic/n-queens.worker', { type: 'module'
The component sends the message with the desired size of the chessboard to the worker via postMessage and thereby starts the calculation there. It receives the result through the message event.
In the future, the CLI takes care of the correct assembly of worker scripts. The TypeScript compiler recognizes them at the end of .worker.ts, which is registered in tsconfig.worker.json created by the
ng generate worker . To ensure that the CLI does not affect these files again when building the main application, the
ng generate worker places the same file template in the exclude tsconfig.app.json section.
Full implementation is in the project with examples of the author. For comparison, the example of the N queens task can be solved both in the main thread and in the web worker. When you try to solve a task for a 12 x 12 chessboard, for example, you will see that the UI hangs up in the first case, while the background calculation using a web worker does not reduce performance.
Differential load
Until now, it was decided to compile applications into the good old ES 5, since this version of our father’s “JavaScript” works almost everywhere. This means that both IE11 and the Google web search engine can execute this code.
However, the new ES 2015 and its later versions are more efficient: they allow you to create more compact packages and the browser can also interpret them more efficiently. Since it was previously decided to roll back to ES 5 as the lowest common denominator, modern browsers, unfortunately, could not take advantage of the new version of the language.
Now it's over: starting with version 8, the CLI has a function called differential boot. The idea is to provide two groups of packages: one based on ECMAScript 5 and designed for older browsers, the other based on a new version of ECMAScript, such as ECMAScript 2015, and provides previously mentioned advantages to modern browsers.
You do not need much work to enable differential loading: all you need is to set the upper and lower limits of supported versions of ECMAScript. The upper bound is specified in tsconfig.json as follows:
"target": "es2015"
The lower limit is defined in the browserslist file. This file includes browsers that will be supported according to certain criteria, such as market share, for example. They can be saved, for example, in a browserslist file, which the CLI creates in the project root when creating a new project:
> 0.5%
last 2 versions
Firefox ESR
not dead
IE 9-11
In this case, the browser list includes ES 5 browsers with IE 9-11. Thus, the CLI defines a lower threshold as this version. When the CLI receives the ng build command, the build process will be executed for both versions:

The disadvantage of this process is as follows: the time required for assembly is doubled.
Now browsers can decide which version of the packages to download. To do this, they receive references to scripts in the index.html add-on: those who point to ECMAScript 5 packages receive the addition of a nomodule. Thus, browsers with support for ECMAScript modules and, therefore, support for ECMAScript 2015+ will not ignore this script. On the other hand, ECMAScript 2015+ packages are implemented by CLI with type = ”module”. Thus, older browsers will ignore these scripts:
<script src="main-es2015.js" type="module"></script> <script src="main-es5.js" nomodule></script>
Unlike ng build, the rest of the CLI commands use only (!) The upper limit of ES support. In our case, this is ECMAScript 2015. This happens, for example, for reasons of efficiency: during debugging and testing, developers usually want to see the result as soon as possible, without waiting for the second build.
Lazy loading of modules
From the first days Angular router supports lazy loading. So far this has been achieved by the magic definition of a loadable module:
{ path: 'lazy', loadChildren: () => './lazy/lazy.module#LayzModule' }
The value before the # describes the path leading to the file with the implementation of the module; the value after means the class it contains. This description style works in Angular 8, but has been deprecated with respect to dynamic ECMAScript imports:
{ path: 'lazy', loadChildren: () => import('./lazy/lazy.module').then(m => m.LazyModule) }
The new entry option still contains the file name as a magic value. However, since the import is supported by many IDEs, invalid values ​​will immediately return an error.
Breaking Changes in ViewChild and ContentChild
There are critical changes in the use of ViewChild and ContentChild, which, unfortunately, have not always worked predictably in the past. If in earlier versions they were used by the component to query elements that are not inside a structural directive, such as ngIf or ngFor, the result of the query was already available in ngOnInit. Otherwise, we could access them no earlier than ngAfterViewInit (or ngAfterContentInit for ContentChild). For items that were loaded into the DOM later because of data binding, the program code should have ngAfterViewChecked or, respectively, ngAfterContentChecked.
Since this behavior was confusing, the component should now indicate when the resolution should occur:
@ViewChild('info', { static: false }) paragraph: ElementRef;
If the static flag is true, Angular will try to find the elements when the component is initialized. This only works if they are not in a structural directive. When using static: false permission is performed after initializing or updating the view.
ng update will try to automatically enter the correct value, if this proves impossible, it will add a comment with TODO.
This change will not affect queries with the ViewChildren and ContentChildren decorators. They always had dynamic behavior, in new terms - in the sense of static: false.
New features ngUpgrade
Until now, one of the problems of the mixed work of AngularJS 1.X and Angular with ngUpgrade was that the routers of both frameworks competed for the URL. This led to difficult to explain side effects. To avoid this, the ability to use a single URL access location service in both versions was added.
To do this, the Angular team has expanded the capabilities of the Angular location services and thus provided a replacement for $ location in AngularJS.
For this reason, a new onUrlChange method has been added to the location service to track changes to URLs:
export class AppComponent { constructor(loc: Location, pLoc: PlatformLocation) { loc.onUrlChange((url) => console.debug('url change', url)); console.debug('hostname: ', pLoc.hostname); } }
PlatformLocation offers additional access to specific parts of the URL. A detailed description of how the $ location replacement based on it is used for better integration of frameworks can be found
here . In addition, you can now find a solution for lazy loading AngularJS, which is based on the aforementioned dynamic ECMAScript import.
Conclusion
Again, the Angular team kept their word: the transition to the new version of Angular is simple and does not include major changes. On the contrary, some corners were smoothed out, making work with the Google spa framework from Google even more comfortable. Differential download provides opportunities for further optimization of package sizes if older browsers are either not supported or supported by separate packages. Web worker support shows that computationally intensive tasks find their way to processing in the browser. Enthusiasts can now take their first steps with Ivy.
PS: This is my first translation, so please note the comments, suggestions and errors in the comments.