Angular 13 in Depth
Everything you need to know about Angular 13
Angular 13 is now available. Time to discover what's new!
In this article, I’ll go over (almost) everything noteworthy in this new release. I’ll also highlight what’s changed around Angular, as I did with my previous articles about Angular 12, Angular 11, and Angular 10.
What's new with Angular 13
If you're looking for the bird-eye view, then here it is:
- IE11 is no longer supported
- Faster production builds (+68%)
- Persistent build cache by default: https://github.com/angular/angular-cli/issues/21545
- View Engine is gone
- New Angular Package Format (APF): https://angular.io/apf
- Simplified API to dynamically create components
- Minor improvements to forms type safety
- Improvements to Angular TestBed
- Accessibility (a11y) improvements to MDC-based Angular Material components
- TypeScript >=4.4.x
- RxJS >=7.4
If you want more, then check out the official release announcement.
And if you want all the details, then stay here with me! We're going to dig much deeper into the release notes ✨.
IE11 is no longer supported
Angular 13 no longer supports Internet Explorer. I consider this to be one of the most important news.
By dropping support for Internet Explorer, Angular can finally make use of native Web browser features such as CSS variables and Web animations. Previously, Angular had to include polyfills to ensure retro-compatibility with IE.
This means that Angular is now lighter than before, and will load/execute faster (i.e., better UX!). Moreover, the Angular team can now focus on evergreen Web browsers, which will enable faster innovation cycles.
It also renders differential loading bogus. Previously, Angular used that technique to generate specific JavaScript bundles for legacy browsers, which slowed everything down and increased the size of production builds.
The update process of angular automatically drops the old IE polyfills and reduces bundle size during migration.
Note that Angular 12 will continue to support IE11 until November 2022.
If you're working for a company that still uses Internet Explorer, the message is clear: it's time to stop that nonsense!
View Engine is not supported anymore
The View Engine is not supported by Angular 13.
This is a great step forward for Angular. Again, it means that the Angular team will be able to focus more on the forward-looking evolutions of the framework.
As mentioned in the official announcement, removing View Engine also means that Angular can reduce its reliance on ngcc
(Angular compatibility compiler) in the future, and teams can look forward to faster compilation because metadata and summary files are no longer included.
Changes to the Angular Package Format (APF)
As mentioned in the official announcement, the Angular Package Format (APF) has been streamlined and modernized to better serve developers. To streamline the APF in Angular 13, older output formats such as CommonJS (CJS) and UMD have been removed. As mentioned by Igor Minar, the whole Web community will be better off once ES Modules (ESM) are used everywhere.
The APF now uses more modern JS formats: ES Modules and ES2020. This means that libraries built with the latest version of the APF will no longer need to use ngcc
. ngcc
is painful for all Angular developers, as I've mentioned previously. Thanks to this change, the first build after an installation will be much faster. Awesome! 🚀
The Angular team has also updated the APF to support Node Package Exports. This will help developers from inadvertently relying on internal APIs that may change.
It is now time for Angular library authors to stop using enableIvy: false
, and to instead use compilationMode: partial
(in tsconfig.prod.json
), as recommended by Younes. The partial
compilation mode is a partial-Ivy code format that is stable between different versions of Angular, and thus safe to publish to npm. Angular code that uses this partial format is processed during the build of the application using the same version of the Angular compiler. The benefit is that it both the application and its libraries rely on a single version of Angular, removing potential compatibility issues. Check out the official guidelines for library authors to learn more.
Hopefully, once enough library authors have started shipping their libraries with the new partially compiled format, ngcc
should finally go away.
Note that the Angular CLI now prefers the ESM version of dependencies (if it is available).
As a result of these changes, the production build of Angular applications now targets ES2020 instead of ES2015 as it was the case before.
Angular 13 now supports TypeScript 4.4
Angular 13 introduces support for TypeScript 4.4, which means that we can now use a ton of new wonderful language features. Also, support for TypeScript 4.2 and 4.3 has been dropped.
One notable improvement with TypeScript 4.4 that is particularly beneficial for Angular applications is the fact that it no longer enforces getters and setters to have the same type. Previously it was the case, and it was especially annoying for @Input
.
Check out the release notes of TypeScript 4.4 to discover the cool new features that you'll be able to use in your projects.
Better API to create components dynamically
Angular no longer requires component factories to dynamically create components.
Previously, we had to create a ComponentFactory
ourselves by invoking ComponentFactoryResolver
. This is not needed anymore. The ViewContainerRef.createComponent
now accepts a component instance of will take care of creating the factory transparently.
So, instead of this:
@Directive({ ... })
export class MyDirective {
constructor(
private viewContainerRef: ViewContainerRef,
private componentFactoryResolver: ComponentFactoryResolver
) {}
createMyComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(MyComponent);
this.viewContainerRef.createComponent(componentFactory);
}
}
We can now write this instead:
@Directive({ ... })
export class MyDirective {
constructor(private viewContainerRef: ViewContainerRef) {}
createMyComponent() {
this.viewContainerRef.createComponent(MyComponent);
}
}
Less boilerplate code is better, yay!
Angular CLI improvements
As you know, the Angular CLI is one of the key pieces of the Angular puzzle. Few developers in the world are able to deal with the build complexity of the modern Web development ecosystem. And luckily for us, the Angular CLI shields us from most of it.
With this release, Angular now uses the persistent build cache by default, as requested by the community. The persistent build cache is a feature that caches build results on disk (under the .angular/cache
folder). This results in up to 68% improvement in build speed.
In order to enable this feature in existing Angular applications, you need to add the following configuration to your angular.json
file:
{
"$schema": "...",
"cli": {
"cache": {
"enabled": true,
"path": ".cache",
"environment": "all" // other supported values: "ci" and "local"
}
}
...
}
You can also disable that feature (don't unless you really have no choice) using ng config cli.cache.enabled false
. If you need to clear the cache, then just remove the .angular/cache
folder.
You can find more information in the documentation.
Aside from that, ESBuild also sees some performance improvements in this release! The Angular team has introduced esbuild, which now works with terser to optimize global scripts. In addition, ESBuild supports CSS sourcemaps and can optimize global CSS, as well as optimizing all style sheets. I'm eager to see some benchmarks on this.
Interestingly, the Angular team is considering using tools like Vite in the future. It makes sense now that Angular supports ESM and is aligned with recent NodeJS versions. I'm curious to see what performance improvements and new features it will bring in the future.
RxJS 7.4 and NodeJS 16
Angular 13 now uses RxJS 7.4 by default for applications created using ng new
.
I wrote an article about RxJS 7 a while ago, but haven't updated it recently. Check out the following page if you want to discover what changed between RxJS 6 and 7.
Aside from that, Angular 13 has dropped support for NodeJS versions below v12.20.0
and has introduced support for NodeJS >=16.10.
Forms
Angular Forms have received a bit more attention in this release. Not yet as much as I would have hoped, but there are still notable improvements to the type safety of reactive forms. How cool is that?! 🚀. Let's explore the changes.
Improved type safety for form status
Form statuses now use a specific type. A new type called FormControlStatus
has been introduced, which is a union of all possible status strings for form controls: 'VALID' | 'INVALID' | 'PENDING' | 'DISABLED'
. That new type is used for AbstractControl.status
.
Also, statusChanges
has been narrowed from Observable<any>
to Observable<FormControlStatus>
. This is a breaking change, but it's really for the best. As mentioned in the release notes, it can break your application if you were using an invalid form status string (thus a bug fix!) or if you were using statusChanges
events as if they were something else than strings.
New form methods
New form methods have been added to AbstractControl
in this release:
addAsyncValidators
: Add one or more asynchronous validator(s) to the control, without affecting other validatorsaddValidators
: Add one or more synchronous validator(s) to the control, without affecting other validatorshasAsyncValidator
: Check whether an asynchronous validator function is present on this control (must be the exact same function that was provided)hasValidator
: Determines whether a validator or validators array has a given validatorremoveAsyncValidators
: Remove asynchronous validators from this controlremoveValidators
: Remove synchronous validators from this control
Those provide us with more control over the validation process. We can now easily add/remove synchronous and asynchronous validators.
Dynamically enable/disable validators
The minLength
and maxLength
validators can now be bound to null
. This allows to disable validation and preventing attributes from being added to the DOM. This fixes a regression that was introduced by those two validators. In addition, we can now disable those validators dynamically.
The ability to dynamically enable/disable validators is definitely going to be very useful for us all!
Templates
Angular now supports autocompletion for string literal union types.
The language service of Angular is now able to automatically insert the optional chaining operator (i.e., ?.
) when property access (i.e., .
) is done on a nullable symbol.
Here's an example:
Note that the fullTemplateTypeCheck
compiler option has been deprecated. You should now use strictTemplates
instead. Check out my article about Angular Template type Checking if you want to know more about that.
An older syntax for bindings has also been deprecated. I don't think that many Angular developers even knew about that, but if you are defining bindings using things like on-click
, then you should stop doing so.
Router
Observe router link active state
A new output called isActiveChange
has been added to the routerLinkActive
directive. It emits whenever the link becomes active or inactive.
Control the router behavior after navigation cancellation
A new option has been added to the public API of the Angular Router: canceledNavigationResolution
. It allows to configure the behavior of the router regarding the state restoration when a navigation is cancelled. Check out the sources for the possible values and meaning.
Observe activate/deactivate events when an outlet gets attached/detached
The router now provides new outputs allowing to subscribe for the attach
and detach
events on a RouterOutlet
. Previously, there was no way to subscribe for those events when an outlet got attached/detached with RouteReuseStrategy
. Those new outputs emit when an outlet gets attached/detached.
Define custom route reuse strategy through DI for RouterTestingModule
It is now possible to provide a custom route reuse strategy through dependency injection for the RouterTestingModule:
TestBed.configureTestingModule({
imports: [RouterTestingModule],
providers: [{provide: RouteReuseStrategy, useClass: AttachDetachReuseStrategy}]
});
Angular tests improvements
With Angular 13, the Angular TestBed has received some improvements.
It now better takes care of tearing down test modules and environments after each test. The DOM is now cleaned up after every test, avoiding side effects. Overall, tests should execute faster, use less memory, and be less interdependent.
The automatic teardown was an opt-in since Angular 12.1.0 and is now the default. As mentioned in the announcement, this behavior can be configured for the entire test suite via the TestBed.initTestEnvironment method:
beforeEach(() => {
TestBed.resetTestEnvironment();
TestBed.initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
{
teardown: { destroyAfterEach: true }
}
);
});
Or it can be configured per module by updating the TestBed.configureTestingModule method:
beforeEach(() => {
TestBed.resetTestEnvironment();
...
TestBed.configureTestingModule({
declarations: [TestComp],
teardown: { destroyAfterEach: true }
});
});
This provides us with the flexibility to use a different approach depending on the situations. Lars Gyrup Brink Nielsen has written a blog post to explain this more in detail.
Accessibility improvements
With Angular 13, the accessibility of Angular Material MDC-based components has been drastically improved.
To me, it is always a pleasure to see large organizations put energy into improving accessibility. I wish more organizations across the world would do the same, given how important it is to ensure that all of our users have a great experience.
All the MDC-based components have been reviewed and adapted to meet more stringent accessibility standards. The improvements include things like contrast, touch targets, ARIA, and more.
In the announcement, the Angular team has highlighted the touch target size changes for components like checkbox and radio button:
As well as the better high contrast mode support for multiple components:
To learn more about those changes, check out the blog post about improving Angular Component's accessibility.
I'll tell you more about the other Angular Material changes further in the article.
And more...
There's a ton more minor changes in this release. Here's a quick overview.
Support for inlining Adobe Fonts
With the release of Angular 11, Angular became capable of inlining Google Fonts. With this release, Angular can now also inline Adobe Fonts. This new feature is enabled by default.
Font inlining is a very cool feature, as it helps improve application performance, and thus reach better Web Vitals scores. In particular, it helps with First Contentful Paint (FCP).
Check out the following video for more details:
Date pipe improvements
Previously, if we needed to specify a custom timezone/timezone offset for the date
pipe, the only option was to use the second (optional) argument of the date
pipe, like this:
{{ myDate | date: "shortTime":"+1200" }}
This was cumbersome because it had to be repeated all over the place. Angular 13 introduces a new way to customize this, using a specific provider:
providers: [
{ provide: DATE_PIPE_DEFAULT_TIMEZONE, useValue: '+1200' }
]
It's a small improvement, but it can be a big win for large projects. Less boilerplate is better for readability and developer experience (DX). You can learn more about this here.
Service worker (NGSW) changes
Small changes have been introduced for the Angular service workers. Previously, we had to check the activated
observable in order to determine if the invocation resulted in an update of the service worker. This is no longer the case. The activated
observable has been deprecated. As of Angular 13, the activateUpdate
and checkForUpdate
promises will return true
if the update was activated.
Note that the available
observable has also been deprecated. The versionUpdates
observable replaces it. The new one provides more information and emits whenever a new version of the service worker is available and if an installation failed.
You can learn more about those changes here.
ng serve changes
The ng serve
command now uses webpack-dev-server
4.x, which uses WebSockets to push changes to the browser. Check out the release notes of the package to discover other new features/improvements.
If you use a proxy, you will need to make sure that your proxy is also configure for WebSockets. Otherwise you'll encounter some issues.. ;-)
Localization changes
$localize
is a fast and efficient method to implement internationalization (i18n) and tag messages for translation in code, but also in templates. Here's an example:
function hello(name) {
return $localize `Hello ${name}`;
}
This translates into:
function hello(name) {
return "Bonjour" + name;
}
Quite nice. Unfortunately, this new API is not compatible with third-party libraries like ngx-translate or transloco.
The documentation describing the localization API has been updated. Check out the guides to learn more. For instance, the $localize API has been documented.
Breaking changes
There are also a number of breaking changes with this release. A necessary evil! 😈
As the official release notes are pretty clear, I’m just copy/pasting those here:
Common:
- The behavior of the
SpyLocation
used by theRouterTestingModule
has changed to match the behavior of browsers. It no longer emits a 'popstate' event whenLocation.go
is called. In addition,simulateHashChange
now triggers both ahashchange
and apopstate
event. Tests which uselocation.go
and expect the changes to be picked up by theRouter
should likely change tosimulateHashChange
instead. Each test is different in what it attempts to assert so there is no single change that works for all tests. Each test using theSpyLocation
to simulate browser URL changes should be evaluated on a case-by-case basis.
Core:
- TypeScript versions older than 4.4.2 are no longer supported.
- NodeJS versions older than
v12.20.0
are no longer supported due to the Angular packages using the NodeJS package exports feature with subpath patterns. - The
WrappedValue
class can no longer be imported from@angular/core
, which may result in compile errors or failures at runtime if outdated libraries are used that are still usingWrappedValue
. The usage ofWrappedValue
should be removed as no replacement is available.
Forms:
- A new type called
FormControlStatus
has been introduced, which is a union of all possible status strings for form controls.AbstractControl.status
has been narrowed fromstring
toFormControlStatus
, andstatusChanges
has been narrowed fromObservable<any>
toObservable<FormControlStatus>
. Most applications should consume the new types seamlessly. Any breakage caused by this change is likely due to one of the following two problems: (1) the app is comparingAbstractControl.status
against a string which is not a valid status; or, (2) the app is usingstatusChanges
events as if they were something other than strings.
Router:
- The default url serializer would previously drop everything after and including a question mark in query parameters. That is, for a navigation to
/path?q=hello?&other=123
, the query params would be parsed to just{q: 'hello'}
. This is incorrect because the URI spec allows for question mark characters in query data. This change will now correctly parse the params for the above example to be{v: 'hello?', other: '123'}
. - Previously
null
andundefined
inputs forrouterLink
were equivalent to empty string and there was no way to disable the link's navigation. In addition, thehref
is changed from a propertyHostBinding()
to an attribute binding (HostBinding('attr.href')
). The effect of this change is thatDebugElement.properties['href']
will now return thehref
value returned by the native element which will be the full URL rather than the internal value of theRouterLink
href
property. - The router will no longer replace the browser URL when a new navigation cancels an ongoing navigation. This often causes URL flicker and was only in place to support some AngularJS hybrid applications. Hybrid applications which rely on the
navigationId
being present on initial navigations that were handled by the Angular router should instead subscribe toNavigationCancel
events and perform thelocation.replaceState
themselves to addnavigationId
to the Router state. In addition, tests which asserturlChanges
on theSpyLocation
may need to be adjusted to account for thereplaceState
which is no longer triggered. - It is no longer possible to use
Route.loadChildren
using a string value. The following supporting classes were removed from@angular/core
:NgModuleFactoryLoader
andSystemJsNgModuleFactoryLoader
- The
@angular/router
package no longer exports these symbols:SpyNgModuleFactoryLoader
andDeprecatedLoadChildren
- The signature of the
setupTestingRouter
function from@angular/core/testing
has been changed to drop itsNgModuleFactoryLoader
parameter, as an argument for that parameter can no longer be created.
Service worker:
- The return type of
SwUpdate#activateUpdate
andSwUpdate#checkForUpdate
changed toPromise<boolean>
. Although unlikely, it is possible that this change will cause TypeScript type-checking to fail in some cases. If necessary, update your types to account for the new return type.
CDK:
CKD_COPY_TO_CLIPBOARD_CONFIG
has been removed. UseCDK_COPY_TO_CLIPBOARD_CONFIG
instead.ConnectedPositionStrategy
has been removed. UseFlexibleConnectedPositionStrategy
instead.OverlayPositionBuilder.connectedTo
has been removed. UseOverlayPositionBuilder.flexibleConnectedTo
instead.
Material:
CanColorCtor
is no longer necessary and has been removed.CanDisableRippleCtor
is no longer necessary and has been removed.CanDisableCtor
is no longer necessary and has been removed.CanUpdateErrorStateCtor
is no longer necessary and has been removed.HasInitializedCtor
is no longer necessary and has been removed.HasTabIndexCtor
is no longer necessary and has been removed.- Material now requires at least version 1.34.0 of Sass. Version 1.38.0 is recommended.
- The
_document
and_dialog
parameters have been removed from theMatDatepicker
andMatDateRangePicker
constructors. MatFormFieldHarness.getHarnessLoaderForPrefix
has been removed. UseMatFormFieldHarness.getPrefixText
instead.MatFormFieldHarness.getHarnessLoaderForSuffix
has been removed. UseMatFormFieldHarness.getSuffixText
instead.- The
_labelOptions
parameter of theMatFormField
constructor has been removed. MatFormField.underlineRef
has been removed.matTextareaAutosize
has been removed. UsecdkTextareaAutosize
from the@angular/cdk/text-field
module instead.MatTabHarness.getHarnessLoaderForContent
has been removed. UseMatTabHarness.getRootHarnessLoader
instead.
Youtube player:
YouTubePlayer.createEventsBoundInZone
has been removed.
Deprecations and bug fixes
Check out the release notes for the full list of deprecations and bug fixes.
Angular Material & Angular CDK
Date adapter for date-fns
Angular Material has included adapters for moment.js and luxon for a while. With Angular 13, a new date adapter has been added that supports date-fns. That's pretty cool!
Angular CDK changes
Angular 13 only includes a small change for the Angular CDK.
The cdkConnectedOverlayOrigin
input of the CdkConnectedOverlay
directive supports the additional types defined by FlexibleConnectedPositionStrategyOrigin
Angular Material changes
There are also a few changes for Angular Material.
It is now possible to define content sections in test harnesses for the Dialog component.
Also, a new injection token called MAT_PROGRESS_BAR_DEFAULT_OPTIONS
has been added to the progress bar. It can be used to configure the default options as follows:
provide: MAT_PROGRESS_BAR_DEFAULT_OPTIONS,
useValue: {
mode: 'buffer',
color: 'warn'
}
The autoFocus
option of dialogs was previously a boolean. It was used to specify whether the container element or the first tabbable element was to be focused on dialog open. As of Angular Material 13, it is now possible to configure it in other ways. For instance, we can now configure it to focus the first header element, or use a CSS selector and have it focus the first element that matches that selector. The new type of the autoFocus
option is AutoFocusTarget | string | boolean = 'first-tabbable';
. Check out the PR for usage examples.
The experimental version of Material has also a few new features. The most noteworthy one is the following:
A DI token called MAT_CARD_CONFIG
has been added for MDC-based cards. It allows to set the default appearance: provide: MAT_CARD_CONFIG, useValue: {appearance: 'outlined'}
.
Angular Universal
Nothing new for Angular Universal in this release, apart from the support for NodeJS 16.
Google Maps
As you know, Angular includes components for Google Maps and Youtube. Version 13 doesn't bring anything new. The only change is the fact that Angular's Google Map component now relies on more recent typings for the google.maps
package: ^3.45.6
.
Upgrading
As usual, there's a complete upgrade guide available, and ng update
will help you out: https://update.angular.io/?l=3&v=12.0-13.0.
A number of automated migrations have been included in this release:
- Remove the old IE-specific polyfills
- Remove options like
extractCss
which have been removed in this release - Add
.angular/cache
to.gitignore
- Update empty
routerLink
in templates - ...
If you're using Nrwl NX (hint: you should!), I'm sure that support for Angular 13 will be added real soon.
Conclusion
In this article, I've explored the new features of Angular 13 as well as all the nitty-gritty details. As usual, this is release is heroic (what else could it be?!).
Now that ViewEngine is gone, Ivy is king in Angular-land. Without a doubt, this will enable the Angular team to focus on forward-looking improvements like making NgModules optional and running type checks in the background, which could lead to huge developer experience improvements.
If you want to learn more about optional NgModules, then check out the Angular Nation Meetup video:
By the way, you can already prepare for the future of Angular by getting rid of shared modules.
I'm really optimistic about the next two major releases of Angular. Hopefully, Angular 14 will introduce much safer reactive forms, and Angular 15 is certainly going to be an EPIC release 😎.
Luckily for us, the Angular team now relies more and more on RFCs to discuss the future evolutions. This gives more room for the community to be listened to, and that's great!
That's it for today! ✨
About Sébastien
I am Sébastien Dubois. You can follow me on X 🐦 and on BlueSky 🦋.
I am an author, founder, and coach. I write books and articles about Knowledge Work, Personal Knowledge Management, Note-taking, Lifelong Learning, Personal Organization, and Zen Productivity. I also craft lovely digital products . You can learn more about my projects here.
If you want to follow my work, then become a member.
Ready to get to the next level?
To embark on your Knowledge Management journey, consider investing in resources that will equip you with the tools and strategies you need. Check out the Obsidian Starter Kit and the accompanying video course. It will give you a rock-solid starting point for your note-taking and Knowledge Management efforts.
If you want to take a more holistic approach, then the Knowledge Worker Kit is for you. It covers PKM, but expands into productivity, personal organization, project/task management, and more:
If you are in a hurry, then do not hesitate to book a coaching session with me: