Created
July 9, 2018 10:58
-
-
Save jeffwillette/93be211a78b7f43a08b305e887c3ddd6 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { ApolloClient } from 'apollo-client'; | |
import { ApolloLink } from 'apollo-link'; | |
import { ApolloProvider } from 'react-apollo'; | |
import { InMemoryCache } from 'apollo-cache-inmemory'; | |
import { JssProvider } from 'react-jss'; | |
import { renderToString } from 'react-dom/server'; | |
import { withClientState } from 'apollo-link-state'; | |
import React from 'react'; | |
import { defaultState } from './src/state/defaults'; | |
import { resolvers } from './src/state/local/resolvers'; | |
import getPageContext from './src/getPageContext'; | |
// this is for the usage of redux | |
// see https://github.com/mui-org/material-ui/blob/master/examples/gatsby/gatsby-ssr.js | |
// to see how the MUI SSR works | |
export const replaceRenderer = ({ bodyComponent, setHeadComponents, replaceBodyHTMLString }) => { | |
const client = createSSRClient(); | |
const pageContext = getPageContext(); | |
const bodyHTML = renderToString( | |
<JssProvider registry={pageContext.sheetsRegistry} generateClassName={pageContext.generateClassName}> | |
<ApolloProvider client={client}>{React.cloneElement(bodyComponent, { pageContext })}</ApolloProvider> | |
</JssProvider> | |
); | |
replaceBodyHTMLString(bodyHTML); | |
setHeadComponents([ | |
<style | |
type="text/css" | |
id="server-side-jss" | |
key="server-side-jss" | |
dangerouslySetInnerHTML={{ | |
__html: pageContext.sheetsRegistry.toString() | |
}} | |
/> | |
]); | |
}; | |
const createSSRClient = () => { | |
const cache = new InMemoryCache(); | |
const stateLink = withClientState({ | |
cache, | |
resolvers, | |
defaultState | |
}); | |
const client = new ApolloClient({ | |
cache, | |
link: ApolloLink.from([stateLink]), | |
connectToDevTools: false | |
}); | |
client.onResetStore(stateLink.writeDefaults); | |
return client; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createGenerateClassName, createMuiTheme, Theme } from '@material-ui/core'; | |
import grey from '@material-ui/core/colors/grey'; | |
import indigo from '@material-ui/core/colors/indigo'; | |
import { SheetsRegistry } from 'react-jss'; | |
export interface PageContext { | |
theme: any; | |
sheetsManager: Map<any, any>; | |
sheetsRegistry: any; | |
generateClassName: any; | |
} | |
interface CustomTheme extends Theme { | |
text: { | |
white: string; | |
}; | |
} | |
const theme = createMuiTheme({ | |
palette: { | |
primary: indigo, | |
secondary: grey, | |
error: { | |
light: 'rgba(128,0,0,.9)', | |
main: 'rgba(128,0,0,.9)', | |
dark: 'rgba(128,0,0,.9)', | |
contrastText: '#FFFFFF' | |
}, | |
background: { | |
default: '#FFFFFF' | |
} | |
}, | |
text: { | |
white: 'rgba(255,255,255,.5)' | |
}, | |
overrides: { | |
MuiButton: { | |
root: { | |
borderRadius: 5 | |
} | |
}, | |
MuiPaper: { | |
root: { | |
boxShadow: | |
'0px 1px 1px -1px rgba(0, 0, 0, 0.2),' + | |
'0px 3px 1px -1px rgba(0, 0, 0, 0.14),' + | |
'0px 1px 1px -1px rgba(0, 0, 0, 0.12)' | |
}, | |
rounded: { | |
borderRadius: 5 | |
} | |
} | |
} | |
}); | |
const createPageContext = (): PageContext => { | |
return { | |
theme, | |
// This is needed in order to deduplicate the injection of CSS in the page. | |
sheetsManager: new Map(), | |
// This is needed in order to inject the critical CSS. | |
sheetsRegistry: new SheetsRegistry(), | |
// The standard class name generator. | |
generateClassName: createGenerateClassName() | |
}; | |
}; | |
interface Process { | |
browser: any; | |
} | |
declare var process: Process; | |
interface Global { | |
__INIT_MATERIAL_UI__: any; | |
} | |
declare var global: Global; | |
const getPageContext = () => { | |
// Make sure to create a new context for every server-side request so that data | |
// isn't shared between connections (which would be bad). | |
if (!process.browser) { | |
return createPageContext(); | |
} | |
// Reuse context on the client-side. | |
if (!global.__INIT_MATERIAL_UI__) { | |
global.__INIT_MATERIAL_UI__ = createPageContext(); | |
} | |
return global.__INIT_MATERIAL_UI__; | |
}; | |
export default getPageContext; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'typeface-roboto'; | |
import './index.css'; | |
import { Grid, withStyles } from '@material-ui/core'; | |
import { IntlProvider, addLocaleData } from 'react-intl'; | |
import { compose } from 'recompose'; | |
import PropTypes from 'prop-types'; | |
import React from 'react'; | |
import en from 'react-intl/locale-data/en'; | |
import zh from 'react-intl/locale-data/zh'; | |
import { Viewer } from '../../state/remote/components'; | |
import Notifications from '../Notifications/notifications'; | |
import locales from '../../locales'; | |
import withRoot from '../../withRoot'; | |
addLocaleData([...en, ...zh]); | |
const styles = () => ({ | |
pageContent: { | |
padding: 15 | |
} | |
}); | |
// this is the main entrypoint for the layout to the site | |
const GlobalLayout = ({ locale, children, classes }) => { | |
return ( | |
<IntlProvider locale={locale} messages={locales[locale]}> | |
<Viewer> | |
{viewer => { | |
return ( | |
<Grid container className={classes.pageContent}> | |
{/* the one of the children is a FullWidth or AppDrawer component, that | |
* component decides how to display the header and the drawer based on the | |
* device width. The following components after children have to be | |
* responsive to both | |
*/} | |
{children} | |
<Notifications /> | |
</Grid> | |
); | |
}} | |
</Viewer> | |
</IntlProvider> | |
); | |
}; | |
GlobalLayout.propTypes = { | |
children: PropTypes.oneOfType([PropTypes.array, PropTypes.object]), | |
locale: PropTypes.string, | |
classes: PropTypes.object | |
}; | |
export default compose( | |
withRoot, | |
withStyles(styles) | |
)(GlobalLayout); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import CssBaseline from '@material-ui/core/CssBaseline'; | |
import { MuiThemeProvider } from '@material-ui/core/styles'; | |
import PropTypes from 'prop-types'; | |
import React from 'react'; | |
import getPageContext, { PageContext } from './getPageContext'; | |
interface Props { | |
pageContext: PageContext; | |
} | |
const withRoot = (Component: React.SFC) => { | |
class WithRoot extends React.Component<Props, {}> { | |
public pageContext = {} as PageContext; | |
constructor(props: any, context: any) { | |
super(props, context); | |
this.pageContext = this.props.pageContext || getPageContext(); | |
} | |
public componentDidMount() { | |
// Remove the server-side injected CSS. | |
const jssStyles = document.querySelector('#server-side-jss'); | |
if (jssStyles && jssStyles.parentNode) { | |
jssStyles.parentNode.removeChild(jssStyles); | |
} | |
} | |
public render() { | |
// MuiThemeProvider makes the theme available down the React tree thanks to React context. | |
return ( | |
<MuiThemeProvider | |
theme={this.pageContext.theme} | |
sheetsManager={this.pageContext.sheetsManager} | |
> | |
{/* CssBaseline kickstart an elegant, consistent, and simple baseline to build upon. */} | |
<CssBaseline /> | |
<Component {...this.props} /> | |
</MuiThemeProvider> | |
); | |
} | |
} | |
return WithRoot; | |
}; | |
export default withRoot; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment