Why Migrate to Angular Standalone Components
Tags: angular, javascript, frontend, programming
Published: 2023-09-21 20:46:13


It's been a while since Angular v14 was released - the version that introduced standalone components.

How many of you have already migrated to Angular v14 and to standalone components - raise your hand.

If you did, good for you!

If you didn't, I'd say "I understand".

I know from experience the struggles of the job. Sometimes so many things are going on - you're overwhelmed! Migrating to the latest version and catching up with updates just has to wait.

Anyhow!

This article aims to answer questions like:

- how to create a standalone component in Angular?
- what changes did they bring to the Angular world?
- why should you care about them?

Hopefully, this will motivate you to put them higher on your priorities and to-do list.

Let's get started!

<hr />


### 1. Creating them is super easy

Creating standalone components, directives, or pipes is as simple as marking their class with standalone: true.

Standalone classes don't need to be declared in an NgModule. In fact, you'll get an error if you try to. Instead, you specify their dependencies directly in their `imports` array.

![Standalone Component Creation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v8hzp1p1kcxpsq62wndl.png)

This means that NgModules are completely optional - which brings us to our next point.


### 2. Less boilerplate code

Once you get to know standalone components, you'll realize that in many cases modules were just boilerplate code.

An `NgModule` is a "context holder" for declarations and providers. This means that modules handle dependencies themselves.

The problem is when a module doesn't do anything like that. It's only exporting a declared component, directive, pipe, etc. Then we just deliver a useless class that provides no additional value.

We don't even need an `AppModule` anymore - we can bootstrap the application directly with a component.

![Angular Bootstrap with Standalone Component](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ezjch6y86vxiejq7cy5l.png)

We just provide the required providers (as if this was a module). Think of `[importProvidersFrom](https://angular.io/api/core/importProvidersFrom)` as a bridging function.

We will see this less often as libraries start to adapt and provide helper functions. For example, with Angular v14.2 we already got this (line 4):

![importProfiversFrom Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/56pbono77gqozf8j9za8.png)

However, to play the devil's advocate here - there's still work that needs to be done.

![Standalon-Yes-But](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/13vll0s9pz5y6eiohpzg.png)

The list of imports can grow fast. It would be nice if we could somehow avoid this duplication.

The Angular team must already be aware of this. Hopefully, we'll see some mechanism that deals with this in an upcoming version.


### 3. Direct and more tree-shakable routing

Remember how we had to point to another module that then pointed to a routed component or route configuration?

That belongs to the past!

Now we can point directly to a routed component (line 10) or route configuration (line 14). Because of standalone components routing became more tree-shakable.

![Routing Standalone Components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/putgxm48a1qm55ewnqr8.png)


### 4. Fine-grained lazy loading

It goes without saying that if you can route to a component, then you can also lazy load a component.

No need to load an entire module when you only need to load a specific component.


### 5. Less confusing scope declaration

Did you know?

Every time you lazy-loaded a module, you got a new scope. And when you eager-loaded a module, you didn't.

This is quite confusing. It's like trying to hit two birds with a stone, but instead shooting your own foot.

Luckily, route configuration now has a providers section (line 5). This is optional, but we can use it to provide some providers for that specific route and all its child routes.

![Providing Providers with Standalone API](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pv23qxi3ercbb67y1pfb.png)

These are the providers we would normally put in our lazy-loaded module.

This is more explicit. We put something there? We know we'll get a new scope, regardless of whether we use lazy loading.


### 6. Project structure remains intact

Structuring the application without modules is not affected by any means. We can simply use folders to organize our project.

![Project Structure Example](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nefir31jy2t1qjoe5hng.png)

A better way to do this is to use barrels. It's like creating a public API. Whatever we export from our `index.ts` means that is backward compatible and won't break by future changes.

### *BONUS*: There is a migration schematic!

As of Angular v15.2, there is an Angular schematic to automate the migration from NgModules to the standalone API.

Getting into the details goes way out of the scope of this article. But you can [read how to use it here](https://github.com/angular/angular/blob/main/packages/core/schematics/ng-generate/standalone-migration/README.md).

<hr />

The screenshots are [from this GitHub repository](https://github.com/kagklis/ng-route-parameters), which is a demo from [a previous article](https://javascript.plainenglish.io/angular-route-parameters-a-simple-guide-88c69d54102c?sk=4cc70766878b63ad7de9846007d827c0). This repository contains two branches - the before and after migration to standalone.

<hr />

## Conclusions
Standalone components certainly made an entrance. 😅

We talked about how to create them, the changes they brought to several features of Angular, and the benefits of using them.

[Subscribe to my newsletter](https://angulargems.beehiiv.com/) and stay tuned for more content like this.

_Thank you for reading!_