All you need to know about Ivy, The new Angular engine!
Smaller bundles, faster compilations, Better debugging, dynamic loading of module and components and advanced concepts like Higher order components. Angular Ivy — The complete guide for the 3rd generation of the Angular renderer.
Over a year ago, the Angular core team announced on ng-conf that they are working on Angular Ivy, and even though it’s not 100% ready for production, I’m feeling like this is a really good time to dive deeper into the new renderer of Angular.
After a long wait, Angular version 8 is here!
This is a major release bringing a lot of cool (and important) features as Differential Loading, New builder API, Web-Workers support and more.
But above all those, Ivy is finally opting-in!
First and foremost — Mobile devices!
It might sound insane but 63% of all US online traffic comes from smartphones and tablets. By the end of this year, 80% of internet usage is expected to come from mobile devices. (Source)
One of our biggest challenges as front end developers is to load our website as fast as we can. Mobile devices unfortunately often suffer from a bad or slow internet connection and making this challenge even harder.
On the other hand, we can use many solutions to load our application much faster e.g: use CDN to serve the files from the closest cloud, PWA to cache the assets and many others. But the biggest opportunity we have as developers is Reducing the bundle size.
Reducing the Bundle size
So…bundle size. Let’s see it in action. Let’s take eliassy.dev as a case study. This is a simple web site build with Angular it looks simple but it uses a lot of core features. It also uses the Angular PWA package to support offline and Angular Material with the Animation Module.
Before Ivy, my main bundle weight was a bit more than 500 kb.
Now let’s opt-in Ivy by editing the
tsconfig.app.json and add a section of
angularComplierOptionand set the
true. for new Angular CLI projects, you can just use the
--enableIvy flag when running your
Now let’s build the app again using
ng build --prod:
We can see that our bundle shrunk in 77KB which is 15% of the bundle size, that means our website’s loading time will be 15% faster.
Some of you might be disappointed by the fact we cut only 15% of the bundle size. The reason for this is even though this is a small project it’s still relying on a lot of core features and for now, Ivy is mainly cutting the generated code and not the framework itself.
“We are now working on reducing the framework size so that we have reduced bundle sizes for real applications in nearly every case before making Ivy the default. Additional benefits will also be possible as we offer new ways of bootstrapping that will leave out more of Angular from your main bundle.”
How does it work?
So, what’s behind it? How does it work?
To understand that we need to go to a deep dive inside the internals of the compiler. Let’s create this simple code:
Now, let’s run the
ngccommand to generate the transpiled code:
- For the view-engine renderer:
2. For Ivy:
node_modules/.bin/ngc -p tsconfig.app.json
It’s changed a lot, but a few main differences are important here:
- We don’t have factory files anymore, now all the decorators converted into static functions. In our example the
@Componentconverts into a
- The set of instructions has changed so it can be tree shakable and will be much smaller.
Not only smaller bundles
If we take a look at the
ngIfsection of the transpiled code:
For some reason, my app component is associated with
TemplateRef. If you wonder where those 2 came from, they are actually dependencies of the
NgIf directive implementation.
In Ivy that becomes much more simpler, every component now references child components or directives though much more cleaner public API. The meaning is when we change something, e.g: the implementation of our
NgIf, we won’t need to recompile everything, we can just recompile the
NgIfand not the
This way we had achieved not only smaller bundles, but also faster compilations, and easier way to ship libraries to NPM.
Debugging with Ivy
Ivy is providing also much easier debug API.
Let’s create an input with a
(input)event and bind it to a not exist function named
Before Ivy, When trying to type something inside the input, we get this in the console:
With Ivy our console will look much more informative about where we got the error from:
So we earned another goal with Ivy, better template debugging!
We have a simple app, with 2 modules, app module, and feature module. The feature module will load lazily with the router and will display the feature component. So, When I’m clicking on the click me button, I’m getting the feature module chunk in the network:
Angular 8 brings a new API for loading modules, it now supports ES6 dynamic import.
With that given, why not try the same exact import directly on the component?
And the result:
It’s actually working!! but wait… Something weird just happened. We have loaded a component, without declaring it in the module.
So, should we still declare components in modules? Or, are modules optional now? We will answer that soon, but first, let’s try to add this component to the view.
For this purpose let’s use the `ɵrenderComponent` function:
I’m getting an exception here which make sense cause we trying to attach the component to the view, but didn’t tell who is the host element right?
Here we have 2 options, the first one — is to add the
FeatureComponent selector to the DOM, and Angular will know to use render the component on the selector placeholder:
renderComponent has another signature getting a config where we can set up the host. We can even add a not existing host, and Ivy will attach it to it:
Are Modules still necessary?
As we just witnessed, we don’t need to declare a component on the module. It makes all of us wonder if we really need Modules?
To answer this, let’s create another use case on- Now
FeatureComponent will inject a config that will be declared and provided in the
Now — If we try to load the component again, we get an exception cause our component doesn’t have an injector:
There are also downsides for not declaring component on the modules, we actually not getting them with injectors. Despite this,
renderComponent config also letting us declare an Injector:
And the result:
Yay! It works!
Higher Order Components (HOC)
As we just saw — Angular is now much more dynamic, And it also allows us to implement advanced concepts like HOC.
What is HOC?
HOC is a function which gets a component and returns a component but also affecting the component in between.
Let’s create the basic HOC by adding it as a decorator to our
Now let’s leverage the concept of HOC and dynamic import to create a lazy component:
Few interesting points to talk about:
- How to get the injector without the Angular DI? Remember the
ngccommand? I’ve used it to check how Angular translating the constructor injection inside the transpiled files and found the
2. I’ve used the HOC function to create a new “life cycle” function named
afterViewLoad that if it exists on the original component, it will be invoked after the lazy component got rendered
The result (Directly on load):
Quick summary on what we just learned:
- Ivy, the 3rd generation of Angular compiler is really here! It has a backward compatible and by using it we can get smaller bundles, easier to debug API, faster compilation and dynamic loading of modules and components.
- The future of Angular with Ivy looks exciting with cool and exciting features like HOC.
- Ivy also sets the ground for Angular Elements to become much more popular in our Angular applications.
- Give it a TRY! It’s just as simple as setting the
Thanks for reading!