Angular 9, released in February 2020, brought the development community lots of long-awaited features: the default Ivy compiler, bundle and build optimizations, improved bug checking during the build, and more. The Angular development team claims the improvements in this version greatly reduce app bundle sizes and build times.
In this article, we go over the key features of Angular 9 and 9.1 and test their performance on a real-world project. We also evaluate the updates brought by Angular 10.
This Angular 9 overview will be useful for developers looking to assess the latest features and performance improvements in Angular.
Contents:
Angular is a web development platform created by Google. Convenient functionality, an a robust command-line interface (CLI), support for various development tools, and frequent releases make this platform one of the most popular choices for building web applications. According to GitHub and Stack Overflow, Angular is the third most popular web development framework after React and ASP.NET MVC.
Angular 9 is one of the biggest updates to Angular in the last three years. Letโs see whatโs new in the Angular 9 release.
Angular 9: Key improvements
The default Ivy compiler and runtime improvements are the most important changes in Angular 9. In previous versions, developers had to use the View Engine compiler that had a long build time and produced large bundles compared to the new compiler.
Nowadays, lots of users surf the web via smartphones, accessing vast amounts of data: high-resolution videos, streaming music, datasets, etc. Web apps need to deliver the best user experience even under the worst conditions. But heavy loads reduce web application performance. Thatโs why developers tend to choose frameworks that load applications and evaluate scripts fast.
The new Ivy compiler allows developers to speed up development and make it more efficient. Ivy helps developers rework the internal application structure with a focus on two things: day-to-day developer needs and bundle optimizations for the final production application. The new compiler is also supposed to significantly speed up the build process and reduce bundle sizes.
Letโs take a close look at each improvement and find out how it facilitates development.
Bundle optimizations
Application performance and bundle size used to be weak spots of Angular. In version 9, theyโre finally resolved. Thanks to tree shaking and reworked dependency management in the underlying architecture of the framework, you can see major performance and bundle size improvements in both small and large applications.
Tree shaking excludes large parts of unused framework code from the application bundle, helping to reduce the final size of the bundle up to 30%. This mechanism is especially effective for small applications. These apps donโt really use the majority of Angular features, so a large part of the bundle was often so-called โdead code.โ
Another useful feature of Angular 9 is the optimization of component factories. The impact of this optimization directly depends on the number of components, making it especially significant for large applications with lots of them. The Angular development team claims a bundle size reduction for large applications of up to 40%.
Build optimizations
Previous Ivy versions added almost 80% overhead compared to pure TypeScript compilation. In Angular 9, this overhead is reduced to ~50%, allowing you to build applications much faster.
The importance of this improvement is hard to overestimate. Angular applications consist mostly of code components and templates that canโt be understood by browsers directly. Thatโs why Angular needs to compile them into efficient JavaScript code that can be executed in the browser. With the reduced overhead, this compilation takes much less time than it used to.
Another positive side effect of Ivy refactoring is ahead-of-time (AOT) compilation optimization. The Angular AOT compiler converts written code into JavaScript before the browser executes it. But due to the high cost of compilation, using AOT wasnโt an option for build development. That only became possible after Ivy refactoring.
Development improvements
Optimization and performance improvements aside, Ivy also changes the way developers work with debugging, testing, and build errors. In Angular 9, the compiler checks more error types and applies stricter checking rules than it did in the frameworkโs previous versions. So finding bugs no longer requires a lot of effort from developers.
Improved bug detection also helps to reduce the cost of fixing bugs and, ultimately, the project budget. Since the build is one of the earliest stages of application development, detecting and resolving an issue at this stage has a lesser influence on the project than fixing the same issue later.
The Angular 9 compiler supports two additional flags to check templates:
fullTemplateTypeCheck
โ tells the compiler to check ngIf, ngFor, ng-template, and other templatesstrictTemplates
โ activates the strictest type checks for templates
By using these flags, you can detect more errors in the console. Angular 9 provides you with a clear description of each detected error and its causes. Ivy also improves the stack trace of internal errors, allowing you to jump directly to the parts of your code related to a specific error.
Debugging in Angular 9 has become simpler too: now developers have an additional injected ng
global object variable. It can be used to get full control of the application in runtime to:
- access your components and directive instances
- trigger change detection
- directly call certain methods
Built-in testability and dependency injection always were features that attracted developers to Angular. But even though testing is one of the built-in concepts, test execution time was always something to complain about, especially in large applications.
The revamped implementation of the TestBed API doesnโt recompile components between tests unless a component has been manually overridden. This change significantly shortens the duration of test execution: acceptance tests are 40% to 50% faster.
Another testing improvement in Angular 9 is the test component harness โ a class that allows tests to interact with components via a supported API. Now you can significantly simplify user interface tests of material components or implement your own harnesses using a component development kit.
Without using component harnesses, tests used to look like this:
it("should show feedback form template", async () => {
expect(fixture.debugElement.query("feedback-form")).toBeNull();
const matSelectTrigger = fixture.debugElement.query(By.css(".mat-select-trigger"));
selectTrigger.triggerEventHandler("click", {});
fixture.detectChanges();
await fixture.whenStable();
document
.querySelectorAll(
".mat-select-panel mat-option"
)[FEEDBACK_FORM_OPTION_INDEX].click();
fixture.detectChanges();
await fixture.whenStable();
expect(fixture.debugElement.query("feedback-form")).not.toBeNull();
});
In Angular 9, the same test requires much less code:
it("should show feedback form template", async () => {
expect(fixture.debugElement.query("feedback-form")).toBeNull();
const select = await loader.getHarness(MatSelect);
await select.clickOptions({ text: "Give feedback" });
expect(fixture.debugElement.query("feedback-form")).not.toBeNull();
});
As you can see, improving the default compiler made this platform much more comfortable to work with and made the compilation process much more efficient. However, Angular 9 improvements arenโt limited to the Ivy compiler and the performance optimizations it provides. Letโs look at some new components that make developersโ lives easier.
Support for TypeScript 3.7
The ninth version of Angular supports TypeScript 3.7. The key feature of TypeScript 3.7 is optional chaining, which helps TypeScript stop expressions that run into null
or undefined
. As a result, you donโt need to write safety code like this:
if (obj && obj.base && obj.base.element && obj.base.element.value) {
return obj.base.element.value;
}
return 0;
With optional chaining, the same code looks like this:
return obj?.base?.element?.value || 0;
Adding nullish coalescing gives us a safer option for the same expression:
return obj?.base?.element?.value ?? 0;
You can check out all the improvements in TypeScript 3.7 in the official documentation. Note that TypeScript 3.7 doesnโt list uncalled function checks, which have a significant impact on coding. Functions are always defined and shouldnโt be checked as conditions, and uncalled function checks notifies a developer if thereโs a typo in conditional operators that will make a function uncallable.
Further improvements in Angular 9.1
Shortly after the version 9 release, the Angular development team rolled out Angular 9.1 โ a minor release containing improvements to the framework and the CLI as well as bug fixes. In particular, version 9.1 introduced an upgraded ngcc compiler, new CLI component generator options, and performance and stability improvements. Angular 9.1 also updates Typescript to version 3.8, which, in fact, doesnโt bring any major changes compared to version 3.7.
Whatโs new in Angular 10?
Four months after the Angular 9 release, the Angular team released version 10 of the framework. This update isnโt as large and significant as version 9, but itโs still worth a look.
The most important change in this update is the --strict
option in the CLI. It allows you to enable strict linting rules for an Angular application on bootstrap. Strict linting is aimed at simplifying development by eliminating warning signs during compilation. You can turn on strict linting with this command:
ng new --strict
This option does the following:
- Enables strict mode in TypeScript
- Turns template type checking to
Strict
- Configures linting rules to prevent declarations of type
any
- Turns on features that enable more build and bundle size optimizations
The next important change is that Angular 10 doesnโt support old browser versions by default. The side effect of this decision is disabling the ES5 bundle build by default for new projects. This bundle used to significantly increase the overall application bundle size. Yet you still can add support for old versions of browsers you need by editing the .browserlslitrc file.
As always, the Angular development team is keeping its framework up to date with the JavaScript ecosystem. Angular 10 supports TypeScript 3.9, tslib 2, and tslint 6.
Also, to improve build optimization, Angular 10 makes changes in many outdated features:
ContentChildren
queries search only direct child nodes by default- Undecorated classes are no longer included in the Angular dependency injection system
- Unbound inputs are now set upon creation of the view
- In case of conflicts, static attributes from the HTML template override host attributes set by directives or components (previously, static host attributes overrode static template attributes)
You can check out the full list of deprecations to find out about other features.
During 2020, the Angular development team augmented their framework with many features designed to speed up development and make web apps lighter. But do they really speed up the development of real-world projects? Letโs compare the performance of Angular 9.1 and previous versions of the framework to find out.
Testing the speed and output of Angular 9.1
Since Angular 10 doesnโt bring any major optimizations or upgrades to the framework, weโll focus on testing the new features in Angular 9.1 in the real world. For this experiment, weโll use the Tour of heroes application thatโs familiar to lots of developers who have learned Angular. We used the Tour of heroes repository as a starting point since itโs written in Angular 8.2. Then we built this project with three different versions of Angular and received the following results:
Angular version | Build duration | Overall output size |
7.2 | 36s | 444,121 B |
8.2 | 33s | 543,337 B |
9.1 | 34s | 564,653 B |
As you can see, builds in 8.2 and 9.1 became faster, but not significantly. Thatโs why for continuous integration and continuous delivery (CI/CD) pipelines, where the build is executed mostly in Docker from scratch, the new version of Angular doesnโt seem to give an advantage.
In our experiment, we also didnโt achieve any size reductions. As we mentioned before, bundle optimization should be most noticeable in large projects, with less of an effect on small and medium-sized applications.
On the bright side, another important takeaway of this test is that we didnโt experience any issues with upgrading Angular dependencies to the newest versions. You can find all the instructions you need for upgrading dependencies in the update guide provided by the Angular team.
The smooth update experience provided with ng CLI simplifies updates significantly, whether you need to move to Angular 9.1 or 10. Note that version 10 also includes a list of not-so-obvious breaking changes that may cause issues on big projects. We highly recommend getting familiar with these changes before considering updating to the tenth version of the framework. Or you can check out the newly-released Angular 11.
Conclusion
During our experiments, we didnโt experience any of the advertised optimizations and performance improvements in Angular versions 9 and 10. However, these versions of the framework provide lots of benefits and useful tools:
- AOT is now finally available for build development
- The TestBed API speeds up your tests by avoiding recompilation between executions
- Implementing tests is simpler thanks to component harnesses
- TypeScript updates allow you to use new TypeScript features
If youโre looking for a development team with expert knowledge of many web app development frameworks including Angular, feel free to contact us!