How to use server-render with blaze-html-templates?

I can make server-render work by removing blaze-html-templates and adding static-html. So far so good, but I have an app that has React and Blaze sections. How can I use server-render with blaze-html-templates? It’s okay if only the React routes are SSR’d.

My code is:

import { Meteor } from 'meteor/meteor';
import React from "react";
import { renderToString } from "react-dom/server";
import { onPageLoad } from "meteor/server-render";
import { App } from "/imports/App";

onPageLoad(sink => {
  sink.renderIntoElementById("app", renderToString(
    <App />
  ));
});

It doesn’t SSR if I remove static-html and add blaze-html-templates.

2 Likes

The sink.renderIntoElementById function and its friends just want a string at the end of the day, so how you do it is up to you.

In this case, you might be more interested in using Spacebars instead of Blaze, since you do not need re-rendering, etc. Check out this package and example:

Spacebars.toHTML({ name: 'foo' }, '<p>Hello {{name}}</p>');

The issue above would be in holding big templates. However, we can work around it by placing HTML files somewhere in Meteor’s ./private folder and using Assets.get(’’) to retrieve them as strings.

renderToString(<App />) is working fine. The problem is that sink.renderIntoElementById isn’t injecting the html/string because apparently it doesn’t find the element app without static-html.

1 Like

Oh man I completely misread the question. I thought the example was from the README.

I believe static-html is a separate thing from Blaze. As the package explains, it’s Meteors utility to ‘define static page content in .html files’

https://atmospherejs.com/meteor/static-html

@benjamn have any thoughts on this?

The static-html package adds head.html and body.html files to the .meteor/local/build/programs/web.browser/ directory, and that’s what the server-render package is operating on.

It looks like Blaze takes full control of rendering the contents of <body> on the client, which is a bit disappointing (though this should have been anticipated). It would be better if Blaze generated a static body.html file with the top-level skeleton of your app, which would allow server-render to inject HTML into the parts of your page that aren’t rendered by Blaze, while still allowing Blaze to interpolate HTML into {{> template}} blocks.

It’s unfortunate that you can’t use static-html at the same time as blaze-html-templates, but I suppose the next best alternative is to merge static-html into blaze-html-templates, so that an .html file with no {{> template}} blocks is effectively the same as an .html file as static-html would handle it.

2 Likes

Hi everyone,

I try to get it working using react-viewmodel with the ViewModelExplorer component, but this last one does not want to be rendered server-side (error: windows is not defined)

So I wanted to only add this component server-side, but I don’t know what to do.
I tried this:

Imports/App.js

if (Meteor.isClient) {
  const ViewModelExplorer = process.env.NODE_ENV === 'production' ?
    (() => null)
    : require('viewmodel-react-explorer').ViewModelExplorer;
}
if (Meteor.isServer) {
  const ViewModelExplorer = null;
}

App({
  render() {
    <div>
      <ViewModelExplorer />
      <h1>It Works!</h1>
      <Person />
      <Big b="defer: true" />
    </div>
  }
})

Server/main.js:

import { Meteor } from 'meteor/meteor';
import React from "react";
import { renderToString } from "react-dom/server";
import { onPageLoad } from "meteor/server-render";
import { App } from "/imports/App.js";

onPageLoad(sink => {
  
  const ViewModelExplorer = null;
  sink.renderIntoElementById("app", renderToString(
    <App />
  ));
});

Do I really need to create 2 App components, one for the server and one for the client?

You should use the same component on the server. In this case it seems like a problem with ViewModel Explorer. I’ll fix it.

I also noticed that the defer binding on a component would prevent SSR from loading it.
Do you think SSR destroys the purpose of defer entirely? Or would there still be a use case for defer with SSR?

Update to viewmodel-react-explorer v1.0.14. You don’t need to do different things client/server. On your App.js:

const ViewModelExplorer = process.env.NODE_ENV === 'production' ?
  (() => null)
  : require('viewmodel-react-explorer').ViewModelExplorer;

App({
  render() {
    <div>
      <ViewModelExplorer />
      <h1>It Works!</h1>
      <Person />
      <Big b="defer: true" />
    </div>
  }
})

server/server.js

import { Meteor } from 'meteor/meteor';
import React from "react";
import { renderToString } from "react-dom/server";
import { onPageLoad } from "meteor/server-render";
import { App } from "/imports/App";

onPageLoad(sink => {
  sink.renderIntoElementById("app", renderToString(
    <App />
  ));
});

As far as I can tell there’s nothing else to do on the client.

As for defer + SSR, it behaves the same on the server as it does on the client. If you have a big component that you’re deferring, then it won’t show up on the SSR’d html, it will be loaded after the page is rendered. If you want the big component to appear on the initial html (SSR’d) then there’s no need to defer the loading on the client (the html is already there).

Hope it helps.

1 Like

Perfect, thanks for your really helpful intervention.
PS: I find the ViewModelExplorer really nice but it is not documented in vm doc itself. It may be worth having a section (next to your VScode extension for example)

See you

So the conclusion is that server-render cannot be used if you have any Blaze in your project?

3 Likes

I’d like to know the same.

1 Like

+1 to elle’s question

Or is there a timeline (if at all) to merging static-html into blaze-html-templates?

When is this going to happen ? I think we should have this in Blaze if we’re Meteor !

2 Likes

Are there any updates on this?

Or is there another way to use Blade Templates as well as Server-Side-Rendering with React?

1 Like

Most of my components have been migrated to react already. But the last few are blocking SSR implementation because I cannot even add static-html. Even though the root components are all React.

=> Started proxy.
=> Errors prevented startup:

   While determining active plugins:
   error: conflict: two packages included in the app (templating-compiler
   and static-html) are both trying to handle *.html