mirror of
https://github.com/vale981/Vulcan
synced 2025-03-11 13:06:41 -04:00

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
79 lines
2.9 KiB
JavaScript
79 lines
2.9 KiB
JavaScript
import React from 'react';
|
|
import { ApolloProvider } from 'react-apollo';
|
|
import { applyRouterMiddleware } from 'react-router';
|
|
import { useScroll } from 'react-router-scroll';
|
|
|
|
import { Meteor } from 'meteor/meteor';
|
|
|
|
import {
|
|
Components,
|
|
addRoute,
|
|
Routes, populateComponentsApp, populateRoutesApp, runCallbacks, initializeFragments,
|
|
getRenderContext,
|
|
} from 'meteor/vulcan:lib';
|
|
|
|
import { RouterClient } 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);
|
|
delete indexRouteWithoutPath.path; // delete path to avoid warning
|
|
|
|
const AppRoutes = {
|
|
path: '/',
|
|
component: Components.App,
|
|
indexRoute: indexRouteWithoutPath,
|
|
childRoutes,
|
|
};
|
|
|
|
const options = {
|
|
rehydrateHook(data) {
|
|
const initialState = data;
|
|
const context = getRenderContext();
|
|
context.initialState = initialState;
|
|
const apolloClientReducer = (state = {}, action) => {
|
|
if (initialState && initialState.apollo && !_.isEmpty(initialState.apollo.data) && _.isEmpty(state.data)) {
|
|
state = initialState.apollo
|
|
}
|
|
const newState = context.apolloClient.reducer()(state, action);
|
|
return newState;
|
|
}
|
|
context.addReducer({ apollo: apolloClientReducer });
|
|
context.store.reload();
|
|
context.store.dispatch({ type: '@@nova/INIT' }) // the first dispatch will generate a newDispatch function from middleware
|
|
runCallbacks('router.client.rehydrate', { initialState, store: context.store});
|
|
},
|
|
historyHook(newHistory) {
|
|
let { history } = getRenderContext();
|
|
history = runCallbacks('router.client.history', history, { newHistory });
|
|
return history;
|
|
},
|
|
wrapperHook(appGenerator) {
|
|
const { apolloClient, store } = getRenderContext();
|
|
const app = runCallbacks('router.client.wrapper', appGenerator({
|
|
onUpdate: () => {
|
|
// the first argument is an item to iterate on, needed by vulcan:lib/callbacks
|
|
// note: this item is not used in this specific callback: router.onUpdate
|
|
runCallbacks('router.onUpdate', {}, store, apolloClient);
|
|
},
|
|
render: applyRouterMiddleware(useScroll((prevRouterProps, nextRouterProps) => {
|
|
// if the action is REPLACE, return false so that we don't jump back to top of page
|
|
return !(nextRouterProps.location.action === 'REPLACE');
|
|
}))
|
|
}));
|
|
return <ApolloProvider store={store} client={apolloClient}>{app}</ApolloProvider>;
|
|
},
|
|
};
|
|
|
|
RouterClient.run(AppRoutes, options);
|
|
});
|