Future proof SSR?

Which is the future of SSR in Meteor? Moving to Apollo and using React-Router?

Are there any other options?

1 Like

I asked a similar question on Jan 4th:

It’s really sad to see so many core feature packages becoming unmaintained. SSR is vital for SEO.

This one has 4 mainteners, is in active development, is used in production : https://github.com/ssr-server/ssr

:wink:

6 Likes

And by the way, it has a TTL cache for SSR rendering allowing it to serve payload under 1ms. Even less when a user returns thanks to e-tag & cache-control. Not too bad. Meteor is a real beast thanks to its fiber implementation :zap:

How does implementing SSR differ in vanilla react stack vs meteor?

Almost no difference. Meteor is a Node equipped with node-fiber. What you do on vanilla Node + Express is seamless as what you do with Meteor + Express.

What we are doing with this project is easing the integration, doing the best practices as far as we can & provide an advanced caching mechanisms. Think of 304, TTL and things alike.

The biggest difference is in store hydration.

Most state stores / data stores in the react ecosystem provide hydration libraries that are easy to plug in.

In Meteor you need something that does similar, such as fast-render, that is assuming you use meteor’s pub/sub system (which I’m considering leaving out of my next project… It is optional you know).

Without store hydration your lovely SSR’d page would go away once React kicks in, only to reappear later.

He, he, that’s the trick. Store re-hydratation with data from Collection.Observe. Allowing to go back on reactivity when you need it and where other frameworks can’t.

It is. Though I’ve been moving more to Apollo lately, and since it’s a redux based tool, store rehydration is already available, and Apollo has notification based reactivity which is really nice, it’s lightweight so performance is great even on mobile, and we’ve been able to handle on one apollo server what was taking 3-5 nodes of meteor!

That’s because you were solely relying on collection’s reactivity. Pub / sub is too often used though actually not required. Apollo is pretty useable on Meteor and even described in Apollo’s dev docs.

When you want to scale, your data strategy is at the core of your concerns. After all, Meteor is just a Node with fibers and a massive number of helpers for live query, hot loading, building, pub/sub… “Meteor lightens the burden of reactivity” should not mean that you should only use it when you’re not requiring it. My two cents.

@pierreeric, SSR-server does it overlap in functionality with Fast-Render?

Is it compatible with Apollo? or do they overlap in functionalities?

Fast-render is different beast, which I do not recommend as it has been discontinued. It hooks deeps in Meteor so that it can perform subscriptions on behalf of the client, server side. And by hooking, I mean, it rewrites some major part of subscriptions.

While the idea is clever, in the long term, it cannot work. Each new Meteor release puts you in the risk of having a dead project. Better get off with it.

Apollo provides a different data strategy: no pub-sub. Meaning no reactivity. Meaning no accounting on the initial rendered payload. A must for SSR and SEO. Currently, our package doesn’t use Apollo but 2 of our contributors have stepped in to include Apollo integration in this package. Currently, with the v1 release, it’s doable. When done, it will not be doable, it will be easy :smile:

1 Like

Apollo alone is not enough of a solution. However because it uses Redux, it’s trivial to get store rehydration setup for Apollo.

Fast render doesn’t actually go that deep (I’ve modified it myself heavily for special purposes). The simple fact is that it covers a glaring omission in meteor pub/sub construct (the go to for meteor data even per the docs right now). Every major client store library on the market now has a rehydration construct built in. Meteor pub/sub does not. Even if SSR was made available for blaze, getting pub/sub to work is painful.

I think you dramatically misunderstand what I’m saying and also what is “standard” in Meteor. Meteor’s reactivity (pub/sub, minimongo) is pervasive. This is lauded as a hallmark, but it is also dangerous, especially at scale. That deep reactivity causes all sorts of potential issues from render thrashing to high load on servers when users have dramatically different data sets.

Apollo fixes these problems, and a stack that is based on Apollo/React/Redux is actually far more stable under load, and performs better. Also such a stack can easily use React-Router-SSR (not the meteor version) which is still supported and works great. It can also use just about any other standard routing platform. I actually recently made the dramatic move of removing webapp from my main project I’m working on, taking it to the point where meteor is my bundler and build system only. I’m using my own hot code reload implementation over Apollo, and otherwise am using Apollo/React/Redux in place of pretty much everything meteor in meteor.

Meteor is great, and I’m not leaving anytime soon, but time has told the tale of how dangerous reactive everywhere is. React pushes the idea of higher order components which are reactive and using the diff tree.

That said, we’ve moved off the main subject. Back on the original subject:

My future proof SSR:

  • React
  • React Router SSR
  • Redux
  • Apollo
  • All running on Express w/ websocket with autoreconnect package from Meteor.

With that I literally have everything I need, all of the same functionality as Pub/Sub/Methods/Minimongo without any of the overhead, and the code is actually LESS boilerplate.

1 Like

My bad. I did not mean any bashing at all. Your path is exactly the one that we have chosen. Currently we are doing:

  • React
  • React route 4 & SSR
  • Redux
  • Express
  • Meteor
  • Sitemaps
  • Robots.txt
  • REST & Webhooks API
  • In memory caching with TTL

We have plan for Apollo, Electrode caching, above the fold, cache pre-filling, Application Cache API, Service workers and code splitting.

May I had also, a “à la” Next routing is in the way. Scaffolding for creating router’s hierarchy is in the way.

Could you please provide a link the the react-router-ssr that is still maintained? Cheers

You can use inject-initial to inject raw meta tags into the head when loading a specific route - you’ll have to regexp req.url but it works without too much hacking.

1 Like

Thanks for pointing me to this package. I am wondering why nobody else mentioned this in any of the SEO questions I found so far. It seems to be exactly what you need for that purpose.

We’ve been using it on production for about six months so far, no probs. We also use it to inject some data to display immediately upon app start rather than wait for a subscription to fetch the same stuff again, seeing how it’s fetched when doing the meta tags anyway. :slight_smile: Depending on your situation you could even render out some of the HTML serverside to render along with the page. Personally I don’t think you need to return anything below the fold from the server - full page SSR is unnecessary in most cases. Some routes don’t need SSR at all. Some require more logic than others, and benefit from different kinds of caching.

It’s also useful otherwise. For multi-tenant apps (subdomain.foo.com, subdomain2.foo.com being different realms in the same app), you can inject the realm ID (user ID, company ID, what-have-you…) resolved from the subdomain right into the document upon app start to use as a limiter for queries. If you don’t have a Very Large list of things to resolve, and they’re fairly static, you can build some crude cache (if not found in list, fetch and insert for next time kinda thing) which is what we did with the subdomain resolution. Doesn’t eat much memory, and gets reset when the server updates, which is about the right amount of retention time in our case.

We return real 404s with a server-only page this way too, btw. For example, we have an app on Galaxy responding at *.domain.com, where company1.domain.com serves data for company1, company2.domain.com would serve data for company2, and if a name doesn’t exist, it returns a real 404 through the connect result.

Oh, we also use it for feeds - works great with XML. Cron generates a mongo doc which is the latest feed result every 5 minutes, so the route just does a .findOne() and returns the document text, which is super fast. :slight_smile:

Is there something, those, who forsaken the runic art of redux could get in use?