Google's Lighthouse score and how to improve loading times of Meteor apps

Seeking help of the community on tips to speed up Meteor apps in general and more specifically our own app.

Seems it’s not possible for a Meteor app to get a decent score on Lighthouse. I’ve tested the following Meteor apps:

http://www.kanyetothe.com/ 23/100
https://kadira.io/ 30/100
http://www.sfr.fr/ 30/100
http://www.telescopeapp.org/ 33/100
https://codefights.com/ 40/100
https://www.meteor.com/ 42/100
http://www.dnagenealogy.tools (our own website): 47/100

Although we do have the best score I don’t consider 47 being good. We do have over 7 seconds until first meaningful paint is done, that’s from what I read industry practice on the web, but Google sets the goal at 1.6 seconds.

More information on Lighthouse: https://developers.google.com/web/tools/lighthouse/

Any idea on best practice and what can be done to achieve a higher score of Google’s Lighthouse (and similar websites testing performance) as well as decreasing time to meaningful first paint is highly appreciated. Especially some low hanging fruits :wink:

4 Likes

Hopefully some of these strategies could help

SO question

I Think there was also an update on the forum about the same question not long ago but haven’t found it doing a quick search

1 Like

The question Lighthouse in Nov 2016 didn’t address how to improve the score unfortunately. It just explained what Lighthouse is and PWA

Oh I see, I actually found the thread, slow visits and there are some updates on how to improve the frist render times from @benlavalley, thought not sure if that directly translates into more points for lighthouse

1 Like

@a4xrbj1 I’ve just run your page through Lighthouse and you got a performance rating of 67.
I’m not sure how much of that increase will be due to us running Lighthouse on different machines but, none-the-less, it looks like you’ve made some very decent performance improvements. Bravo :clap:

What steps did you take to achieve this?

Now with Meteor 1.5 you can use dynamic imports to decrease page load times and the bundle size.

Agree but this is with Meteor 1.4

It just takes a lot of work, use these tools and follow their advices. We don’t even use a CDN :wink:

Hey Matt, you can achieve this by using WebApp.connectHandlers.use() what you basically do is tell Meteor to render a static page as your Landing page, that will avoid loading all the minified code the first time then it will load all the minified code after its ready, which will speed up the loading speed/scores. I had some help from @benlavalley as he first came with the idea of doing this to modify how meteor renders the contents for the first time, here’s a code example, Warning: it only works for production, so whenever you test run meteor --production

Code Example (Server side code):

import { SSR } from 'meteor/meteorhacks:ssr';
import { Inject } from 'meteor/meteorhacks:inject-initial';

SSR.compileTemplate('landing', Assets.getText('html/landing.html'));

const tempFunc = function () {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = '/assets/foo.js';
    document.getElementsByTagName('body')[0].appendChild(script);
};
let convertedLoadFunc = tempFunc.toString();
convertedLoadFunc = convertedLoadFunc.replace('function tempFunc() {', '');
convertedLoadFunc = convertedLoadFunc.replace('}', '');
convertedLoadFunc = convertedLoadFunc.split('/assets/foo.js');
const lightSpeedOne = convertedLoadFunc[0];
const lightSpeedTwo = convertedLoadFunc[1];

Inject.rawModHtml('lightSpeedJS', function (htmlVar) {
    let html = htmlVar;
    let scripts = html.match(/<script type="text\/javascript" src.*"><\/script>\n/g); // get all scripts
    if (scripts) {
        scripts = scripts.join('');
        let scriptReplace = scripts.replace(/<script type="text\/javascript" src="/g, lightSpeedOne);
        scriptReplace = scriptReplace.replace(/"><\/script>\n/g, lightSpeedTwo);
        html = html.replace(/<script type="text\/javascript" src.*"><\/script>\n/g, ''); // remove all scripts.
        html = html.replace(/<body>/g, '<body>\n' + SSR.render("landing"));
        html += `<script> window.onload = function () {${scriptReplace}};</script>`; // now replace with these!
    } else {
        console.log(`lightSpeed error: unable to find any scripts to process. htmlVar is : ${htmlVar}`);
    }
    return html.replace(/[\n]+/g, '\n').replace(/ +/g, ' ');
});

Also now that there’s Meteor 1.5 you can use Dynamic Imports, which should be less “hacky” but this will work if you’re not ready to update to 1.5

Hope that helps!
Greetings!

3 Likes

Thanks very much!
I’m currently in the process of refactoring my code so that I can make use of dynamic imports. But this is really cool and it’s nice to have a back-up option!

Do you think that Lighthouse scores likely affect search rankings?

Yes, search rankings are positively influenced by loading times, especially on mobile. Google is ranking those pages higher