The Glimmer Binary Experience | LinkedIn Engineering


Co-authors: Sarah Clatterbuck, Chad Hietala, and Tom Dale

A bit over a year ago, Ember.js got a major overhaul. In a tight collaboration between LinkedIn engineers and the open source community, we replaced Ember’s rendering engine with a new library, Glimmer VM, that improved performance and significantly reduced the size of compiled templates.

Glimmer treats Handlebars templates as a functional programming language and compiles them into a sequence of instructions that can be executed in the browser. These instructions, or opcodes, are encoded in a compact JSON data structure.

When we migrated our linkedin.com web application to use Glimmer, we saw dramatic improvements in load time. In addition to reducing over-the-wire size by 40%, compiling templates into JSON allowed us to reduce the amount of time the browser spent parsing JavaScript. Overall, this change improved load times at the 90th percentile by over one second.

In this blog, we will discuss a recent experiment to improve load times even further by entirely eliminating the cost to parse compiled templates.

Unlocking experimentation with Glimmer.js

About six months ago, the Ember.js team announced the release of Glimmer.js as a standalone component library. Breaking off the view layer empowered us to experiment with bringing all the goodness of Ember and the Glimmer VM to developers creating lighter-weight experiences, like mobile apps for emerging markets, or SEO pages.

The break out of Glimmer has unlocked a lot of experimentation by our team in the subsequent months. Recently, for example, we introduced hybrid rendering, where HTML is generated with server-side rendering (SSR) and “rehydrated” in the browser. This is just the beginning of the performance benefits afforded by Glimmer’s virtual machine architecture.

The holy grail of web performance is the ability to load quickly for first time visitors, to update quickly when the user takes action (preserving 60fps performance), and to provide performance by default, meaning that large teams with less experienced developers can build performant web apps without significant intervention.

Traditionally, there has been a tension between delivering minimal JavaScript to enable instant loads and the ability to have a sophisticated, responsive UI. It seems like a fundamental tradeoff that as an app grows larger, performance or productivity suffers. With Glimmer, our goal is to build apps that are lightweight, fast, and productive. One of the keys to achieving that goal is to reduce the cost of each new component added to an application.

Instant templates

While switching from JavaScript to JSON reduces the cost of parsing compiled templates, we’ve combined Glimmer with cutting-edge browser features to eliminate the parse step entirely.

When optimizing load time, most developers tend to focus on reducing file size to make downloads faster. In a JavaScript-based web application, however, startup performance is also impacted by the browser’s ability to parse, compile, and evaluate your code. And significantly, on a mobile device, parsing and compiling JavaScript can be 2-5x slower than on desktop computers. This step alone can easily take up a big chunk of your performance budget.

Today, the majority of frameworks compile their view layer abstraction to JavaScript functions. The cost of parsing this JavaScript is often hidden, as it sneaks up on applications slowly as they add more and more features. As mentioned above, Glimmer today compiles templates into a sequence of opcodes that are transmitted to the browser as JSON. Because the JSON grammar is much simpler than the JavaScript grammar, a JSON parser can be up to 10× faster than a JavaScript parser when parsing the same data.

But this still means that parse times will increase as template size grows, just at a slower rate. What if we could bypass the parse step altogether?

In the last few years, browsers have become really great at handling binary data. With low-level APIs like ArrayBuffer, JavaScript programs can handle binary data as fluently as their native counterparts. We took advantage of this fact to compile templates into our own bytecode format that the Glimmer virtual machine can execute directly. Similar conceptually to something like the JVM bytecode format, Glimmer bytecode is a platform-agnostic binary format that encodes the Glimmer VM’s instruction set as a bytestream of opcodes and their operands. Instead of being bottlenecked by JSON or JavaScript parsing performance, now we are only limited by the browser’s ability to copy raw bytes from the network.

Encoding Glimmer bytecode

Like many VMs, instructions in the Glimmer VM are identified by numbers. Bytecode is just an encoded sequence of these numbers. What makes Glimmer unique is that its instruction set is designed for rendering DOM in the browser.

For example, a template of <h1>Hello World</h1> would be compiled to the following JSON “wire format” at build time:



Source link