Skip to content

Instantly share code, notes, and snippets.

@ghankerson
Created May 30, 2019 21:38
Show Gist options
  • Save ghankerson/d903339be83b55c9ac1629274a326a63 to your computer and use it in GitHub Desktop.
Save ghankerson/d903339be83b55c9ac1629274a326a63 to your computer and use it in GitHub Desktop.
import React from 'react';
import ReactDOM from 'react-dom/server';
import { ApolloProvider, renderToStringWithData } from 'react-apollo';
import { HelmetProvider } from 'react-helmet-async';
import { ServerLocation } from 'apm-titan';
// import { client } from '../shared/graphql/graphqlClient';
import App from '../shared/App';
import fs from 'fs';
import os from 'os';
import {
globalHostFunc,
replaceTemplateStrings,
isFresh,
apm_etag,
siteConfigFunc
} from './utils';
import fetch from 'cross-fetch';
import { ApolloClient } from 'apollo-client';
import { createHttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import FragmentMatcher from '../shared/graphql/FragmentMatcher';
export default function ReactAppSsr(app) {
app.use((req, res) => {
const helmetContext = {};
const filepath =
process.env.APP_PATH === 'relative' ? 'build' : 'current/build';
const forwarded = globalHostFunc(req).split(':')[0];
const siteConfig = siteConfigFunc(forwarded);
const hostname = os.hostname();
const context = {};
const cache = new InMemoryCache({ fragmentMatcher: FragmentMatcher });
let graphqlEnv = hostname.match(/dev/) ? '-dev' : '';
graphqlEnv = process.env.NODE_ENV === 'development' ? '-dev' : graphqlEnv;
const client = new ApolloClient({
ssrMode: true,
cache,
link: createHttpLink({
uri: `https://cmsproxy${graphqlEnv}.publicradio.org/api/v1/graphql`,
fetch: fetch
})
});
let template = fs.readFileSync(`${filepath}/index.html`).toString();
const component = (
<ApolloProvider client={client}>
<HelmetProvider context={helmetContext}>
<ServerLocation url={req.url} context={context}>
<App forward={forwarded} />
</ServerLocation>
</HelmetProvider>
</ApolloProvider>
);
renderToStringWithData(component).then(() => {
const { helmet } = helmetContext;
let str = ReactDOM.renderToString(component);
const is404 = str.match(/Not Found\. 404/);
if (is404?.length > 0) {
str = 'Not Found 404.';
template = replaceTemplateStrings(template, '', '', '', '');
res.status(404);
res.send(template);
return;
}
template = replaceTemplateStrings(
template,
helmet.title.toString(),
helmet.meta.toString(),
helmet.link.toString(),
str
);
template = template.replace(/__GTMID__/g, `${siteConfig.gtm}`);
const cacheStr = JSON.stringify(client.extract());
const clientCache = `<script>window.__APOLLO_STATE__ = ${cacheStr}</script>`;
template = template.replace(/__script__/, clientCache);
res.set('Cache-Control', 'public, max-age=120');
res.set('ETag', apm_etag(str));
if (isFresh(req, res)) {
res.status(304);
res.send();
return;
}
res.send(template);
res.status(200);
});
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment