How I sped up the initial render of my Polymer app by 86%

Marcus Hellberg
3 min readJun 26, 2016

--

I was trying to optimize the startup time of my Polymer application (Expense Manager) and realized that the main reason it took so long to render was that even though the user lands on the login page, the browser was busy setting up the main page that wasn’t even visible yet. In addition, I had all my Polymer elements in one bundle file that needed to get loaded before anything could get shown.

Here’s what I did to speed up the first meaningful render from about 2,200ms to just over 300ms on localhost.

Unoptimized: First meaningful paint took about 2,200ms on localhost.

Step 1: Split the bundle

The first step was to ensure that I’m not loading more than needed for the initial login screen render. The way I decided to do that was to adapt my application to the new project structure that Polymer CLI uses. With this structure, instead of one bundle containing all the elements in the entire app, I got two bundles, one that just contained the components needed to show the login page, and one that contained the rest.

Splitting up the bundle and deferring the load of the second bundle until navigation sped up the load time considerably. But there was one new issue that it brought with it. Now, after logging in, I had a brief flash of empty screen before the new bundle was actually downloaded and rendered.

Step 2: Load the second page in the background

While searching for ways to fix the flicker, I stumbled upon an undocumented feature in Polymer, a callback that gets called after a given component has finished rendering.

Polymer.RenderStatus.afterNextRender(this.$.login, () => {
this.importHref(this.resolveUrl(‘overview-page.html’),
null, null, true);
});

With this callback, I was able to begin downloading and rendering the overview page as soon as the login page was rendered. Because users are slow compared to computers, this meant that by the time the user actually logs in, everything is already set up for them and the transition is instant.

Optimized: First meaningful paint takes just over 300ms on localhost. Most of the heavy lifting happens while the user is performing the login.

Step 3: Fetch data only once render is complete

One final optimization I did using the same trick was to delay the Pouch DB setup until the second page was fully rendered. This way, the user gets quick visual results and the overall experience feels snappier .

Polymer.RenderStatus.afterNextRender(this, () => {
this._setupDB();
});

Conclusion

Polymer.RenderStatus.afterNextRender gives you a simple way to defer things that need to get done soon, but that don’t need to get done in the next render.

You can find the demo online at: https://wc.demo.vaadin.com/expense-manager/ and source code at https://github.com/vaadin/expense-manager-demo

--

--

Marcus Hellberg

Developer Advocate at Vaadin. Working mostly on Progressive Web Applications and Polymer.