codelord.net

Code, Angular, iOS and more by Aviv Ben-Yosef

Avoiding ng-include for Elegance and Performance

| Comments

ng-include might seem like an innocent, helpful directive. After all, it allows us to break down a big template into simpler chunks, which makes code more readable, right?

Personally, I never liked ng-include or used it, but I didn’t care much if I saw code that made use of it. But years ago I found out that in addition to being a kind of code smell, ng-include also has a pretty significant performance hit. Since then I’ve religiously made sure my clients stay clear of it.

And yet, whenever I start working on another Angular codebase it’s always there like clockwork – another whole slew of ng-includes.

So, today, we will see why you shouldn’t be using it, for elegance and for performance!

ng-include is a code smell

I know most people use ng-include because it “makes code clearer” or “makes templates easier to maintain”. But come on, does it, really?

Look at this:

1
2
3
4
5
<div>
  <div ng-include="'header.html'"><div>
  <div>Some things go here</div>
  <div ng-include="'footer.html'"></div>
</div>

If you think that this will be easier to maintain, you’re wrong. In fact, what we just did is break a single component to have its template spread across 3 different places.

Want to make a change in the component’s controller to refactor an object? Make sure to track down all the sub-templates that use it to change it there, too.

The indirectness between the component and its newly-split template makes for a very common pitfall. I’ve seen these break and cause bugs in production so many times, because it’s the easiest thing to miss when you quickly scan a template file and do a search for the name of a variable you just changed. You simply don’t expect it to be used elsewhere.

Also, if what you’re saying is that your component’s template is so big you need to break it down, why not create a new component to make it smaller?

Most of the times, it’s not just the template that’s getting bigger, since things aren’t static. You may be making the template files shorter, but in the background we’ll have a controller that’s growing bigger and bigger, with way more responsibility than it aught to have.

My rule of thumb is that if I feel like something is getting too big, I’ll break it down to smaller components, not just try to sweep parts of the template under the rug.

But even you don’t agree, performance will kill you

I was actually very surprised when I first saw this while debugging performance issues in a big app a few years ago. And this has yet to change.

ng-include is just way slower than using a directive/component instead. Yeah, even though components create new scopes and actually introduce more watches, they are faster.

Benchmarks shows that if you have a lot of ng-includes on a screen, initial loading time of these sub-templates will be about 50%-60% longer than if you’d use plain sub-components.

And it doesn’t stop at initial loading. Once everything is one the screen, even though using a subcomponent easily doubles the amounts of watches, the impact of using ng-include on the digest cycle can be a whopping 100% increase. Yes, your average digest cycle can take twice as long, simply because of that, making everything in your app feel slower and laggy.

It’s even as simple as replacing:

1
2
3
<div ng-repeat="todo in $ctrl.todos">
  <div ng-include="'todo.html'"></div>
</div>

With:

1
2
3
<div ng-repeat="todo in $ctrl.todos">
  <todo todo="todo"></todo>
</div>

This alone, with a big enough todos list, will show you initial loading taking seconds longer, and digest cycles twice as slow. You can see it for yourself, compare this ng-include option with this sub-components option. On the upper left corner you will see ng-stats running and displaying the digest cycle time. At least on my machine this shows ng-include as 27ms components 14ms on Chrome (93% more), and 4.3ms vs 1.6ms in Safari (169% more!).

So please, stay away from ng-include. Not using it is a simple win-win – code that’s more resilient to breaking, easier to maintain, and more performant.

“Maintaining AngularJS feels like Cobol 🤷…”

You want to do AngularJS the right way.
Yet every blog post you see makes it look like your codebase is obsolete. Components? Lifecycle hooks? Controllers are dead?

It would be great to work on a modern codebase again, but who has weeks for a rewrite?
Well, you can get your app back in shape, without pushing back all your deadlines! Imagine, upgrading smoothly along your regular tasks, no longer deep in legacy.

Subscribe and get my free email course with steps for upgrading your AngularJS app to the latest 1.6 safely and without a rewrite.

Get the modernization email course!

Comments