Angular 10 Deep Dive
Babloo Kumar
Posted on July 25, 2020
Angular 10, the latest major version of angular has just been released. It's time to discover what's new available for us to explore and enhance the experience.
What’s in this release?
In this article, I'll touch up almost everything noteworthy in this new release. I'll also go through what's changed around the angular as a platform, including Framework, Angular Material and the CLI.
I'll try here to dig deeper into the release notes for Angular 10.0.
Angular 10 is already here, just four months after version 9. Of course during this short time period, there’s not that much that has changed. Still, there are quite a few noteworthy features, in addition to the large number of bug fixes brought by this release.As a reminder, the Angular team tries to release two major versions per year, so Angular 11 should arrive this fall.
Support for TypeScript 3.9.x
Keeping upto date with the JavaScript Ecosystem we have made a few updates to the dependencies of Angular to stay synchronized with the JavaScript ecosystem.
So the very first thing that makes me happy about this release of Angular is the fact that it supports TypeScript 3.9.
Angular 10 has dropped support for TS 3.6, 3.7 and 3.8! I hope this should not be the major hold back for you.
Thanks to its support for TS 3.9.x and other improvements in the compiler CLI, type-checking is faster than ever in Angular 10, which should be positive for most projects out there; especially larger ones.
TSLib 2.0
Additionally, Angular 10 also upgraded to TSLib 2.0. For those who don’t know, TSLib is an official library providing TypeScript helper functions that can be used at runtime. TSLib works in combination with the importHelpers flag of “tsconfig.json”; when enabled, it allows the compiler to generate more condensed/readable code. Anyways, nothing to worry about; TSLib hasn’t changed much.
Starting with version 10 you will see a new tsconfig.base.json. This additional tsconfig.json file better supports the way that IDEs and build tooling resolve type and package configurations.
TSLint v6
TSLint has been updated to v6.
Stricter settings [optional]
Angular 10 brings the possibility to create stricter projects right at creation time, which is great and should certainly be used for all new projects. To create a project with stricter defaults, use:
ng new --strict
This will allow you to detect issues much sooner at the build time itself, lot of time & effort can be saved.
This new option enables TypeScript strict mode (which you should all enable on your projects!).
Next to that, it also enables strict Angular template type checking.
It also lowers the budgets in “angular.json” quite drastically:
See the pic.
This is good as it will encourage new users to pay attention to the bundle size of their applications. Default bundle budgets have been reduced by ~75%.
It Configures your app as side-effect free to enable more advanced tree-shaking.
It also enforces a stricter TSLint configuration which bans “any” (“no-any” is set to true), and also enables quite a few interesting rules provided by codelyzer. Note that even though strict, you can still go much further with TSLint. For instance, here’s the config of one of my projects, which you can use as starting point.
I feel that this new "strict" option is amazing, but sadly its an optional flag. For making it optional i imagine that the rationale is that by being more lenient by default, Angular feels less scary at first?
Anyways, if you do create a new project, please enable this and go even further; you’ll thank me later.
Configuration Layout
This is new TypeScript configuration layout. With this new release, the TypeScript configuration provided by default in new projects has changed. There’s now a “tsconfig.base.json” file in addition to “tsconfig.json”, “tsconfig.app.json” and “tsconfig.spec.json”.
We have included all these configuration files to better support the way IDEs and build tools look up the types and compiler configuration. If you would have worked on Visual Studio Professional for developing any tool/app you can understand easily.
With the new setup, “tsconfig.json” simply contains TypeScript project references based on the so-called “solution style” brought by TypeScript 3.9, which is great to improve compilation times and enforce a stricter separation between parts of the project:
In this case, the separation is there to have clean isolation of application code (taken care of by “tsconfig.app.json”) from tests (handled by “tsconfig.spec.json”).
If you look at the “tsconfig.base.json” file, then you’ll find the bulk of the TypeScript configuration:
Note that this one was generated using the strict option discussed in the previous section.
As you can see above, this file only configures TypeScript compiler and Angular compiler options; it doesn’t list/include/exclude files to compile.
The answer is indeed in the “tsconfig.app.json” file, which lists the “main.ts” and “polyfills.ts”:
If you have an existing project without this layout, then you should probably review your TypeScript configuration in order to stay aligned and benefit.
Now Let's move to new item for discussion.
NGCC
In case you haven’t done this yet (this was already true with NG9), make sure that you have a postinstall script in your “package.json” file to execute NGCC right after an installation:
Note that in this release, NGCC is more resilient. Previously, it couldn’t always recover when one of its worker processes crashed. So if you sometimes saw issues with NGCC hanging, this should now be fixed.
There were also quite a lot of improvements made to NGCC, including performance-related ones, which is clearly every ones biggest pain point around NGCC.
New Default Browser Configuration
The browser configuration for new projects to exclude older and less used browsers.
Web browsers move faster than ever. Angular follows course and now uses an updated browserslist file (.browserslistrc).
As explained in the official blog post, the side effect of the new configuration is that ES5 builds are disabled by default for new projects.
Of course, at this point it doesn’t make much sense anymore to generate ES5 code. Modern Web browsers support at the very least ES2015. If you still use Internet Explorer or UC Browser, then it’s clearly time to let go of the past!
To get the exact list of supported Web browsers, just execute the following command in your project:
npx browserslist
The output is generated based on the contents of the “.browserslistrc” file at the root; by default it now looks as follows (V10 Defaults):
Bazel
Angular Bazel has left Angular Labs now. Support for Bazel is not part of the Angular project anymore. Bazel will never be the default build tool in Angular CLI after all.
@angular-devkit/build-angular 0.1000.0)
The name and version nomenclature hides important piece of information around it (the way Angular Apps are built).
The new version has bought lot of good features, all are covered below -
The coolest one (if you’re using SASS that is) is the fact that build-angular will now rebase relative paths to assets.
As stated in the commit, previously, paths like url(./foo.png) referenced in stylesheets and imported in other stylesheets would retain the exact URL. This was problematic since it broke as soon as the importing stylesheet was not in the same folder. Now, all resources using relative paths will be found.
Another hidden gem in that release is the fact that build-angular now dedupes duplicate modules that Webpack can’t handle. This is done through a custom Webpack resolve plugin.
Few more are listed below
Incremental template type checking
In this release, the compiler CLI is now able to perform template type checking incrementally. Hopefully this will save quite a few trees.
CanLoad
Previously, CanLoad guards could only return booleans. Now, it’s possible to return a UrlTree. This matches the behavior of CanActivate guards.
Note that this doesn’t affect preloading.
Service Workers
The default SwRegistrationStrategy has been improved. Previously, there were cases where the Service Worker never registered (e.g., when there were long-running tasks like intervals and recurring timeouts).
Internalization & Localization (I18N/L10N)
Previously, only one translation file was supported per locale. Now, it is possible to specify multiple files for each locale. All of those then get merged by message id. If you are using you would have got my point.
Angular Material
Lot of important fixes has been done for the Angular material. For the detailed list please see the release notes
Some of the new stuffs included -
Angular Material now includes a new date range picker. To use the new date range picker, you can use the mat-date-range-input and mat-date-range-picker components.
Angular Team Fixit (Bug fixes galore)
As mentioned a few weeks back, the Angular team has invested a lot of time and effort in bug fixing and backlog grooming. They’ve decreased their issue count by > 700 issues inlcuding framework, tooling & components, which is quite impressive.
One of fact that enabling strict template type checking caused issues with routerLinks because their underlying type didn’t include null/undefined. Another one that was fixed is the KeyValuePipe, which didn’t play along well with the async pipe.
While we’re on templates, note that the language service of Angular now supports more array-like objects such as ReadonlyArray and readonly property arrays for *ngFor loops.
Deprecations and removals
The Angular Package Format no longer includes ESM5 or FESM5 bundles, saving you 119MB of download and install time when running yarn or npm install for Angular packages and libraries. These formats are no longer needed as any down leveling to support ES5 is done at the end of the build process.
Based on feedback from the community, we have deprecating support for older browsers including IE 9, 10, and Internet Explorer Mobile.
There are quite a few deprecated elements such as ReflectiveInjector, CollectionChangeRecord, DefaultIterableDiffer, ReflectiveKey, RenderComponentType, ViewEncapsulation.Native, ngModelwith Reactive Forms, preserveQueryParams, @angular/upgrade, defineInjectable, entryComponents, TestBed.get, etc.
Classes using Angular features without an Angular decorator are not supported anymore
Up to version 9, it was okay to have a class using Angular features without specifying one of the decorators (@Component, @Directive, etc).
With Angular 10, it is now mandatory to add an Angular decorator if a class uses Angular features. This change impacts all cases where you have components extending from a base class and one of the two (i.e., parent or child) is missing an Angular decorator.
Why is this change mandatory? Simply put, because Ivy needs it!
When there’s no Angular decorator on a class, the Angular compiler doesn’t add extra code for dependency injection.
As stated in the official doc, when the decorator is missing from the parent class, the subclass will inherit a constructor from a class for which the compiler did not generate special constructor info (because it was not decorated as a directive). When Angular then tries to create the subclass, it doesn’t have the correct info to create it.
In View Engine, the compiler has global knowledge, so it can look up the missing data. However, the Ivy compiler only processes each directive in isolation. This means that compilation can be faster, but the compiler can’t automatically infer the same information as before. Adding the @Directive() explicitly provides this information.
When the child class is missing the decorator, the child class inherits from the parent class yet has no decorators of its own. Without a decorator, the compiler has no way of knowing that the class is a @Directive or @Component, so it doesn't generate the proper instructions for the directive.
The nice thing about this change is that it brings more consistency into the Angular world (and consistency is good :p). Now things are simple: if you use Angular features, then you must add a decorator.
To give you an example, the following code won’t compile with Ivy:
Before:
@Component({
selector: 'base-menu',
template: '
})
class BaseMenu {}
export class SettingsMenu extends BaseMenu {}
After: (this will be valid code for compilation)
@Component({
selector: 'base-menu',
template: '
})
class BaseMenu {}
@Component({
selector: 'base-menu',
template: '
})
export class SettingsMenu extends BaseMenu {}
To fix the issue, you need to add a decorator to the SettingsMenu class.
-
This schematic also decorates classes that use Angular field decorators, including:
- @Input()
- @Output()
- @HostBinding()
- @HostListener()
- @ViewChild() / @ViewChildren()
- @ContentChild() / @ContentChildren()
Before:
class Base {
@Output()
countChanged = new EventEmitter();
}
@Directive({
selector: '[myDir]'
})
class Dir extends Base {
}
After:
@Directive() // schematic adds @Directive()
class Base {
@Output()
countChanged = new EventEmitter();
}
@Directive({
selector: '[myDir]'
})
class Dir extends Base {
}
Mandatory generic type for ModuleWithProviders
In previous releases, ModuleWithProviders already accepted a generic type, but it was not mandatory. With NG 10, the generic argument is required.
It’s a good thing for type safety anyways, so hopefully you already had the parameter defined:
If you stumble upon the following error because of a library that you’re using:
"error TS2314: Generic type 'ModuleWithProviders' requires 1 type argument(s)."
Then you should contact the library author to get it fixed as ngcc can’t help there. A workaround there is to set skipLibChecks to false.
Other breaking changes
Here are notable breaking changes:
Resolvers behave differently; those that return EMPTY will now cancel navigation. If you want to allow navigation to continue, then you need to make sure that your resolvers emit a value; for instance using defaultIfEmpty(...), of(...) and the like.
Service worker implementations that rely on resources with Vary headers will not work like they did previously. Vary headers will be ignored. The proposed “solution” is to avoid caching such resources as they tend to cause unpredictable behavior depending on the user agents. Because of this, resources may be retrieved even when their headers are different. Note that cache match options may now be configured in NGSW’s config file.
Property bindings such as [foo]=(bar$ | async).fubar will not trigger change detection if the fubar value is the same as the previous one. The workaround if you rely on the previous behavior is to manually subscribe / force change detection or adapt the binding in order to make sure that the reference does change.
The following format codes of formatDate() and DatePipe have changed; apparently the previous behavior was incorrect for day periods that crossed midnight.
The function that stands behind the UrlMatcher utility type (function alias) now correctly states that its return type may be null. If you have a custom Router or Recognizer class, then you need to adapt those.
Additional occurrences of ExpressionChangedAfterItHasBeenChecked can now be raised by Angular for errors that it didn’t detect before.
Angular now logs at error level when it notices unknown elements / property bindings in your templates. These were previously warnings.
Reactive forms’s valueChangeshad a bug with FormControls that were bound to inputs of type number (they fired twice since 2016! A first time after typing in the input field and a second time when the input field lost focus). Now, number inputs don’t listen to the change event anymore, but to the input event. Don’t forget to adapt your tests accordingly. Note that this breaks IE9 compatibility, but that’s not a problem for anyone.
The minLength and maxLength validators now make sure that the associated form controls values have a numeric length property. If that’s not the case, then these won’t be validated. Previously, falsy values without a length property (e.g., false or 0) were triggering validation errors. If you rely on that behavior, then you should add other validators like min or requiredTrue.
Upgrading
As usual, there’s a complete upgrade guide available and ng update will help you out: https://update.angular.io/#9.0:10.0l3
If you do the upgrade manually and still use Protractor (just in case), then don’t forget to update protractor to 7.0.0+ as previous versions had a vulnerability.
Conclusion
In this article, I’ve tried to explore the new features of Angular 10, as well as the deprecations, removals and breaking changes.
All in all, it’s clearly a rock solid one with tons of bug fixes and a few gems.
As usual, we can only be thankful for all the efforts made by the Angular team and the community that surrounds it!
Posted on July 25, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.