1) Lazy loading and Prefetching
A method of loading modules in the application upon user request. Example case of that is the usage of modals or tooltips. There is no need to load all of the modules whenever the page loads. If a modal or such modules are not shown with a page load, they should be lazy-loaded.
Standard way of importing
Whenever a module is imported in a standard way. It will be added as a node of a main.js in the dependency graph and bundled with it.
Lazy Loading
This way webpack will bundle the content of the dynamically imported module into a separate file. Which will be used upon a request.
Route-based lazy loading with vue-router
Dynamically imported components on the routes work the same way and reduce the overall size of the bundle which does have huge impact on the performance of the application.
This is done automatically on Nuxt
The drawback of lazy-loading on UX
Although lazy loading saves some bytes and increases performance of the initial load, the lazy loaded modules are still needed for the application to work properly. Those modules need to be downloaded at the point of interaction, which means the user will have to wait for the module to be downloaded to be able to see it (ex. a modal). If the module is doing a heavy work that would take more than 100ms according to RAIL model guidelines is too much to wait.
That’s where Prefetch comes into play.
Prefetching
Prefetching in simple words, is just downloading certain resources that may be needed in a future before they are requested by the browser. In our case this might be a lazily loaded modal window or a lazily loaded route. For example if we’re in a page of the application, we could prefetch any other pages that the user has a high chance of visiting.
What’s important is that the prefetching will only start after the initial load is completed and the browser becomes idle. This way prefetching does not affect the page load speed or the interactivity of the loaded page.
Prefetching on Vue and Nuxt
With Nuxt every
2) Optimizing Third-Party Dependencies
The code that we write by ourselves is just a small piece of our production bundle. Most of its content is filled with third-party dependencies. A simple library, can in fact, contain more code than your whole application!
We usually do a lot of different optimizations in our own code hoping that they will make our apps faster when in reality it’s not our code that makes them slow - it’s others code!
We can analyze the build bundle by using “webpack-bundle-analyzer” package or adding the “—report” parameter to the build script of the vue-cli.
Using minified versions of imported UI components
Before Minify | After Minify |
---|---|
app (3.01 MiB) | app (2.77 MiB) |
3) Caching
Have you noticed that pages that you’re visiting most often are loading a little bit faster than other ones? This is happening because our browsers are smart enough to cache files that will be potentially useful in the future.
Caching is a process of storing commonly-used data in a quick to access memory so it can be used immediately after its requested. Because of that our browsers can sometimes omit the network and immediately access files that we regularly use from our own machine.
Browser Caching
When the cache headers are done correctly on the backend, the browser will automatically cache the results in Memory Cache (persists until the browser is closed) which is stored in RAM and in Disk Cache which persists much longer but is stored in a hard drive that takes much longer to access.
We can retrieve files from browser cache only when we have a stable network connectivity. No matter what we have in there if we’re offline we will always see “No Internet” page.
Service Workers and Cache API
The Cache API is a system for storing and retrieving network requests and their corresponding responses. These might be regular requests and responses created in the course of running your application, or they could be created for the purpose of storing data for later use.
Service Worker, in short, is a JavaScript code that runs a different thread than your app and acts like a Proxy between the browser and the network. It means that we have full control over network requests and responses in our web app! We can change request URL, parameters or even the response.
With Service Workers and Cache API we can programmatically serve certain files that we have previously put in the cache as responses to specific network requests.
Caching with Workbox
Mastering Service Workers and Cache API could be a time-consuming process but thankfully there is a great library that allows us to benefit from these browser features without learning it’s complicated APIs - Workbox. Workbox configuration can be edited further to cache not only the static files (css,ico,png,html,js) but also the dynamic requests (png,jpg,jpeg,svg,json) which will drastically improve the performance of the application.
4) Optimizing and Compressing Images
Images contribute a lot to the application’s bundle size. When the app renders the images with considerable sizes can increase the app’s loading time. What we can do is optimize the way to serve images. And for that, we can locally compress the images or use CDNs.
5) Reduce Unnecessary CSS
On the application, we often might have CSS that are not being used but take up space. There are libraries like “PurgeCSS”.
“To optimize the whole, we must sub-optimize the parts.”
Before and After Optimization Results of Mojob’s Homepage