ng-samurai — Schematics to improve tree shaking of Angular libraries
Angular schematics to split your library into multiple chunks with ng-packagr’s subentries

Angular libraries are a great way for open source projects or companies to share code across multiple applications.
Thanks to the Angular CLI, creating a library is easy. However, by default, your library may not be as tree shakable as you might think. In most cases, this is not a big deal, but sometimes, it can have a considerable impact on consumer’s performance. In other words, your library can slow the (initial load) of an application.
This happens mainly when your library includes third party libraries packaged in another format then ESModules
like moment
for example.
If you are not familiar with the points mentioned in the introduction I recommend you to check out the following article which explains such scenarios in detail.
But even in scenarios without problematic third-party imports, a split library makes sense. So why don’t we split our library?
Well, it’s it is practically not documented how to do this, and it is complicated. But the good news is, there are schematics to assist you, which I will show you in more detail throughout this blog post.
But first, let me show you the downside of single chunk libraries.
The Game of thrones wiki library
Let’s say we build a library that displays characters from Game of Thrones. The library project is generated with the CLI as a multi-project workspace and contains the following modules.
lib
|_ arya-stark
|_ arya-stark.{component, module, etc...}
|_ bran-stark
...
|_ cercei-lannister
...
|_ jaime-lannister
...
|_ john-snow
...
|_ lannisters
...
|_ robb-stark
...
|_ starks
...
|_ tyrion-lannister
...
|_ tywin-lannister
...
public-api.ts
Each character gets its folder which contains a component
, a module
, a component.spec
, a scss
file and an image of the character.
In real world applications there are better ways to deal with images, but for the purpose of this app, I want the library bundle to become big 😉.
The lannisters
and the starks
modules import other modules to display information about all members of the family.
Nothing fancy, a simple Angular library generated with the CLI.
Let’s analyze how tree shakable this library is in an application that takes advantage of lazy loading.
Analyze tree shaking for the got-wiki library
To answer this question we create a simple application that uses the got-wiki
library to display members of the stark family.

Our application uses a couple of Material components to display the toolbar and side navigation. It contains four lazy-loaded modules that are all accessible over the menu items in the form of lazy loaded routes.
Let’s analyze how this reflects in the bundles.

Each lazy-loaded feature gets split into its chunk.
That’s great. But wait, somethings wrong here. Each bundle is only around 1.5 KB
size. That’s super small, too small 🤔
Our library module includes the image of the character, which is very big. Since the lazy-loaded chunks are that small, the library module needs to be added somewhere else. But where?
In the main? No, the main bundle is at 392 KB
, they can not be there. But there’s another chunk called 1-es5.f3...
and indeed, it looks pretty big. Let’s toggle it in the side menu and have a closer look.

All modules from the got-wiki library got bundled into one big chunk. Small quiz at this point, can you spot our lazy-loaded modules in the image above? 😉
They are displayed as blue squares at the top right corner.
The point here is that the whole got-wiki
library ends up in a dedicated chunk. Even if parts of the library are used in different lazy-loaded pieces, they can not be split apart. Means, once we load the images for one chunk, everything from the got-wiki
library gets loaded. Therefore, we lose almost all the advantages of tree shaking.
So — how to improve — well, ng-samurai!
Ng-Samurai — split your library into multiple subentries
ng-packagr
has a very cool concept called subentries. Subentries are a lovely way to break libraries into multiple chunks instead of one. Doing this in the got-wiki
library, each character would end up in a separate fragment that can be loaded when needed.
Sounds awesome! But! Subentries are rarely documented, and therefore it can be tough to get started. You have to deal with a lot of complexity while the error messages from ng-packagr
are not always helpful.
Common challenges are:
- Find out how your IDE can understand subentries.
- Find out how to adjust import paths from one chunk that imports another chunk.
- Understand how to handle imports so that consumers of your library don’t need to adjust imports to deep imports, and your library remains tree shakable.
There are just a lot of things to it, and it can be very time consuming to get the right setup. That’s the reason why I created ng-samurai! ng-samurai is a collection of Angular schematics that does all that for you!
Ng-samurai is an Angular schematic which automatically updates your library to take advantage of subentries and improve tree shaking. Furthermore it helps you to quickly generate new subentries.
To get started with ng-samurai
we first need to install it as a dev dependency of our project.
npm i -D ng-samurai
Once installed, we can use the schematics provided. Ng-samurai currently provides us with two schematics. split-lib
and generate-subentry
. Let’s first have a look at split-lib
.
Split-lib
split-lib
automatically updates your projects and splits it into multiple chunks
To use split-lib
you need to run the following command from the root of our got-wiki
library.
ng g ng-samurai:split-lib
This command does the following changes to our project:
- Converts each folder where it encounters a module to a subentry — it will add a (
index.ts
,public-api.ts
,package.json
) - Export all the necessary Typescript files from the
public-api
. Necessary files arecomponents
,services
or other files. Basically, every TypeScript file expect.spec
files. - Update the
public-api
at the root level and export all subentries. - Adjust the paths of your
tsconfig.json
so that your IDE understands subentries.

Build with subentries
Once ng-samurai
successfully ran and updated the files we can run ng build --prod
.

The current build log tells us that we build a single entry point for each module. We can also see this in our dist
folder when checking the fesm2015
bundles.

Let’s check how the output of the webpack bundle analyzer looks after we build and install the got-wiki
lib and rerun the analyzer.

Wow! 🤩 That’s what you would expect if you talk about tree shaking, wouldn’t you?
Each lazy-loaded feature module now contains the code it needs and nothing more. Our library code now gets correctly split to the lazy-loaded bundle it is required. The code from our JohnSnowModule
is now only downloaded if it is needed.
ng-samurai allows you to get huge optimizations with one command! 💪
Restrictions of ng-samurai
For ng-samurai to function appropriately, there are certain requirements your library needs to fulfill. In some cases, you might need to refactor your application before using ng-samurai
.
Folder structure
Converting your library to subentries may also require a change of the folder structure. Each module will result in a subentry and needs its folder. Subentries can not have multiple modules.


Circular dependencies
A subentry can use another subentry. But subentries can not work with circular dependencies.

Each file needs to belong to a module
Entry points can contain all sorts of files. ng-samurai
needs a module-file to be present to perform the migration. The .module
file indicates to ng-samurai
that this code will be split into a subentry.

The shared.module.ts
file doesn’t make sense. Therefore it can also be deleted after ng-samurai
adjusted the code.
Creating new features with ng-samurai
ng-samurai
did a fantastic job of splitting our library. But that’s not the only use case of this library. It also supports us in creating new subentries.
Even though he died early, Ned Stark is one of the coolest characters in Game of thrones. It will be a shame if our library doesn’t include him.
Let’s use generate-subentry
command from ng-samurai
for this.
ng g ng-samurai:generate-subentry

This command is very similar to the ng generate module
command of the Angular CLI. In fact, it uses the CLI command under the hood. But additionally, it also creates the public-api.ts
, the index.ts
and the package.json
with the correct content.
Thanks to Tomas Trajan for the assistance and the contributions on this feature.
Conclusion
Subentries can improve tree shakebility of your library and therefore boost the performance of your application.
To enable tree shaking, you need to take advantage of ng-packagr’s
subentries. Subentries are pretty cool, but there’s a lack of documentation about the topic.
I gained experience with subentries by using it in big enterprise projects. Finding the correct setup can get very complicated, and you can lose a lot of hours on the topic.
ng-samurai
is an Angular Schematics that automatically splits your library into multiple chunks.
🧞 🙏 If you liked this post, share it and give some claps👏🏻 by clicking multiple times on the clap button on the left side.
Feel free to check out some of my other open-source libraries.