Optimizing Vue for Speed, Performance, and Core Web Vitals

Posted on June 17, 2021

Last week I gave a talk at AlpineDay entitled "From Vue to Alpine: How & Why".

In the talk I shared a few situations in which I've moved applications that were previously using Vue to use Alpine instead, for the sake of Google's Core Web Vitals. These sites were using Vue for light enhancements on top of a server-rendered app, and I found that Alpine is lighter to load and parse in these cases.

I still stand by everything I said in the talk. However, a large swath of the Internet discovered my slides, hadn't heard the talk, and assumed I was badmouthing Vue.

So, I wanted to write a post about how we can optimize our usage of Vue for this same scenario! How do we minimize Vue's impact on the Core Web Vitals?

When Vue is too heavy

In my talk, I described working on the Tighten website to improve its Core Web Vitals scores.

For that particular site, we were using Vue for some very small components, and the combination of Vue's loading time and the components' initial processing time in the browser led to a significant delay for loading the page.

I discovered I could solve our problem by replacing those components with Alpine components, and realized — and then gave a talk about this idea — that Alpine is an ideal fit, even for a Vue-loving agency like ours, for enhancements above vanilla JavaScript and below heavy dashboards and SPAs.

Gimme my Vue!

However, many of our sites — and likely yours, if you're reading this — are ideal for Vue, so we're not just going to drop it. Instead, let's look: can we optimize our page load speeds?

There's a whole group of answers that have to do with code splitting and async loading, which you can find a link to down at the bottom of this post. But there are two strategies that are very similar to what I talked about in my talk, so they're the ones I'm going to cover in this talk.

Making Vue load faster

If you define your Vue components inline in your HTML (rather than in single-file components), it turns out this requires a heavier (larger file download) and slower (more processing power spent) version of Vue. This version has an in-browser compiler, which causes the impact to load size and processing time.

I talked briefly with Evan You, the creator of Vue, who taught me that the "runtime-only" version (meaning, with no compiler) of Vue is 2/3rd the download size of the full Vue. He also gave me two ideas for how we can shrink Vue's load size and processing time.

1. Pre-compile your templates and use the "runtime" Vue build

As I mentioned above, if Vue is going to have to compile Vue component definitions from your HTML, it has to include an in-browser compiler, which makes the script file larger and the processing time take longer.

So, your first step is to use a build tool (like Laravel Mix), pre-compile your templates, and then use the "runtime-only" build of Vue.

How to pre-compile your templates

"Pre-compiling" in this scenario means using single-file .vue components that you then process with your build tooling. These files are compiled into JavaScript, so the end user isn't delivered HTML that needs to be parsed, but a JavaScript file ready to be executed.

"Not pre-compiling" simply means placing your Vue template inline in your HTML; this may be convenient (and some times it's even necessary), but if you work this way you can't drop to the smaller Vue file.

Using the runtime-only build in Laravel Mix

In Laravel Mix, you can switch to the runtime-only build by passing {runtimeOnly: true} to your mix.vue() call:

mix.vue({runtimeOnly: true})

Using the runtime-only build from a CDN load

If you're using a CDN to load Vue (which I assume is unlikely if you're pre-compiling your templates, but what do I know?), your link likely looks something like this:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14"></script>

However, you can get a minified version easily (which you should do no matter what):

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>

And if you are pre-compiling your templates, you can ask for the runtime-only version by appending runtime after vue in the file name:

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.runtime.min.js"></script>

Using the runtime-only build elsewhere

If you use other build tooling, you'll want to modify your build script from pulling the vue.whatever.js file to the vue.runtime.whatever.js file. You can take a look at Laravel Mix's source here to see how they do it.

2. For light enhancements, don't mount to the larger app

Evan also shared another tip for speeding up Vue, especially when it comes to the processing time it takes on each page load.

If you're working with a server-rendered app and just adding a light touch of Vue here and there, don't mount to the body or a master #div. If you do, Vue has to parse your entire application's body content and replace it with a new DOM on every page load.

Rather, bind Vue individually to just the spots where it's needed. Move from this:

new Vue({
    el: "#app",
});

to this:

new Vue({
    el: "#hamburger",
});

new Vue({
    el: "#sliders",
});

And more...

There are a ton of additional considerations you can look at to improve your Vue applications' performance. These are just two that have very specifically to do with initial load time and processing.

Here are a few other worth digging into. There's a fantastic series on VueSchool called Vue.js Performance, which I would recommend and have linked in several of these items.


Comments? I'm @stauffermatt on Twitter


Tags: vuejs

Subscribe

Quick links to fresh content, and more thoughts that don't make it to the blog