Optimizing Ember Templates

Templates make up 60% of your Ember app. Now what?

When source code goes through a compiler or transpiler, it’s easy to create a disconnect between the perceived weight of a piece of code and its actual size in the shipping product.

This is especially true with Ember templates, where small changes can have a profound impact on the amount of JavaScript that is generated.

“Every byte matters.” 
 — Every Front-end Web Developer
 (after exhausting the other ways of optimizing app startup)

Conditional Blocks are Expensive

Consider a component template that renders two paragraphs, the second is conditionally rendered using an #if helper:

The total size of the generated code for this component is 3.8 KiB, surprisingly large! Where does all the code come from?

Each template is converted into a JavaScript module at build time. Each module contains the logic, code and data needed to create the DOM and populate its children and values (sample below).

The surprise here is in the way the conditional IF block is compiled. It turns into a full template child, almost as large as the parent template, complete with metadata and rendering functions of its own (shown in red).

Generated JavaScript for Template with Conditional IF

The {{#if}} helper is very easy to use, and mentally it’s a lightweight solution to a conditional situation. However, behind the scenes each conditional block is actually represented by the same infrastructure as an entire new template.

If instead we conditionally hide the paragraph element using a class name it removes half the generated code and saves 1.2 KiB off the total app size!

This may seem like a controversial way to optimize a template, but it illustrates the general concept that we will continue to explore: small changes can save a lot of code, sometimes at the expense of maintainability 
and readability.

Using a dynamic class removes an entire template child

Avoid Repetitive IF/Else using Loops

A more complex template involving a series of If/Else statements shows how generated code can become even larger. Every conditional block is converted into a child template the same size as the red text in the example above. So while this looks like one template, it’s actually eight.

We can refactor this component using a #each loop and move the creation of the instrumentList array into javascript:

Even when accounting for the additional JavaScript needed to build the instrumentList, the new implementation saves 12 KiB of code.

Computed Properties

Another technique for avoiding conditional blocks in templates is to move the work into computed properties. In the example below you save more than 50% of the component size by calculating the displayed value in JavaScript.

SVG In Templates

SVG also increases in size when used in templates. This SVG file renders a checkmark inside a circle; the source is 298 bytes but compiles to 2.2 KiB of JavaScript!

  • Remember to run the SVG through a minifier like SVGO before adding it to your template.
  • Manually inspect the result to cleanup any additional unused attributes.
  • You can safely omit the xmlns and version attributes on inline SVG.

Better yet, try moving the SVG into an external file and referencing it as a background image or as the source for an <img> tag. It will save the cost of the entire template, a wise choice if it’s rarely used. Sometimes you can even create the same image using CSS!

Use the Component’s Implicit Tag

Every Ember component has an implicit wrapping tag that can be used for styling and layout. Even though it’s not defined in the template, you can customize that tag using the component’s JavaScript file.

In the Loop example above we can optimize out the wrapping tag 
<section class=’instruments-container’> by modifying our component:

Any template with a single top level element in the template is a candidate for using the implicit component tag instead. This technique also helps reduce the number of nodes in the DOM.

Extend Components instead of Wrapping

When adding new functionality to an existing component it can be tempting to wrap the base component in a new template and relay all the attributes. This has the unfortunate side effect of creating a new template file, and can often be avoided entirely by extending the existing component:

Extending an Existing Ember Component

Going Further

Understanding the Ember template compiler helps make these techniques more intuitive. A quick way to go deeper is to implement the same template in multiple ways and compare the results. You can use a diff tool to see how the final output compares and which method works best for your scenario. Happy templating!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.