Meteor server side rendering is about to become much easier


#1

Gotta love it when @benjamn gets curious and ends up dropping a PR like this …

What does this mean? A quick react based usage example:

main.js:

import React, { Component } from 'react';
import { render } from 'react-dom';

class Welcome extends Component {
  constructor(props) {
    super(props);
    this.state = {
      name: '',
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState({ name: event.target.value });
  }

  welcome() {
    return this.state.name ? <strong>Welcome {this.state.name}!</strong> : null;
  }

  render() {
    return (
      <div id="welcome">
        <form>
          <label>
            Name? <input name="name" onChange={this.handleChange} />
          </label>
        </form>
        <p>
          {this.welcome()}
        </p>
      </div>
    );
  }
}

if (Meteor.isClient) {
  import { render } from 'react-dom';
  render(<Welcome />, document.getElementById('app'));
}

if (Meteor.isServer) {
  import ReactDOMServer from 'react-dom/server';
  import DOM from 'react-dom-factories';

  WebAppInternals.registerBoilerplateDataCallback(
    'loadWelcome',
    (data, request, arch) => {
      const div = DOM.div({
        id: 'app',
        dangerouslySetInnerHTML: {
          __html: ReactDOMServer.renderToString(<Welcome />)
        }
      });
      data.body = ReactDOMServer.renderToString(div);
    }
  );
}

The <Welcome /> component here will be fully rendered server side and returned to the browser first (helping out things like search engines, page load times, etc.). Then when state manipulation comes into play, the client side component takes over. I’m just scratching the surface here, but this really opens up a lot of possibilities! :tada:


Serving different html for different useragents
SSR alternative to abandoned flow-router-ssr? (React)
#2

I would have expected this post to get a gazillion likes within the first hour, given all the heated discussions around arguably “how hard ssr is on meteor”


#3

With the server-render package that I just pushed to that PR branch, your Meteor.isServer case can be simplified:

if (Meteor.isServer) {
  import { renderToString } from 'react-dom/server';
  import { renderIntoElementById } from 'meteor/server-render';
  // This assumes a container element with id="app" exists on the page,
  // which can be ensured using (for example) the static-html package.
  renderIntoElementById("app", request => renderToString(<Welcome />));
}

Further explanation.


#4

Nice benjman! this is awesome, looks much cleaner and very easy to use :smiley:


#5

Can’t wait to use this!


#6

This is super exciting news indeed!


#7

This looks amazing! Can’t wait to use this!


#8

What’s the use case for this?


#9

@aadams These changes open up Meteor’s server side rendering capabilities in a big way. With regards to the benefits of using server side rendering (and for an example use case), check out: The Benefits of Server Side Rendering Over Client Side Rendering (which outlines the performance benefits Walmart gets from server side rendering a lot of their content).

There are definitely pros/cons to server side rendering (see Client-side vs. server-side rendering: why it’s not all black and white for a good breakdown), but these changes add yet another awesome tool to the Meteor toolbox that developers can leverage as needed.

@viejo You won’t have to wait much longer - these changes are coming in Meteor 1.5.1!


#10

Will this technique be added to the guide and to an example app (preferably a complex one)?

I’m very curious how server side rendering will work with a complex app with multiple pages and routes.


#11

:slight_smile:


#12

What about data? Is it automatically managed?


#13

This looks like a great feature, but it would have made more sense to put it in 1.6 just so that the fixes to issues found in the 1.5 release (one of which was a showstopper for me) could be released sooner as part of the 1.5.1 release. I haven’t been able to run version 1.5 since it was released a month ago. I thought the third number in the semver format is meant to be for bug fixes, whereas the second number indicates new features.


#14

Thanks @tab00 - as of right now this feature is slotted to be released in 1.5.1, but things can definitely change. A few things to add however:

  • Meteor releases do not follow semver.
  • The focus of the 1.6 release is almost exclusively the upgrade to Node 8. As you can imagine, there are a lot of internal changes being incorporated into 1.6, so the addition of extra features is trying to be avoided, as much as possible.
  • The upcoming server side rendering changes weren’t really planned ahead of time. They came out of the work that’s underway to remove Meteor’s server side dependency on Blaze. For the full backstory see PR #8820, but long story short - during the review for that PR, the idea of adjusting things to better facilitate SSR was discussed, and PR #8841 was born. We could consider waiting to push these changes out after 1.6, but given that they will be tied into other pending PR’s, it might make sense to get them out sooner than later.

The above being said, what 1.5 problems are you seeing? Is there a specific GH issue you can reference?


#15

Thank you for the response and explanation.

This one that was opened over a month ago (which you had responded to):


#16

Awesome news! Can’t wait for the update.


#17

Great news indeed!
https://github.com/ssrwpo/ssr has done a great job recently for ssr, especially their upcoming v3 (the develop branch, which is already stable). Their concept to hydrate and rehydrate the data seems pretty cool to me (https://ssrwpo.github.io/ssr/SSR/). Maybe, some pointers could be drawn from them, but it would be definitely awesome to see how this in-house ssr handles data.

Great work @benjamn!


#18

Really? Meteor (React) SSR?
Best day ever


#19

What about Vue support?


#20

The new api is completely independent of whatever ui library you want to use. It basically gives you access to the lifecycle of the request/response and the html that’s sent down to the client along with a chance to change it. It is up to you to use plain javascript/react/blaze/vue/whatever to inject that html.