Last active
June 18, 2020 01:44
-
-
Save gonecase/82ab2ddb1603b0d2ece872d8ebf2e590 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 createApi from './helpers/api'; | |
import _ from 'lodash'; | |
const siteMapItemFromContentId = (sitemap, contentID) => { | |
const paths = Object.keys(sitemap).filter(path => !!sitemap[path].contentID && `${contentID}` === `${sitemap[path].contentID}`); | |
if (paths.length > 0) { | |
return sitemap[paths[0]]; | |
} | |
return false; | |
} | |
const createAgilityMiddleware = (config, options) => { | |
if (!config) { | |
return (req, res, next) => { | |
next(); | |
} | |
} | |
// create agility API | |
const prodApi = createApi(config.guid, config.productionKey); | |
const previewApi = createApi(config.guid, config.previewKey, true); | |
return async (req, res, next) => { | |
// to make sure it wont redirect to 404 when request favicon.ico | |
if(req.url.toLowerCase() == '/favicon.ico') { | |
next(); | |
} | |
// check if there is a url param in the req agilitypreviewkey has length of over 10 characters | |
const isPreview = !!req.query.agilitypreviewkey; | |
const api = (isPreview) ? previewApi : prodApi; | |
let sitemap = await api.getSitemap(); | |
let sitemapNested = await api.getSitemapNested(); | |
// handle redirects with contentID in query param | |
const contentIdRedirect = siteMapItemFromContentId(sitemap, req.query.contentID); | |
if (!!contentIdRedirect) { | |
res.redirect(contentIdRedirect.path); | |
return; | |
} | |
// get all content items we need beforehand | |
let prefetchedContentItems = await Promise.all(options.prefetch.contentItems.map( i => api.getContentItem(i) )); | |
// get all content lists we need beforehand | |
let prefetchedContentLists = await Promise.all(options.prefetch.contentLists.map( i => api.getContentListAll(i) )); | |
let currentUrlSlug = req ? req.path.toLowerCase() : pathname; | |
currentUrlSlug = (currentUrlSlug === '/' || currentUrlSlug === '') ? '/home' : currentUrlSlug; | |
if (currentUrlSlug[currentUrlSlug.length - 1] == '/') { | |
currentUrlSlug = currentUrlSlug.substring(0, currentUrlSlug.length - 1); | |
} | |
let thisSiteMapItem = sitemap[currentUrlSlug]; | |
// REDIRECT TO 404 - look into withRouter | |
if (typeof thisSiteMapItem == 'undefined') { | |
thisSiteMapItem = { | |
redirect: {url: options.error404} | |
} | |
} | |
// HANDLE REDIRECTS and Do not process if not needed | |
if (!!thisSiteMapItem.redirect) { | |
let redirectLocation = thisSiteMapItem.redirect.url.replace('~', ''); | |
res.redirect(redirectLocation); | |
return; | |
} | |
var currentPage = await api.getPage(thisSiteMapItem.pageID); | |
// HANDLE Dynamic Content | |
if (!!currentPage.dynamic && !!thisSiteMapItem.contentID) { | |
//console.log(thisSiteMapItem.contentID); | |
currentPage.thisDynamicItem = await api.getContentItem(thisSiteMapItem.contentID); | |
} | |
// get the handlers working | |
if (!!currentPage.zones) { | |
Object.keys(currentPage.zones).map((zoneKey, zoneIndex) => { | |
let zone = currentPage.zones[zoneKey]; | |
if (typeof options.zoneHandlers[zoneKey] == 'function') { | |
zone = options.zoneHandlers[zoneKey]({zone, api, sitemapNested, thisSiteMapItem, url:req.url, query: req.query}); | |
} | |
zone.map( agilityModule => { | |
if (options.moduleHandlers[agilityModule.module]) { | |
options.moduleHandlers[agilityModule.module]({agilityModule, api, url:req.url, query: req.query}); | |
} | |
}); | |
}); | |
} else { | |
} | |
// Handle unset titles | |
if (!!!thisSiteMapItem.title || thisSiteMapItem.title == '[empty]') { | |
thisSiteMapItem.title = false; | |
} | |
//console.log('all done on the server'); | |
// setup Pagedata | |
res.pagedata = { | |
currentPage, | |
sitemap, | |
thisSiteMapItem, | |
sitemapNested, | |
isPreview: isPreview, | |
prefetchedContentItems, | |
prefetchedContentLists | |
}; | |
next(); | |
} | |
} | |
export default createAgilityMiddleware; |
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 _ from 'lodash'; | |
import axios from 'axios'; | |
const AgilityOptions = { | |
agilityMiddlewareOptions : { | |
error500: '/errors/500', | |
error404: '/errors/404', | |
prefetch: { | |
contentLists: ['timeline'], // referenceNames of content lists where you want all the data | |
contentItems: [15741], // ids of content items | |
}, | |
zoneHandlers: { | |
Masthead: ({zone, api, sitemapNested, thisSiteMapItem}) => { | |
zone.push({module: "Breadcrumbs", item: {contentID: 'breadcumbItem', fields: thisSiteMapItem}}); | |
return zone; | |
} | |
}, | |
moduleHandlers: { | |
Search: ({agilityModule, api, url, query}) => { | |
if (!!req.query.s) { | |
return agilityModule; | |
} | |
const startIndex = !!req.query.startIndex ? req.query.startIndex : 1; | |
const searchResults = await axios.get(`https://www.googleapis.com/customsearch/v1?key=SEARCH_KEY&cx=SEARCH_CX&q=${req.query.s}&start=${startIndex}`) | |
.then(r => r.data) | |
.catch( err=> err.data); | |
agilityModule.searchResults = searchResults; | |
return agilityModule; | |
} | |
}, | |
}, | |
agilitycmsConfig: { | |
guid: 'XXXX', | |
previewKey: 'XXXX', | |
productionKey: 'XXXXX' | |
} | |
} | |
export default AgilityOptions; |
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 agility from '@agility/content-fetch'; | |
import _ from 'lodash'; | |
const createApi = (guid, apiKey, isPreview=false) => { | |
const api = agility.getApi({ | |
guid: guid, | |
apiKey: apiKey, | |
isPreview: isPreview | |
}); | |
return { | |
api : api, | |
getSitemap : items => { | |
return Promise.resolve( | |
api.getSitemapFlat({ | |
channelName: 'website', | |
languageCode: 'en-us' | |
}) | |
.then(sitemap => sitemap) | |
.catch(error => error.data) | |
); | |
}, | |
getSitemapNested : () => { | |
return Promise.resolve( | |
api.getSitemapNested({ | |
channelName: 'website', | |
languageCode: 'en-us' | |
}) | |
.then(sitemap => sitemap) | |
.catch(error => error.data) | |
) | |
}, | |
getPage : (pageID) => { | |
return Promise.resolve( | |
api.getPage({ | |
pageID: pageID, | |
languageCode: 'en-us', | |
contentLinkDepth: 6 | |
}) | |
.then(page => page) | |
.catch(error => error.data) | |
) | |
}, | |
getContentItem : (contentID) => { | |
return Promise.resolve( | |
api.getContentItem({ | |
contentID: parseInt(contentID), | |
languageCode: 'en-us', | |
contentLinkDepth: 6 | |
}) | |
.then(contentItem => contentItem) | |
.catch(error => error.data) | |
) | |
}, | |
getContentList : (referenceName, skip=0) => { | |
return Promise.resolve( | |
api.getContentList({ | |
referenceName: referenceName, | |
languageCode: 'en-us', | |
contentLinkDepth: 5, | |
take: 50, | |
skip: skip, | |
sort: 'properties.created', | |
direction: api.types.SortDirections.ASC | |
}) | |
.then( contentList => contentList ) | |
.catch(error => error.data) | |
); | |
}, | |
getContentListAll : async (referenceName) => { | |
let listDefinition = { | |
referenceName: referenceName, | |
languageCode: 'en-us', | |
contentLinkDepth: 5, | |
take: 50, | |
skip: 0, | |
sort: 'properties.created', | |
direction: api.types.SortDirections.ASC | |
} | |
let items = await Promise.resolve( | |
api.getContentList(listDefinition) | |
.then( contentList => contentList ) | |
.catch(error => error.data) | |
); | |
let xitems; | |
if (items.totalCount > items.items.length) { | |
let diff = items.totalCount - items.items.length; | |
let numPages = Math.ceil(diff/50); | |
xitems = await Promise.all(Array.from(Array(numPages), (x,i) => { | |
return api.getContentList({ | |
...listDefinition, | |
skip: 50*(i+1) | |
}) | |
.then( contentList => contentList ) | |
.catch(error => error.data) | |
})) | |
return { | |
items: _.flatten([items.items, _.flatten(xitems.map(i => i.items))]), | |
totalCount: items.totalCount | |
}; | |
} else { | |
return {items}; | |
} | |
}, | |
getTimeLine : (page=0) => { | |
return Promise.resolve( | |
api.getContentList({ | |
referenceName: 'news', | |
languageCode: 'en-us', | |
contentLinkDepth: 5, | |
take: 50, | |
skip: 0, | |
sort: 'properties.created', | |
filters: [ | |
{property: 'fields.timelineHidden', operator: api.types.FilterOperators.NOT_EQUAL_TO, value: true}, | |
], | |
direction: api.types.SortDirections.DESC | |
}) | |
.then( contentList => contentList ) | |
.catch(error => error.data) | |
); | |
} | |
} | |
} | |
export default createApi; |
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 { hydrate } from 'react-dom'; | |
import App from './components/App'; | |
import createApi from './apiHelpers'; | |
import config from './options/agility'; | |
hydrate(<App {...window.___appProps} />, document.getElementById('root')); | |
if (module.hot) { | |
module.hot.accept(); | |
} |
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 App from './components/App'; | |
import React from 'react'; | |
import express from 'express'; | |
import { renderToString } from 'react-dom/server'; | |
const server = express(); | |
server.use(agilityMiddleware) | |
.get('*', (req, res) => { | |
res.pagedata = res.pagedata || {}; | |
const pagedata = {...res.pagedata} | |
const markup = renderToString(<App {...pagedata}/>); | |
const host = req.get('host'); | |
res.send( | |
// prettier-ignore | |
`<!doctype html> | |
<html lang="en"> | |
<head> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | |
<meta charSet='utf-8' /> | |
<title>${res.pagedata.isPreview ? 'Preview : ' : ''}${!!res.pagedata.thisSiteMapItem.title ? res.pagedata.thisSiteMapItem.title + ' | ' : ''} First Canadian Place | Exchange Tower</title> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<base href="/" /> | |
<link href="/favicon.png" rel="shortcut icon" /> | |
<link rel="stylesheet" href="pathtocompliledclient.css"> | |
</head> | |
<body class="${host}"> | |
<div id="root">${markup}</div> | |
<script src="pathtoclient.js" defer crossorigin></script> | |
<script>var ___appProps = ${JSON.stringify(pagedata)}</script> | |
</body> | |
</html>`); | |
}); | |
export default server; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment