Static imports of lazy-loaded libraries are forbidden.

If you are using Nx, you might have already encountered this issue. This Eslint rule comes from the package @nx/enforce-module-boundaries developed by the Nx team.

If you don’t know or you are not using Nx, this article can still be valuable and you might learn something from it.

Context

Nx is a workspace organizer. You will create folders called libraries to organize your code, and you will expose components and functions to be used outside of the library. This error happens when you try to lazy import an element and at the same time you eager import another element from the same library.

In this article, we will see what this error really means and the side effect that this error is preventing. Lastly we will see how to resolve it.

Setup

First let’s create a small example to better illustrate the issue.

We create a dashboard application with the following architecture:

In the apps folder, we have our application entry point. AppComponent is the root component.

In the libs folder, we have one library called users containing two components:

UsersDashboardComponent is a table listing all users. (It uses Angular Material MatTable.)UserComponent is a component displaying an icon and the user’s fullname. (It uses MatIcon)index.ts is our library entry point where both component are exposed.// index.ts
export { UserComponent } from ‘./lib/user.component’;
export { default } from ‘./lib/users-dashboard.component’;

AppComponent is eager referencing UserComponent and it’s lazy-loading UsersDashboardComponent as shown below:

import {
UserComponent,
type User,
} from ‘@angular-challenges/static-dynamic-import/users’;
// ^Where the ESlint error is shown!!!

@Component({
imports: [UserComponent, RouterOutlet],
template: `
Author:
<sdi-user [user]=”author” />
<router-outlet />
`,

})
export class AppComponent {
author: User = {…};
}

Where the router is defined as follow:

provideRouter([
{
path: ”,
loadComponent: () =>
import(‘@angular-challenges/static-dynamic-import/users’),
},
]),

We can now clearly see that users library is loaded statically and dynamically.

However at serve/build time, Typescript is not showing errors and the application is running correctly. So, why do we need to create an ESlint error to guard us from this issue and what is the side effect of importing a library statically and dynamically at the same time ?

Side-Effect

To better understand the issue, we will inspect the bundle of the application’s build. The tool source-map-explorer will be of great help.

Let’s build our application using the production configuration and setting sourceMap to true.

After the build has completed, we can see this summary printed in the console:

build bundle size

Let’s explore what is inside the main bundle by opening the chunk inside source-map-explorer by re-running the following command:

npx source-map-explorer [PATH_DIST_FOLDER]/*.js

This command will give you the following visualization:

main bundle exploration

By opening the source-map of the main chunk, we can see that MatTable and MatIcon are bundled in the same chunk, although MatTable is only used inside UserDashboardComponent which is lazy-loaded. We would have expected that this component would be bundled inside the lazy-loaded one.

This small example clearly shows that the compiler is bundling the entire library inside the main bundle despite using only a small portion of it.

Solution

The solution is straight forward. We only have to create a new library and move our UserComponent. We will now have two libraries. One which will be lazy loaded, and a shared one which can be eager loaded anywhere in our code.

Let’s rebuild our refactored application.

build summary

and rerun source-map-explorer

main bundle containing only MatIconLazy-loaded bundle containing MatTable

The compiler divided our component successfully. MatTable is now located inside the lazy-loaded component and it will not increase the main bundle unnecessarily.

If you want to play with this example and try it on your own, I created a challenge inside AngularChallenges.

You can find me on Medium, Twitter or Github. Don’t hesitate to reach out to me if you have any questions.

Static imports of lazy-loaded libraries are forbidden. was originally published in ngconf on Medium, where people are continuing the conversation by highlighting and responding to this story.

Leave a Comment

Your email address will not be published. Required fields are marked *