Vulcan/packages/vulcan-routing/lib/server/routing.jsx
Al Pagan 48ad632bf3 Add callbacks to vulcan:routing SSR hooks
This method allows for access to the SSR app component and associated css in the routing's hook functions without needing to hack core files.

This makes it possible, for example, to add MUI wrapper components and inject compiled css with the JSS library (see https://material-ui-1dab0.firebaseapp.com/guides/server-rendering).

Here's how I'd implement the callbacks in my own custom module: https://gist.github.com/wayfarerboy/96c0f1d13b3b7d3d2743501a1c7c0187
2017-10-13 14:20:20 +01:00

76 lines
2.6 KiB
JavaScript

import React from 'react';
import Helmet from 'react-helmet';
import { getDataFromTree, ApolloProvider } from 'react-apollo';
import { Meteor } from 'meteor/meteor';
import {
Components,
addRoute,
Routes, populateComponentsApp, populateRoutesApp, initializeFragments,
getRenderContext,
runCallbacks,
} from 'meteor/vulcan:lib';
import { RouterServer } from './router.jsx';
Meteor.startup(() => {
// note: route defined here because it "shouldn't be removable"
addRoute({name:"app.notfound", path:"*", componentName: 'Error404'});
// init the application components and routes, including components & routes from 3rd-party packages
initializeFragments();
populateComponentsApp();
populateRoutesApp();
const indexRoute = _.filter(Routes, route => route.path === '/')[0];
const childRoutes = _.reject(Routes, route => route.path === '/');
const indexRouteWithoutPath = _.clone(indexRoute);
if (indexRouteWithoutPath) {
delete indexRouteWithoutPath.path; // delete path to avoid warning
}
const AppRoutes = {
path: '/',
component: Components.App,
indexRoute: indexRouteWithoutPath,
childRoutes,
};
const options = {
historyHook(req, res, newHistory) {
let { history } = getRenderContext();
history = runCallbacks('router.server.history', history, { req, res, newHistory });
return history;
},
wrapperHook(req, res, appGenerator) {
const { apolloClient, store } = getRenderContext();
store.reload();
store.dispatch({ type: '@@nova/INIT' }) // the first dispatch will generate a newDispatch function from middleware
const app = runCallbacks('router.server.wrapper', appGenerator(), { req, res, store, apolloClient });
return <ApolloProvider store={store} client={apolloClient}>{app}</ApolloProvider>;
},
preRender(req, res, app) {
runCallbacks('router.server.preRender', { req, res, app });
return Promise.await(getDataFromTree(app));
},
dehydrateHook(req, res) {
const context = runCallbacks('router.server.dehydrate', getRenderContext(), { req, res });
return context.apolloClient.store.getState();
},
postRender(req, res) {
runCallbacks('router.server.postRender', { req, res });
},
htmlHook(req, res, dynamicHead, dynamicBody) {
const head = runCallbacks('router.server.html', Helmet.rewind(), { req, res, dynamicHead, dynamicBody });
return {
dynamicHead: `${head.title}${head.meta}${head.link}${head.script}${dynamicHead}`,
dynamicBody,
};
},
};
RouterServer.run(AppRoutes, options);
});