With the changes in the new version of Lighthouse, we saw our pages drastically dropped in score as compared to the last version (version 6 vs version 5)
This forced us to take a look again at how we are loading our pages and worked hard during the last couple of weeks to change the structure of our meteor pages.
Here are some learnings that might help other users of Meteor and React
react-router to identify and cache the inline-css of different routes (although the pages are dynamic, each route normally displays the same page structure (i.e. the same critical css); used staticContext for cases where a page structure changes depending on some variable)
fast-render-like data handling: we did not use fast-render in this case but the idea is the same. When generating the SSR page, we attached the data from the static context to the generated HTML page. During react hydration, the data is being used to hydrate the page and not query from the server
Sample pages:
Feedback welcome so we can further improve our pages
Would sending the main CSS bundle with HTTP/2 push headers be just as good?
I am personally wary of using CSS in JS, because of the runtime overhead, even if it speeds up page load. (Even though I do use it on my main app - mostly because Material-UI uses JSS.)
but with respect to “performance last”: css in js is usually much cleaner, easier, more flexible and maintainable then pure css (or even scss). I would value that much higher than some runtime overhead (unless you are some tech giant where every milisecond matters)
My pattern is still very modular - I have an SCSS file right next to my component definitions in the file hierarchy, it’s just included in a main SCSS bundle instead of the JS, and all delivered at once instead of piecemeal through JS. Every file has a “root” class/id to keep things modular. CSS in JS always seemed like overkill to me.
From experience, the blinking problem (white-screen flicker) is caused by the following in a component:
React render -> componentDidMount -> query data -> callback with results -> setState with the results -> re-render
We solved this issue by ensuring that componentDidMount will not run any data query function because the state already has the data from the SSR page. Without data query, no setState, no re-render. Therefore, it is just hydration in the initial load.
You need to make sure the SSRed page looks exactly the same as what the client will initially render which is done by injecting the data in the page and using it for the initial load.
As you know, I do something similar with Vue - just for sales landing pages, not product pages. What’s the trick in removing the flash once Vue/React take over the DOM? In my case I don’t think I need data-hydration because these are effectively static pages.
Hi, I am updating a Meteor app we’ve been maintaining for years, thanks a lot for this summary with recent sources!
One question I have with Loadable: code-splitting in Meteor seems to be very tied to dynamic loading. I guess this make sense from a technical standpoint, in the scenario where you navigate through links in the SPA.
Yet for a big application, I hit some limitations. For instance, I’d like some public facing pages to have their own separate bundle. Currently, this would be dynamically importing 99% of the app so this public facing page is not “polluted”. Is that the sign that I need 2 apps? Is there a solution with one app to handle this scenario?
To give a concrete setting: we have a backoffice to setup forms, and a page to display the form for end users. Both are deeply tied, so one application is a good fit, yet both have very different performance requirement. Should I dynamically the whole backoffice just to boost the page that displays the form?
In our case, all our “admin stuff” is separated into its own app.
For the app above, it has huge members-only modules that use code-splitting. Previously, it was separated into its own app but maintainance becomes a headache and we ended just joining the guest and members only into one app with separate admin-only app
But in terms of code-splitting, it can really make the decision easier to join modules into one app