The entirety of my app is traditional client-side React, but I have one route/URL in particular that I want to use SSR for, so the user sees something come up much quicker. What can I use, without interfering with the rest of my application?
Can you not set up SSR the normal way, but only render if the route matches the one you want?
Not even sure what “the normal way” is.
What are you using? react + redux + react-router?
I’m about to try and do the same thing. I’ll let you know what I find.
I can help as I have accomplished this, but I need to know what you’re using for routing at the very least.
Right now I just have a client-side routing meteor app with react-router V4.
Check out this example here, except throw an if statement to only do this if it matches the route you want
Won’t be able to help you out there as I haven’t used flowrouter in about 2 years, but the example I provided may help you get a general idea.
Thanks, Brendan! I’m sure I can piece something together. I’ll check it out when I get a few mins.
We’re on Blaze, but using FR, so I think most of this will make sense:
import { WebApp } from 'meteor/webapp';
import { SSR } from 'meteor/meteorhacks:ssr';
const serverRendering = (req, res, next) => {
const pathName = req.originalUrl;
if (pathName.includes('/theTarget/')) {
// If the path matches
const htmlContent = SSR.render('someTemplate', { data });
// This should be a template literal but the formatting was getting messed up
const html = '
<!html>
<head>
<!-- header stuff -->
</head>
<body>
${htmlContent}
</body>
';
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(html);
} else {
// Otherwise, just let your default router handle it
next();
}
});
WebApp.connectHandlers.use(serverRendering);
Great, so I got some basic output thanks to piecing stuff together from the various code snippets above. Thanks! Though the next challenge is: how (if it’s even possible) do I get this to be interactive (event handling, state, etc)? Bear with me, I have zero experience with SSR. AFAIK, the way this works is:
- Server quickly renders out static HTML to the browser.
- Client then loads up, doesn’t have to draw anything since the server already did it, but provides all the reactivity/interactivity.
I’m not sure how to get this working. Below is what I have so far. I think I need a way to call next()
, so that the client side / Flow Router can detect the /ssr
route and render the exact same thing… yes?
import React from 'react';
import { WebApp } from 'meteor/webapp';
import { renderToString } from 'react-dom/server';
class Clicker extends React.Component {
state = {
clicker: 0,
};
increase = () => {
this.setState({ clicker: this.state.clicker + 1 });
};
render() {
return (
<div>
<div onClick={this.increase}>Click this! {this.state.clicker}</div>
</div>
);
}
}
WebApp.connectHandlers.use('/ssr', function(req, res, next) {
const html = renderToString(<Clicker />);
res.statusCode = 200;
res.setHeader('Content-Type', 'text/html');
res.end(html);
});
Why did you end up using connectHandlers
over onPageLoad
?
Now that I’m seeing your use case better, I’m not sure how easily you will be able to hydrate/provide the necessary interactions using the method I posted above. That is definitely geared towards a static html experience. Not saying it can’t be done, that’s just not how we use the implementation I posted.
Because I like keeping my app lean (i.e. don’t add packages unless I absolutely need them). And meteor/webapp
is there for free.
Yeah, with Flow Router handling the low level setup of the routes and injecting an <App />
into the react-root
div, I don’t think this will work. I’ll need to ditch Flow Router if I want to make one of my routes SSR.
@ffxsam there used to be a Flowrouter-SSR implementation IIRC. Maybe there is something in there that could help?! https://github.com/kadirahq/flow-router/tree/ssr