Why and how to use secondary entrypoints in your Angular Libraries in Nx
Tags: angular, nx, package, library
Published: 2021-11-06 09:05:53

Photo by <a href="https://unsplash.com/@sxy_selia?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Sangga Rima Roman Selia</a> on <a href="https://unsplash.com/s/photos/check?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText">Unsplash</a>

Nx Devtools recently released [version 13.1](https://github.com/nrwl/nx/releases/tag/13.1.0), which came with a very handy generator for Angular libraries, which [creates secondary entrypoints for your Angular Libraries](https://github.com/nrwl/nx/pull/7501) with ease. In this blog post we will cover why and how we should make use of this new function.

## Why secondary entrypoints make sense?
By adding secondary entrypoints, we basically split our Angular libraries into multiple chunks, just like `Angular Material` does.
A Example: 
```typescript
// One entrypoint: 
import { MatButtonModule, MatCardModule } from '@angular/material';

// With secondary entrypoints:
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
```

The idea behind it is not new at all, this option already exists since the beginning phase of `ng-packagr`. By leveraging secondary entrypoints, we aim better architecture, support of treeshaking, smaller bundle sizes and therefore faster applications. 

### Demo 👀
To demonstrate the impact, I prepared a little example: 
Therefore I created a small `greeter` library and an a simple test-app, which just consumes one component out of this greeter library.

Here is the greeter library, which contains a `simple greeter` and a `fancy greeter`: 
```typescript
// simple-greeter.component.ts
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';

@Component({
  selector: 'kauppfbi-blogs-simple-greeter',
  template: ` <p>Nice to meet you, {{ name }}!</p> `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class SimpleGreeterComponent {
  @Input() name!: string;
}

// fancy-greeter.component.ts
...
import moment from 'moment';

@Component({
  selector: 'kauppfbi-blogs-fancy-greeter',
  template: `
    <p>Nice to meet you, {{ name }}!</p>
    <p>Today is the {{ time }}</p>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FancyGreeterComponent implements OnInit {
  time = '';
  @Input() name!: string;

  ngOnInit(): void {
    this.time = moment().format('DD.MM.YYYY');
  }
}
```

Both are exported in the `index.ts` file (public api) of the library:
```typescript
export * from './lib/simple-greeter/simple-greeter.module';
export * from './lib/simple-greeter/simple-greeter.component';

export * from './lib/fancy-greeter/fancy-greeter.module';
export * from './lib/fancy-greeter/fancy-greeter.component';
```
You probably noticed, that the `fancy greeter` imports `moment`... you already know, where this leads to. 

Our `test-app` is also kept simple:
```typescript
// app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { SimpleGreeterModule } from '@kauppfbi-blogs/greeter';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, SimpleGreeterModule],
  bootstrap: [AppComponent],
})
export class AppModule {}

// app.component.ts
@Component({
  selector: 'kauppfbi-blogs-root',
  template: `<kauppfbi-blogs-simple-greeter [name]="name"></kauppfbi-blogs-simple-greeter>`,
})
export class AppComponent {
  name = 'Duke';
}
```

To complete the demonstration, we will use the `webpack-bundle-analyzer` to inspect the production bundle of the app:
```bash
# build app with production configuration and generate bundle statistics
npx nx test-app:build:production --stats-json
# inspect the bundle
npx webpack-bundle-analyzer dist/apps/test-app/stats.json
```
This will open up a new webpage containing the chunks of our app:
![Webpack Bundle Analyzer unoptimized](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d6jm1r5sujcz57i2fcaj.png)
As you can see, our bundle consist largely of `moment` even though we did not consume the `fancy greeter`, but the simple greeter. 🐵

## How to use the new generator? 
Now as we know, why it makes sense to use secondary entrypoints in Angular Libraries, we will look into how to use them. 

As it is just one command, it is pretty simple: 
```bash
npx nx generate @nrwl/angular:library-secondary-entry-point \
--name=my-secondary-entrypoint \
--library=my-library
``` 
or with the Nx Console:
![Nx Console](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ubuwnbiloi3ynd1rubgk.png)
 
The command will scaffold a new folder with the name of your entrypint containing a `src` folder with a `Readme`, a `package.json` and a `module` exported by a new `index.ts` file. In addition, it will adjust the `lintFilePattern` of the entire library project and it will create the correct `pathMapping` in the `tsconfig.base.json`.

Now you can either move existing modules there or create new ones.
In our use case, it was a matter of two minutes to shift the code.

Let's analyze the result:
![Webpack Bundle Analyzer optimized](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bqmhnutke7p5wcigfy7e.png)
First of all, we can see that the bundle size was decreased significantly. Okay, this was just a demo and I wouldn't recommend to use `moment` nowadays at all. But, more importantly we verified that we only load necessary code and we are able to support proper treeshaking with our solution!

That's it already, happy coding! 🚀

## GitHub Repository 
All the code is available in a [public repository](https://github.com/kauppfbi/kauppfbi-blogs) on Github. You can find the `greeter library` [here](https://github.com/kauppfbi/kauppfbi-blogs/tree/main/libs/shared/greeter) and the `test-app` [here](https://github.com/kauppfbi/kauppfbi-blogs/tree/main/apps/test).

## Further Links 🔗
Checkout the following blog posts to learn more about `seondary entrypoints`:
*  [Improve SPA performance by splitting your Angular libraries in multiple chunks](https://medium.com/angular-in-depth/improve-spa-performance-by-splitting-your-angular-libraries-in-multiple-chunks-8c68103692d0) by Kevin Kreuzer
*  [Creating Secondary Entry Points for your Angular Library](https://medium.com/tunaiku-tech/creating-secondary-entry-points-for-your-angular-library-1d5c0e95600a) by Christian Ing Sunardi