import { CodeSurfer, CodeSurferColumns, Step, } from "code-surfer"; import { condensed } from 'mdx-deck/themes' import { github, vsDark } from "@code-surfer/themes";
export const themes = [ condensed, vsDark, { colors: { text: '#FFF', background: "#000" }, styles: { CodeSurfer: { title: { backgroundColor: "#000", color: "#FFF" }, code: { backgroundColor: "#000" }, pre: { backgroundColor: "#000" } } } } ]
Senior Front-End Engineer @ H-E-B Digital
- Why SSR?
- SSR at H-E-B Digital
- How to SSR your app
- Resolve your data internally
- Ship only what the client needs
- Defer javascript parsing after rendering
- Webpack Code Splitting
- Univeral Component Library
- React Router
- Styled Components
- React Helmet
Decoupling our Java Monolith
- API for SSR React components
- Returns markup, critical CSS and JS
- Sets up a shared Redux and Apollo context
- Decouples UI from our Java Application
{
"components": {
"Header": {
"component": "Header",
"props": {
"searchTerm": "apples"
}
},
"Footer": {
"component": "Footer"
}
},
"state": {
"cartItems": 5
}
}
{
"preload": "<link rel=\"preload\" href=\"Header.5438fe62fe34bb6f2a65.js\" as=\"script\" />",
"styles": "<style data-styled data-styled-version=\"5.0.0\">body {...}</style>",
"components": {
"Header": "<div data-heb-key=\"Header\">...</div>"
"Footer": "<div data-heb-key=\"Footer\">...</div>"
},
"state": "<script type=\"text/javascript\">window.__PRELOADED_STATE__ = {...}; </script>",
"scripts": "<script type=\"text/javascript\" src=\"Header.5438fe62fe34bb6f2a65.js\" defer=\"defer\">"
}
- Full page routes with code splitting
- Same components as rendering service
- Fully decoupled from our Java Application
import { Provider as ReduxProvider } from "react-redux";
import { ApolloProvider } from "@apollo/react-hooks";
import { ThemeProvider } from "styled-components";
export function WrappedApp({ apolloClient, reduxStore }) {
return (
<ThemeProvider>
<ApolloProvider client={apolloClient}>
<ReduxProvider store={reduxStore}>
<Routes />
</ReduxProvider>
</ApolloProvider>
</ThemeProvider>
);
}
import { renderToString } from 'react-dom/server';
const application = renderToString(
<App />
);
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
const store = createStore();
const application = renderToString(
<App store={store} />
);
const state = store.getState();
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
import { ServerStyleSheet } from "styled-components";
const store = createStore();
const sheet = new ServerStyleSheet();
const application = renderToString(
sheet.collectStyles(
<App store={store} />
)
);
const state = store.getState();
const styles = sheet.getStyleTags();
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
import { ServerStyleSheet } from "styled-components";
import flushChunks from 'webpack-flush-chunks';
import { flushChunkNames } from 'react-universal-component/server';
const store = createStore();
const sheet = new ServerStyleSheet();
const application = renderToString(
sheet.collectStyles(
<App store={store} />
)
);
const state = store.getState();
const styles = sheet.getStyleTags();
const chunkNames = flushChunkNames();
const { js } = flushChunks(clientStats, { chunkNames });
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
import { ServerStyleSheet } from "styled-components";
import flushChunks from 'webpack-flush-chunks';
import { flushChunkNames } from 'react-universal-component/server';
const store = createStore();
const sheet = new ServerStyleSheet();
const application = renderToString(
sheet.collectStyles(
<App store={store} />
)
);
const state = store.getState();
const styles = sheet.getStyleTags();
const chunkNames = flushChunkNames();
const { js } = flushChunks(clientStats, { chunkNames });
return `<!doctype html>
<html>
<head>
<title>My Application</title>
${styles}
</head>
<body>
<div id="root">${application}</div>
<script type="text/javascript">
window.__PRELOADED_STATE__ = ${JSON.stringify(state).replace(/</g, '\\u003c')};
</script>
${js}
</body>
</html>`;
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
import { ServerStyleSheet } from "styled-components";
import flushChunks from 'webpack-flush-chunks';
import { clearChunks, flushChunkNames } from 'react-universal-component/server';
const store = createStore();
const sheet = new ServerStyleSheet();
const application = renderToString(
sheet.collectStyles(
<App store={store} />
)
);
const state = store.getState();
const styles = sheet.getStyleTags();
const chunkNames = flushChunkNames();
const { js } = flushChunks(clientStats, { chunkNames });
sheet.seal();
clearChunks();
return `<!doctype html>
<html>
<head>
<title>My Application</title>
${styles}
</head>
<body>
<div id="root">${application}</div>
<script type="text/javascript">
window.__PRELOADED_STATE__ = ${JSON.stringify(state).replace(/</g, '\\u003c')};
</script>
${js}
</body>
</html>`;
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
import { ServerStyleSheet } from "styled-components";
import flushChunks from 'webpack-flush-chunks';
import { clearChunks, flushChunkNames } from 'react-universal-component/server';
import { createClient } from 'client/create';
const client = createClient();
const store = createStore();
const sheet = new ServerStyleSheet();
const AppTree = <App store={store} apolloClient={client} />
await getDataFromTree(AppTree);
const application = renderToString(
sheet.collectStyles(AppTree)
);
const state = store.getState();
const styles = sheet.getStyleTags();
const chunkNames = flushChunkNames();
const { js } = flushChunks(clientStats, { chunkNames });
sheet.seal();
clearChunks();
return `<!doctype html>
<html>
<head>
<title>My Application</title>
${styles}
</head>
<body>
<div id="root">${application}</div>
<script type="text/javascript">
window.__PRELOADED_STATE__ = ${JSON.stringify(state).replace(/</g, '\\u003c')};
</script>
${js}
</body>
</html>`;
import { renderToString } from 'react-dom/server';
import { createStore } from 'store/create';
import { ServerStyleSheet } from "styled-components";
import flushChunks from 'webpack-flush-chunks';
import { clearChunks, flushChunkNames } from 'react-universal-component/server';
import { createClient } from 'client/create';
const client = createClient();
const store = createStore();
const sheet = new ServerStyleSheet();
const AppTree = <App store={store} apolloClient={client} />
await getDataFromTree(AppTree);
const application = renderToString(
sheet.collectStyles(AppTree)
);
const apolloState = client.extract();
const state = store.getState();
const styles = sheet.getStyleTags();
const chunkNames = flushChunkNames();
const { js } = flushChunks(clientStats, { chunkNames });
sheet.seal();
clearChunks();
return `<!doctype html>
<html>
<head>
<title>My Application</title>
${styles}
</head>
<body>
<div id="root">${application}</div>
<script type="text/javascript">
window.__APOLLO_STATE__ = ${JSON.stringify(apolloState).replace(/</g, '\\u003c')};
window.__PRELOADED_STATE__ = ${JSON.stringify(state).replace(/</g, '\\u003c')};
</script>
${js}
</body>
</html>`;