This never made much sense to me. My total CSS package is generally under 40K, and it’s only 1 extra request. On PixStori it’s only around 7.8KB - though much of the app CSS framework is JSS from Material-UI - even though I’ve been actively moving away from JSS overrides in component code - at runtime, it’s SO SLOW. My apps start and run noticeably faster if I do it this way. If it’s really that much of a concern for Google, I suppose I could inline the CSS content in the HTML, or send an http/2 header or something. I guess in some sites where they just have a ton of extra CSS that might be an issue, but my apps aren’t typically overloaded that way. ymmv.
JSS is the worst idea I have encountered in a very long time, its apparent popularity never ceases to amaze me. I am totally fine with a single CSS bundle; it’s Lighthouse/Google who’s complaining about it, not me. Especially in the context of an SPA a single cacheable CSS makes totally sense – far more so than inline CSS in html head or similar. Thing is, I feel forced to dance to Google Search’s tune. I’m just looking for a solution to avoid my app getting penalized by Google for what they like to see as “bad practice”.
The new core web vitals introduced by Google months ago will be affected.
-
The blocking css call affects the loading of the major content of the site.
-
One way to solve this is to defer the loading of the css file. But that will affect another metric which is the shifting of elements in the page as they are loading which is a bad experience
The solution we did is inlining css for the initial page loaded by the user while deferring the css file for the rest of the SPA
I was going to say - just inline the one main CSS bundle to the HTML page output, and you’re done. But I don’t know how to do that in Meteor…
Yeah, JSS is not my favorite - I honestly keep looking for a way to simply remove it from Material UI - I wish they’d get rid of that thing… Material UI has a lot of value though, so I tolerate it. But I don’t use it myself.
Given these new core web vitals, Meteor’s single blocking css bundle is becoming increasingly questionable. I’m wondering about Google’s reluctance to acknowledge SPAs as being different in many aspects from traditional web applications, but realistically, when it comes to policy making, Google has the status of a deity that just doesn’t listen to ordinary mortals’ earthly concerns.
Following the principle of 'if the mountain will not come to Muhammad, then Muhammad must go to the mountain, we may have to find a suitable solution to be built into Meteor, along the lines of the solution you mentioned.
We are also doing AMP. And Google has a limit to the “size” of the css that you can inline
If anybody is interested, @wildhart has a fantastic solution to this. That is what we followed for our implementation
Of course they do…
Why didn’t you mention ways to use CSS in JS, such as styled- Components? It’s so cool, you have to try it if you get the chance
It breaks prerendering completely.
I use JSS in some Material-UI projects to a minimum extent - I don’t like it, as it takes longer for page refreshes during development, and there is a runtime overhead, even in production (sometimes quite noticeable overhead). I prefer to just use SCSS directly.
BTW, it doesn’t break SSR, but you have to wire it up in your SSR code. (There are similar tutorials for styled components.)
I don’t have SSR, just prerendering with a headless Chrome. In that configuration JSS hopelessly breaks everything.
Is that through puppetteer? I can see how that would mess with stuff. Why not use SSR techniques?
I’ve actually been thinking about how to do AOT (ahead of time) rendering (or static pre-rendering as they call it) in Meteor like NextJS does. It wouldn’t be that hard to make spin up a Meteor instance, then run a list of routes against it to get some output, and capture that. I find puppetteer
to be problematic, but proper static rendering (either through SSR or AOT techniques like Next uses) clean everything up nicely, because it makes the purpose of execution clear. (I’ve even used react-snapshot
a bunch, and it was also more reliable that various other puppetteer solutions - and it just runs jsdom - at least in my limited experience).
More challenging might be to do partial build like Next can. I suppose as long as the SSR output is configured with the right kind of output, it should be possible to diff that output based on triggers. It’d be harder to pull off in Meteor though, because we don’t have methods like getServerSideProps
and getSstaticProps
which can be run outside of any React code. It would probably not be too hard to create a package to add something like that though.
We use prerender and, apart from problems with JSS, it’s working really just fine. We serve the search engines with the prerendered snapshots from redis via nginx.
With respect to SSR I failed completely and utterly. I’ve read various guides of how other folks do it, and I admit I didn’t understand any of it. It feels like an intellectual barrier I’ve hit with full speed.
I agree that SSR is not easy with Meteor - possible, but not easy. The way they do it in Next is a bazillion times easier, but it required implementing an entirely different routing paradigm (they don’t use React Router). I kind of wonder whether Meteor should have something like that - we almost did back in the day with Flow Router, though its goals were not to facilitate SSR and code splitting the way next/router does. Still, it would be even better in Meteor, given Meteor’s perfect code splitting. I’m thinking a lot about this lately.
I should say though - SSR in Meteor is not harder than platforms like Express.js - it’s just not as easy as Next.js
BUT - there are trade offs. Nextjs is not as flexible with how you put things together as Meteor is. Meteor can literally SSR anything. With Nextjs, you have to use their special data methods and/or block SSR/Static rendering in order to gain the full advantage - and it’s all tightly coupled with React.
You are right, I just wanted to say, more needs to be done in this area
I agree completely. I’m trying to do a quick project using methods which fetch data from 3rd party APIs - and the SSR story there is anything but simple.