Great work @lhz516, thanks for sharing, I’ll give it a try soon to understand it’s behavior (what exactly is loaded when). I’m still on React Router v3, so this will also help me to update.
In Meteor server-render package, there’s no way to do redirection or get cookies for login token from request header. I don’t know if MDG will extend server-render package, but currently the only way seems to use WebApp.connectHandlers for the access of req object from client
I’ve used fast-render auth file to inject the cookie in the request header. Then used the following block of code to retrieve the user object (again from the fast-render package)
// A workaround to pass the request and cookie info
WebApp.connectHandlers.use('/', (req, res, next) => {
const loginToken = req.cookies.meteor_login_token;
if (req.url === '/' && loginToken) {
if (loginToken) {
const hashedToken = loginToken && Accounts._hashLoginToken(loginToken);
const query = {
'services.resume.loginTokens.hashedToken': hashedToken
};
const options = { fields: { _id: 1 } };
user = Meteor.users.findOne(query, options);
loggedIn = true;
}
} else {
loggedIn = false;
user = null;
}
return next();
});
Then at the onPageLoad function I’d check the user and loggedIn variables. It’s working for now, but not sure if this valid for multiple concurrent requests. Ideally we’d have the server render package extended to support this use case, I think you’ve opened a github issue on this.
At the client I’ve used React Loadable to asynchronously load module
import React from 'react';
import Loadable from 'react-loadable';
const AsyncModule = Loadable({
loader: () => import('./module.js').then(ex => ex.default),
loading: () => <div />
});
export default AsyncModule;
And at the router:
<Route name="module" path="/module" component={AsyncModule} />
I only SSR the landing page, login page and the home page for returning visitors and dynamically import everything else.
For the initial data, I inject them with the initial server rendered page using the sink.appendToBody
function.
const encodedData = encodeURIComponent(JSON.stringify(someUserDataArray));
sink.appendToBody(
`<script type="text/injected-data" id='injected-date'}>${encodedData}</script>`
);
and then I use the following code to retrieve them at the client and pass them to the react component.
const injectedData = document.getElementById('injected-date');
if (injectedData && limit.get() <= DEFAULT_LIMIT) {
const data = injectedData.innerHTML;
if (data) {
const injectedPosts = JSON.parse(decodeURIComponent(data));
injectedData.remove();
...
I really think there is a need for a package that make implementing those capabilities easier and your package seems like a good starting point!