Skip to content

Instantly share code, notes, and snippets.

@QuadradS
Created March 24, 2020 10:16
Show Gist options
  • Save QuadradS/85014fe9376812580640526ee5ace5a3 to your computer and use it in GitHub Desktop.
Save QuadradS/85014fe9376812580640526ee5ace5a3 to your computer and use it in GitHub Desktop.
custom ssr
import React from 'react'
import ReactDOMServer from 'react-dom/server'
import { Provider } from 'react-redux'
import { StaticRouter } from 'react-router-dom'
import App from '../App'
import { Helmet } from 'react-helmet'
const getHtml = ({ store, context, url }) => {
let html;
let helmet;
try {
html = ReactDOMServer.renderToString(
<Provider store={store}>
<StaticRouter context={context} location={url}>
<App />
</StaticRouter>
</Provider>
);
} catch (error) {
console.error(error, "ERROR IN RENDER TO STRING")
html = "";
}
try {
helmet = Helmet.renderStatic();
} catch (error) {
console.error(error, "ERROR FROM HELMET RENDER STATIC")
}
return {
html,
title: helmet ? helmet.title.toString() : "",
meta: helmet ? helmet.meta.toString() : "",
link: helmet ? helmet.link.toString() : "",
script: helmet ? helmet.script.toString() : ""
};
};
export default getHtml;
import getHtml from './get_html'
import routes from '../routes'
import { matchPath } from 'react-router-dom'
import configureStore from '../configure_store'
import App from '../App'
import HelmetWrapper from '../helmet/helmet'
const path = require('path')
const fs = require('fs')
const getFinalResult = ({ store, context, url, htmlData, isGoogleBot = false }) => {
let { html, title, meta, link, script } = getHtml({ store, context, url })
let headContent = /<head>(.*)<\/head>/.exec(htmlData)[1]
if (process.env.REACT_APP_MODE !== 'production') {
headContent = `${headContent} <meta name="googlebot" content="noindex, nofollow">`
}
meta = meta.replace(/ data-react-helmet="true"/g, '')
htmlData = htmlData
.replace('<div id="root"></div>', `<div id="root">${html}</div>`)
.replace(
/<head>.*<\/head>/,
`<head>${script}${link}${meta}${title}${headContent}</head>`
)
.replace(
`<script data-initial-state="true"></script>`,
`<script data-initial-state="true">
window.__STATE__ = ${JSON.stringify(store.getState())};
</script>`
)
if (!isGoogleBot) {
htmlData = htmlData
.replace(
`<script data-google-tag-manager></script>`,
`<script>
(function(w, d, s, l, i) {
w[l] = w[l] || [];
w[l].push({ 'gtm.start': new Date().getTime(), event: 'gtm.js' });
var f = d.getElementsByTagName(s)[0],
j = d.createElement(s),
dl = l !== 'dataLayer' ? '&l=' + l : '';
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=' + i + dl;
f.parentNode.insertBefore(j, f)
})(window, document, 'script', 'dataLayer', 'GTM-5KHVLRJ')</script>`
)
.replace(
`<script data-other-scripts></script>`,
`<script src="//code.tidio.co/sshks8go0mbgkrb6fudxg79gxfuuy0fq.js" defer></script>
<style>
#tidio-chat-iframe {
bottom: 53px !important;
}
</style>
<script data-other-scripts type="text/javascript">
_linkedin_partner_id = '1458324';
window._linkedin_data_partner_ids = window._linkedin_data_partner_ids || [];
window._linkedin_data_partner_ids.push(_linkedin_partner_id)
</script>
<script type="text/javascript">
(function() {
var s = document.getElementsByTagName('script')[0];
var b = document.createElement('script');
b.type = 'text/javascript';
b.async = true;
b.src = 'https://snap.licdn.com/li.lms-analytics/insight.min.js';
s.parentNode.insertBefore(b, s)
})()
</script>
<noscript>
<img height="1" width="1" style="display:none;" alt=""
src="https://px.ads.linkedin.com/collect/?pid=1458324&fmt=gif"/>
</noscript>
<script>
!function(f, b, e, v, n, t, s) {
if (f.fbq) return;
n = f.fbq = function() {
n.callMethod ?
n.callMethod.apply(n, arguments) : n.queue.push(arguments)
};
if (!f._fbq) f._fbq = n;
n.push = n;
n.loaded = !0;
n.version = '2.0';
n.queue = [];
t = b.createElement(e);
t.async = !0;
t.src = v;
s = b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t, s)
}(window, document, 'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '2217053995289605');
fbq('track', 'PageView')
</script>
<noscript><img height="1" width="1" style="display:none"
src="https://www.facebook.com/tr?id=2217053995289605&ev=PageView&noscript=1"
/></noscript>
`
)
}
return htmlData
}
const cleanParams = params => {
const result = {}
Object.keys(params).forEach(p => {
result[p] = params[p].split('?')[0]
})
return result
}
export default (req, res) => {
const url = req.originalUrl
const filePath = path.resolve(__dirname, 'index.html')
fs.readFile(filePath, 'utf8', async (err, htmlData) => {
if (err) {
console.error('err', err)
return res.status(400).send('Could not read index.html template file')
}
const context = {}
const store = configureStore({}, true)
const token = req.cookies.token
const getMePromise = () => {
return App.fetchData({ dispatch: store.dispatch, token })
}
const getHelmetPromise = () =>
HelmetWrapper.fetchData({
dispatch: store.dispatch,
url
})
let params = {}
const activeRoute =
routes.find(route => {
const match = matchPath(req.baseUrl, route)
if (match && match.params) {
params = cleanParams(match.params)
}
return match
}) || {}
const getContainerPromise = () => {
if (!activeRoute.component || !activeRoute.component.fetchData) {
return Promise.resolve()
}
if (!!activeRoute.component.componentDidMountSSR) {
activeRoute.component.componentDidMountSSR({
dispatch: store.dispatch,
query: req.query,
url,
params,
token
})
}
return (
activeRoute.component.fetchData({
dispatch: store.dispatch,
query: req.query,
url,
params,
token
})
)
}
try {
await getMePromise()
} catch (error) {
console.error(error, 'ERROR FROM GET ME PROMISE')
}
try {
await getContainerPromise();
await getHelmetPromise();
} catch (error) {
console.error(error, 'ERROR IN RENDERER')
}
const userAgent = req.headers['user-agent'].toLowerCase()
await send({
res,
store,
context,
url,
htmlData,
activeRoute,
isGoogleBot: ['Googlebot', 'Chrome-Lighthouse'].some(el => userAgent.includes(el.toLowerCase()))
})
})
};
async function send({
res,
store,
context,
url,
htmlData,
activeRoute,
isGoogleBot
}) {
let finalResult
finalResult = await getFinalResult({
store,
context,
url,
htmlData,
isGoogleBot
})
if (activeRoute.component === undefined || store.getState().notFound) {
return res.status(404).send(finalResult)
}
if (context.url) {
res.redirect(context.url)
} else {
return res.send(finalResult)
}
}
import express from 'express'
import cookieParser from 'cookie-parser'
import serverRenderer from './renderer'
const path = require("path");
require("dotenv").config({
path: path.resolve(__dirname, "..", "..", ".env")
});
function startServer(port) {
const app = express();
app.use(cookieParser());
const router = express.Router();
router.use(
express.static(path.resolve(__dirname, "..", "..", "build"), {
maxAge: "30d"
})
);
router.use("*", serverRenderer);
app.use(router);
return new Promise((resolve, reject) => {
const server = app.listen(port, error => {
if (error) {
reject(error);
}
resolve(server);
});
});
}
export default startServer;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment