Server-side rendering (SSR) in Meteor

Looking at Meteor’s implementation of SSR + a real-world example

This is a guest post from community member Julian Ćwirko, and was originally published on julian.io.

Not only is the Meteor platform is still alive, it’s constantly being improved! Meteor is becoming a more flexible and complete platform every day, despite proceeding at a slower pace than when the project was younger. For me, the most interesting improvement lately is Server-Side Rendering. In this post I’ll tell you why, and why I especially like it in Meteor.

What we’ll cover here:

Why is Server-Side Rendering (SSR) good to have, especially in Meteor?

How is it implemented in Meteor?

Real-world example in ready-to-use boilerplate

Why is Server-Side Rendering (SSR) good to have, especially in Meteor?

Some time ago, I wrote an article about why I keep coming back to Meteor. I shared that I use Meteor in projects that aren’t that demanding because of some of its limitations; I saw it as the most complete platform that’s very simple to start with. I still believe this is the best platform for fast prototyping, but with recent (and future) improvements I believe it has also become suitable for big apps.

It has ultra-simple deployment options, and the build system works automatically, which is why there are so many devs who like it. And now we have SSR on board along with a couple of other nice features like dynamic imports (but that’s topic for separate article).

Server-Side Rendering is a feature that’s always nice to have in smaller projects that are part apps and part websites, because your site will be accessible to all web crawlers out there and your SEO will shine. Of course Google bots should index your website anyway, but what about Facebook or Twitter bots, what about sharing materials on social services? I always had problems with that, even when building simple projects.

For that reason, having SSR on board with a simple configuration is something I like in every framework. Of course there will be many situations when you may choose not to use SSR because the benefits to not using it are greater: you may want a separated front-end and backend (different servers), or you may just not need it in the app because it will mostly be used internally, or all content and functionalities are available only by private access for logged-in users.

You may be thinking, “So how did it all work before SSR?” There are couple of options. SSR isn’t ultimately a significant improvement. You can implement some workarounds which are also very good: You can use services like Prerender.io, or you can use your own server that generates static websites and serves them for web crawlers only. This is just a matter of choosing what is most valuable in the app you’re building.

So, why do I like SSR in Meteor especially? Because this is the next missing puzzle piece in a very simple-to-start platform without significant configuration needed to get going. You can just focus on coding. With Meteor, I can get not only SSR, but the whole stack, up and running very quickly.

How is SSR implemented in Meteor?

This is the most interesting part of this article, so without further ado, let’s see what it looks like.

First of all, you need a new package called server-render, which needs to be added to your Meteor app. You can do this by writing in the terminal: meteor add server-render . Unlike the dynamic-import package, this one isn’t added when creating a new Meteor app. I think this is good; you’ll be able to decide and add it if only needed.

After you add the package, you need to be sure that your components will be accessible on both the server and client side. I use React, so this is very simple to achieve. (I am not sure how it looks with other view layers like Angular.) Later, you’ll see how I’ve got it structured in my simple boilerplate. I haven’t tested it yet, but the package should work with all modern front-end frameworks that can be integrated with Meteor. For now, let’s see what the API looks like.

So the server-render package exposes onPageLoad method, a callback function which is called with a sink object as parameter. Sink provides useful methods which allow you to modify the HTML that will be served from the server. Basically what we need to do on the server side is to render our main App component to a string using built-in React methods (the standard way of doing SSR with React) and then we can use sink.renderIntoElementById to put the whole HTML in proper place in the body. onPageLoad will always fire when it is needed, so the current source code of the page should be updated. You can use other methods from sink : you can append some elements to the head tag by, for example, using react-helmet on the server (which I’d strongly recommend). This had always been problematic, especially when you wanted to share your content on social services like Twitter or Facebook. In that case, you can now inject Open Graph tags and other meta tags so Facebook or Twitter bots will see them properly, which is very useful.

If you’re interested, you can find the full documentation. Now it’s time to jump into the real example, which is my simple boilerplate. Let’s see how SSR looks like there.

An example in ready-to-use boilerplate

Lately I’ve updated my Meteor boilerplate to be ready for SSR. It also uses Redux, so it’ll be a good opportunity to show how to use Redux and SSR together.

This is a pretty standard boilerplate based on the Meteor Guide, so the folders structure should be simple for every Meteor developer. It may look a little bit overwhelming, but that bunch of the extra code is because of the boilerplate and not because of server-side rendering. Let’s see what we have in there. I have client app initialization and server-side app initialization. I also share React routes and Redux actions and reducers between the server and client.

Let’s see what we have on the server side:

This is where all the magic happens. We need to wrap all the code inthe onPageLoad method just to be able to rerun it and generate new static HTML on every page request. Here we can create the initial state for our Redux store. Then we can create the store and prepare the main component. We use static router configuration here because on the server there isn’t browser history, etc. Another thing which needs to be done is putting the initial state into our static HTML code. We do this using sink.appendToBody method from server-render package. All main code is generated using React’s renderToString and then it is injected into the app div element using sink.renderIntoElementById .

Now let’s see what we have on the client side:

As you can see, I use Redux, so when using SSR I can get the initial state for the store on the server and pass it in the static generated HTML. This is recommended way. Here on the client side, I just get the initial state from a special object injected into the body. You’ll see how it’s done above. Then I create the Redux store with initial data and prepare standard main App component with routing. I use React Router 4 here. This is all you need on the client side for now.

What else can we do here? Of course, we could inject some meta tags, like Open Graph tags, or just a title and description for every page by using the react-helmet library. We’d use the Helmet.renderStatic method which returns data that then can be appended to the tag of our static document. This will give us different data for every page. We use the sink.appendToHead method to be able to do that.

That’s basically it! Having this API, we are able to configure SSR in a very simple way. This is another part of Meteor which makes the platform very nice to use for any developer. Let me know what you think and how you use it in your projects.