Skip to content

Last week I got the chance to attend the NG-DE Angular conference with six other LeanIX engineers. In this post, I will share my summaries of some of the talks that were presented there.

LeanIX ❤️ Angular

Out of all software engineers at LeanIX, 40 are actively contributing to our Angular applications every month.

While the LeanIX products Enterprise Architecture Management and Value Stream Management use Angular as the main frontend framework, our Saas Management Platform product is happily using Vue.js.

Summary of talks

The following content is based on the notes I have taken during the talks. Some of them are more complete than others. I'm not including any opinions of my own.
I also recommend watching the recordings on the NG-DE YouTube channel once they are available, since not seeing the slides results in less context information.

Jump to a talk:

How do new Angular features improve developer experience?

by Simona Cotin

Angular is an opinionated framework. Yet each company has different needs.

The Angular team highly values listening to the community. The Angular developer survey that they conduct annually is one of the most powerful tools for them to achieve this.

The following are Angular updates that Simona presented in her talk.

Debugging and Profiling

The Angular Team got together with the Chrome Team to improve the developer experience in chrome devtools.
By enabling the new x_google_ignore_list plugin on the "Sources" tab (available in the three-dot-menu), searching for a file to inspect becomes easier as it will no longer list results from third-party code inside node_modules.
The list of directories to exclude by this plugin is included in the sourcemap by Angular.
Link to a video with a demo of this feature.

The documentation and guidance for how to deal with ExpressionChangedAfterItHasBeenCheckedError have been greatly improved. Link to documentation: https://angular.io/errors/NG0100

Testing

Support for Playwright, Cypress, and WebDriverIO in the Angular CLI through ng e2e command. See this blog post.

Protractor is officially deprecated. See this issue on the angular GitHub project. Work on establishing extended support is ongoing.

Build times

Today, building Angular applications involves three stages:

  • webpack bundler
  • function inlining
  • terser

Version 14 added experimental support for esbuild as bundler instead of webpack.

For a simple "hello world" Angular app, the build time was reduced to 3.6 seconds from 7.1 seconds when enabling esbuild.

You can give it a try by replacing @angular-devkit/build-angular:browser with @angular-devkit/build-angular:browser-esbuild in your angular.json file.

Reducing the learning curve

Having to understand the concept of NgModule for people starting out on their Angular learning journey can be confusing.
With the new standalone components API, it is no longer required to use NgModule when starting out with Angular.

User Experience

One way to measure user experience is to look at the Core Web Vitals:

  • Largest Contentful Paint
  • First Input Delay
  • Cumulative Layout Shift

The Angular team got together with the Aurora Chrome Team to reduce the time to the Largest Contentful Paint on pages that include images by introducing the NgOptimizedImage directive.

Link to announcement on the chrome developer blog.

Accessibility

Easy page title manipulation through the new TitleStrategy. A new title property is available in the route configuration to easily set the page title at the same place where the routes are defined.

Also in Angular 13 a new ariaCurrentWhenActive input was added to the routerLinkActive directive to make it easier to indicate that a link is currently active to assistive technologies like screenreaders.

Angular Material component library

The Angular Material component library is transitioning to using the Material Design Components. Link to the respective item on the Angular roadmap.

Outlook

Other topics that the Angular team is looking into:

  • Improving documentation
  • Improvements to Hydration
  • New reactivity concepts (ties into zoneless Angular as well)

Stop Micromanaging State and Start Being Reactive

by Lara Newsom

Implementing state management in an imperative style results in brittle and more bug-prone code.

You easily run into the following bad code patterns when working with an imperative style for state management in Angular:

  1. redundant properties
  2. void methods
  3. Observable.subscribe() calls inside of the component class

1. On redundant properties

This happens for example when you need to touch an old component and fail to understand the existing properties, so you just add a new property to accomplish the task at hand.

2. void methods

Rather than reassigning properties with pure functions that return a new value, a common code pattern is to have some private method like updateStateAfterResponse(response) which has no return value and mutates multiple class properties inside of it.

3. Observable.subscribe() calls inside of the component class

Having Observable.subscribe() calls in your component class can result in memory leaks when you forget to unsubscribe. This pattern can also lead to many duplicate subscriptions when resubscribing to the same observable in some class method.

In addition to this, having .subscribe() calls within .subscribe() calls can lead to race condition bugs.

Addressing these issues

Lara advocates for a component structure where your component class only contains the inputs and outputs. Any logic for computed properties (observables) should come from injectable services.

You should first think about what data is required for your component and map this to component inputs.
In the second step you set up observable streams in injectable services to be used in your component.

Two possible ways to do this are by using Subjects inside your service or to communicate with a state management library like ngrx in your service.
For the Subject way: always keep the Subject itself private and expose it on a public property on the service using the Subject.asObservable() method.

By following these patterns, your components will be a lot shorter (fewer lines of code). It will also be easier to test compared to imperative style, as you'll end up with better defined component and service APIs which make your test setup easier.
Your services will also be easier to reuse, should that need ever arise.
All of this also results in code that is easier to refactor.

Securing Angular with Trusted Types

by Philippe De Ryck

All modern frontend frameworks, including Angular, escape HTML when rendering any string in a component.

In cases where you want the browser to parse and render the HTML inside a string, Angular comes with the helpful innerHtml directive out of the box.
This sets it apart from other frameworks.
The innerHtml directive will sanitize the given HTML string by removing any malicious HTML, such as calls to alert().

However, this does not mean that Angular applications are generally safe from things like Cross-Site-Scripting.

Using DomSanitizer.bypassSecurityTrustHtml() should generally be avoided when injecting HTML into the DOM.

Another danger lies in the ViewChild decorator, which exposes the native DOM element to the component class.

This is where the trusted-types Content Security Policy (CSP) comes in. It helps you protect your entire website from using unsafe DOM access.

You can enable it for Angular applications by including trusted-types angular; require-trusted-types-for 'script' in the content-security-policy response header.

By using this policy, the browser will throw an error whenever Element.innerHTML is assigned to an unsafe value, such as a value returned by DomSanitizer.bypassSecurityTrustHtml().

If you need to define your own policy, you can do so using the TrustedTypes.createPolicy() API. In his example, Philippe used the DOMPurify library to do this:

trustedTypes.createPolicy('default', {
createHTML: string => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true})
});

The trusted-types CSP is not supported in Firefox and Safari today, but Philippe recommends still enabling it during development.

Philippe has also published a comprehensive blog post on this topic, which you can read here.

Lazy loading techniques beyond Angular router

by Vojtech Mašek

  • The VSCode Import cost plugin will display the number of kilobytes added to your bundle for each imported module.
  • On bundlephobia.com you can quickly see both the minified and gzipped bundle size by an npm package.
  • Using npx webpack-bundle-analyzer stats.json you can inspect the bundles of your Angular application after build. You can generate this stats.json by providing the --stats-json argument on your ng build command.
  • Use lazy loaded Angular routes. Link to docs
  • Using esnext dynamic imports you can lazy load any import, so that it's only loaded when it's used.
  • Create custom exports of a third-party library by importing and registering only the plugins you need so that unused plugins are not included in your bundle.
  • Enable the vendorChunk option in the Angular CLI build options so that any third-party code will be bundled separately from your main.js. This boosts performance since the vendor bundle can be loaded from cache as long as it remains unchanged.

Community === You

by Ana Cidre

Ana shared her experience of growing together with the Angular community.

Consider giving a talk of your own or organizing community events. You don't have to do this alone. The Angular community is very supportive.

Definition of Community

On Wikipedia you would find a definition of the term "Community" like this:

People sharing or having certain interests and attitudes in common.

Ana presented her criteria of what makes a community like the Angular one:

  • a space where people have a sense of belonging
  • a safe space
  • a space to share knowledge
  • a place where people go to learn

Perks of taking part in the community

Giving a talk or writing a blog article is a catalyst to dive deeper into a topic.

A strong network is helpful for finding jobs.

Call to action

Reach out to event organizers if you have a topic that you would like to be covered in a future event. This kind of feedback is just as valuable to the organizers as people giving talks.

Perceived faster Angular Applications

by Cathrin Möller

Some metrics on perceived web performance:

  • When a user does not get feedback for an action performed on a Website after 5 seconds, they give up.
  • Everything up to 100 milliseconds will be perceived as "instantly".
  • 100 to 300 milliseconds is a small noticeable delay, but nothing annoying.
  • 300ms to 1 second is perceived as "this page is working".
  • Anything beyond that is not desirable.

When comparing Angular's bundle size to other popular frontend frameworks like Vue or React, one should also consider that when not using Angular, you will need additional dependencies to get things like routing or form validation.

It is crucial to keep the perceived initial loading time of a website low. Let's look at the three most important parts of bootstrapping an Angular application.

  1. index.html
  2. main.ts
  3. app.module.ts

On index.html

The index.html is responsible for loading the JavaScript bundles for your Angular application. You must add some sort of inline HTML and CSS to your index.html to display some moving parts on the page, while JavaScript is still loading. Looking at a white screen while the page is loading is not providing any sort of feedback to the user.
Even better: Use a page skeleton with shimmer animations.

On main.ts

Avoid blocking requests before the bootstrapModule call. If you must fetch some sort of configuration before bootstraping, consider if you can include that configuration in your bundle at build time.

On app.module.ts

By using Angular's localize package, you can get UI translations incorporated at build time, which results in one less file to be loaded in contrast to runtime internationalization libraries which load the messages during bootstrapping.

If you have to do anything during the initialization for your Angular application, use the APP_INTIALIZER token for that. Your Angular app will not complete initializing as long as the Promise returned by the injected function does not resolve. A common use case for this is checking if the user is authenticated.

Pay attention when animating CSS properties

Not all CSS properties are equal when it comes to animation performance.
It's much more efficient to animate the scale of an element rather than its width or height for example, as the latter will trigger the browser to recalculate the layout of the page.

Cathrin recommended the csstriggers.com website as a helpful resource for this. At the time of writing this article, that page is not available anymore, but I've found this one on web.dev helpful as well.

Do optimistic updates

When the user performs an action that triggers an API request that's likely to succeed eventually, you can also reflect the updated state in the UI right away.
One example is the "like" button in a social network. This way the user gets instant feedback instead of having to wait.

Battle tested strategy for Angular Micro Frontends using web components

by Konstantin Tieber

On the second day of the conference, I got the chance to give a 20-minute talk at the community stage provided by e.on. I presented the Angular micro frontend solution using web components, which we've been using in production at LeanIX for two years.

You can download the slides for that talk here.

Link to the example project presented during the talk: github.com/fboeller/microfrontends-with-angular

Link to a YouTube video explaining our micro frontend solution from start to finish: youtube.com/watch?v=ee17YczpCpU

Thank You

This blog post was very much made possible by the organizers and speakers of the NG-DE conference. A big thank you to all of you!

Keep an eye on the NG-DE YouTube channel for the recordings of the talks.

Link to the NG-DE conference Website

Image of the author

Published by Konstantin Tieber

Visit author page