Hello there, I tried to initiate Server Side Rendering with server-render package from @benjamn and this worked well until I try to use it with Universal Router.
My problem is on the server you guess:
main.js (server)
import { Meteor } from 'meteor/meteor';
import React from "react";
import { renderToString } from "react-dom/server";
import { onPageLoad } from "meteor/server-render";
import UniversalRouter from 'universal-router/legacy';
// legacy because node version of meteor makes it crash otherwise
import { App } from '../imports/App';
import { Big } from '../imports/Big/Big';
import { Fourofour } from '../imports/404/404';
Meteor.startup(() => {
// code to run on server at startup
});
const routes = [
{
path: '/',
action() {
return {
title: 'App',
component: <App />
};
}
},
{
path: '/about',
action() {
return {
title: 'About us',
component: <Big />
};
}
},
{
path: '*',
action() {
return {
title: '404',
component: <Fourofour />
};
}
}
];
const router = new UniversalRouter(routes);
function renderLocation(thisSink) {
router.resolve({path: thisSink.request.url.path}).then(route => {
console.log (route.component)
console.log(route.title)
//This is working and returning valid title and component
thisSink.renderIntoElementById("app", renderToString(
<Big />
));
// NOT WORKING !! sink.renderIntoElementById
// will fail silently in this context (no error in the console)
});
thisSink.renderIntoElementById("app", renderToString(
<Big />
));
// This is working here !!
}
onPageLoad(sink => {
//Wrap all the code in onPageLoad method just to be able to rerun it and generate new static HTML on every page request
renderLocation(sink);
});
As you can see I cannot render my hard-coded â<Big / >â component because server-render fails to execute within the promise.
The create container is creating problems, since, the above code worked for a very simple App with no containers or subscriptions
I am getting an error such as:
TypeError: Meteor.subscribe is not a function
in the terminal
Would you know what is happening or what mistake am I making
Hi tomsp
For the server render, is not everything from the client going to be processed in a âserverâ way, and since all collections are already present with the server, wonât it ignore the Meteor.subscribe?
Or is there some other way to handle the createContainer part in the server-render
I was not able to figure out in the docs
Thanks
Itâs working when autopublish is turned on and on removing the subscriptions from the client side
Which i feel is a bit improper a solution, i do not wish to publish all data everywhere, there should be a workaround right?
The problem is resolved.
I put all the subscriptions in Meteor.isClient block, so yeah the subscriptions shouldnât run on the server at all, even if the code is present on the client and one is using it for server-render, the Meteor.isClient block should be provided for the codes which might cause error on server render
Glad you figured it out! My answer was going to be: you have to return a Promise from the callback function passed to onPageLoad if you want the server to wait for async work to finish.
In case youâre still having problems, I think you may need to return a Promise from your renderLocation function, rather than just calling router.resolve:
function renderLocation(thisSink) {
return router.resolve(...);
}
Thanks @benjamn, indeed this was the trick to make server-render work with universal router on the new Meteor version.
I used not to return router.resolve(..) and just call router.resolve(..) in renderLocation(sink) which worked OK on Meteor 1.5 but caused performance issue on 1.6 for some reason.
The simple trick to return the promise works super good, and is the way we should work with async/await: the await renderLocation(sink) means âawait this Promiseâ so make sure to return the promise in the renderLocation function