Created
March 24, 2020 10:16
-
-
Save QuadradS/85014fe9376812580640526ee5ace5a3 to your computer and use it in GitHub Desktop.
custom ssr
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 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; |
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 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) | |
} | |
} |
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 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