UNPKG

cl-react-graph

Version:
358 lines (301 loc) 10.3 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); const React = require(`react`); const fs = require(`fs`); const _require = require(`path`), join = _require.join; const _require2 = require(`react-dom/server`), renderToString = _require2.renderToString, renderToStaticMarkup = _require2.renderToStaticMarkup; const _require3 = require(`@reach/router`), ServerLocation = _require3.ServerLocation, Router = _require3.Router, isRedirect = _require3.isRedirect; const _require4 = require(`lodash`), get = _require4.get, merge = _require4.merge, isObject = _require4.isObject, flatten = _require4.flatten, uniqBy = _require4.uniqBy; const apiRunner = require(`./api-runner-ssr`); const syncRequires = require(`./sync-requires`); const _require5 = require(`./data.json`), dataPaths = _require5.dataPaths, pages = _require5.pages; const _require6 = require(`gatsby/package.json`), gatsbyVersion = _require6.version; // Speed up looking up pages. const pagesObjectMap = new Map(); pages.forEach(p => pagesObjectMap.set(p.path, p)); const stats = JSON.parse(fs.readFileSync(`${process.cwd()}/public/webpack.stats.json`, `utf-8`)); const chunkMapping = JSON.parse(fs.readFileSync(`${process.cwd()}/public/chunk-map.json`, `utf-8`)); // const testRequireError = require("./test-require-error") // For some extremely mysterious reason, webpack adds the above module *after* // this module so that when this code runs, testRequireError is undefined. // So in the meantime, we'll just inline it. const testRequireError = (moduleName, err) => { const regex = new RegExp(`Error: Cannot find module\\s.${moduleName}`); const firstLine = err.toString().split(`\n`)[0]; return regex.test(firstLine); }; let Html; try { Html = require(`../src/html`); } catch (err) { if (testRequireError(`../src/html`, err)) { Html = require(`./default-html`); } else { throw err; } } Html = Html && Html.__esModule ? Html.default : Html; const getPage = path => pagesObjectMap.get(path); const createElement = React.createElement; var _default = (pagePath, callback) => { let bodyHtml = ``; let headComponents = [React.createElement("meta", { name: "generator", content: `Gatsby ${gatsbyVersion}`, key: `generator-${gatsbyVersion}` })]; let htmlAttributes = {}; let bodyAttributes = {}; let preBodyComponents = []; let postBodyComponents = []; let bodyProps = {}; const replaceBodyHTMLString = body => { bodyHtml = body; }; const setHeadComponents = components => { headComponents = headComponents.concat(components); }; const setHtmlAttributes = attributes => { htmlAttributes = merge(htmlAttributes, attributes); }; const setBodyAttributes = attributes => { bodyAttributes = merge(bodyAttributes, attributes); }; const setPreBodyComponents = components => { preBodyComponents = preBodyComponents.concat(components); }; const setPostBodyComponents = components => { postBodyComponents = postBodyComponents.concat(components); }; const setBodyProps = props => { bodyProps = merge({}, bodyProps, props); }; const getHeadComponents = () => headComponents; const replaceHeadComponents = components => { headComponents = components; }; const getPreBodyComponents = () => preBodyComponents; const replacePreBodyComponents = components => { preBodyComponents = components; }; const getPostBodyComponents = () => postBodyComponents; const replacePostBodyComponents = components => { postBodyComponents = components; }; const page = getPage(pagePath); let dataAndContext = {}; if (page.jsonName in dataPaths) { const pathToJsonData = `../public/` + dataPaths[page.jsonName]; try { dataAndContext = JSON.parse(fs.readFileSync(`${process.cwd()}/public/static/d/${dataPaths[page.jsonName]}.json`)); } catch (e) { console.log(`error`, pathToJsonData, e); process.exit(); } } class RouteHandler extends React.Component { render() { const props = Object.assign({}, this.props, dataAndContext, { pathContext: dataAndContext.pageContext }); const pageElement = createElement(syncRequires.components[page.componentChunkName], props); const wrappedPage = apiRunner(`wrapPageElement`, { element: pageElement, props }, pageElement, ({ result }) => { return { element: result, props }; }).pop(); return wrappedPage; } } const routerElement = createElement(ServerLocation, { url: `${__PATH_PREFIX__}${pagePath}` }, createElement(Router, { baseuri: `${__PATH_PREFIX__}` }, createElement(RouteHandler, { path: `/*` }))); const bodyComponent = apiRunner(`wrapRootElement`, { element: routerElement, pathname: pagePath }, routerElement, ({ result }) => { return { element: result, pathname: pagePath }; }).pop(); // Let the site or plugin render the page component. apiRunner(`replaceRenderer`, { bodyComponent, replaceBodyHTMLString, setHeadComponents, setHtmlAttributes, setBodyAttributes, setPreBodyComponents, setPostBodyComponents, setBodyProps, pathname: pagePath, pathPrefix: __PATH_PREFIX__ }); // If no one stepped up, we'll handle it. if (!bodyHtml) { try { bodyHtml = renderToString(bodyComponent); } catch (e) { // ignore @reach/router redirect errors if (!isRedirect(e)) throw e; } } // Create paths to scripts let scriptsAndStyles = flatten([`app`, page.componentChunkName].map(s => { const fetchKey = `assetsByChunkName[${s}]`; let chunks = get(stats, fetchKey); let namedChunkGroups = get(stats, `namedChunkGroups`); if (!chunks) { return null; } chunks = chunks.map(chunk => { if (chunk === `/`) { return null; } return { rel: `preload`, name: chunk }; }); namedChunkGroups[s].assets.forEach(asset => chunks.push({ rel: `preload`, name: asset })); const childAssets = namedChunkGroups[s].childAssets; for (const rel in childAssets) { chunks = merge(chunks, childAssets[rel].map(chunk => { return { rel, name: chunk }; })); } return chunks; })).filter(s => isObject(s)).sort((s1, s2) => s1.rel == `preload` ? -1 : 1); // given priority to preload scriptsAndStyles = uniqBy(scriptsAndStyles, item => item.name); const scripts = scriptsAndStyles.filter(script => script.name && script.name.endsWith(`.js`)); const styles = scriptsAndStyles.filter(style => style.name && style.name.endsWith(`.css`)); apiRunner(`onRenderBody`, { setHeadComponents, setHtmlAttributes, setBodyAttributes, setPreBodyComponents, setPostBodyComponents, setBodyProps, pathname: pagePath, bodyHtml, scripts, styles, pathPrefix: __PATH_PREFIX__ }); scripts.slice(0).reverse().forEach(script => { // Add preload/prefetch <link>s for scripts. headComponents.push(React.createElement("link", { as: "script", rel: script.rel, key: script.name, href: `${__PATH_PREFIX__}/${script.name}` })); }); if (page.jsonName in dataPaths) { const dataPath = `${__PATH_PREFIX__}/static/d/${dataPaths[page.jsonName]}.json`; headComponents.push(React.createElement("link", { as: "fetch", rel: "preload", key: dataPath, href: dataPath, crossOrigin: "use-credentials" })); } styles.slice(0).reverse().forEach(style => { // Add <link>s for styles that should be prefetched // otherwise, inline as a <style> tag if (style.rel === `prefetch`) { headComponents.push(React.createElement("link", { as: "style", rel: style.rel, key: style.name, href: `${__PATH_PREFIX__}/${style.name}` })); } else { headComponents.unshift(React.createElement("style", { "data-href": `${__PATH_PREFIX__}/${style.name}`, dangerouslySetInnerHTML: { __html: fs.readFileSync(join(process.cwd(), `public`, style.name), `utf-8`) } })); } }); // Add page metadata for the current page const windowData = `/*<![CDATA[*/window.page=${JSON.stringify(page)};${page.jsonName in dataPaths ? `window.dataPath="${dataPaths[page.jsonName]}";` : ``}/*]]>*/`; postBodyComponents.push(React.createElement("script", { key: `script-loader`, id: `gatsby-script-loader`, dangerouslySetInnerHTML: { __html: windowData } })); // Add chunk mapping metadata const scriptChunkMapping = `/*<![CDATA[*/window.___chunkMapping=${JSON.stringify(chunkMapping)};/*]]>*/`; postBodyComponents.push(React.createElement("script", { key: `chunk-mapping`, id: `gatsby-chunk-mapping`, dangerouslySetInnerHTML: { __html: scriptChunkMapping } })); // Filter out prefetched bundles as adding them as a script tag // would force high priority fetching. const bodyScripts = scripts.filter(s => s.rel !== `prefetch`).map(s => { const scriptPath = `${__PATH_PREFIX__}/${JSON.stringify(s.name).slice(1, -1)}`; return React.createElement("script", { key: scriptPath, src: scriptPath, async: true }); }); postBodyComponents.push(...bodyScripts); apiRunner(`onPreRenderHTML`, { getHeadComponents, replaceHeadComponents, getPreBodyComponents, replacePreBodyComponents, getPostBodyComponents, replacePostBodyComponents, pathname: pagePath, pathPrefix: __PATH_PREFIX__ }); const html = `<!DOCTYPE html>${renderToStaticMarkup(React.createElement(Html, (0, _extends2.default)({}, bodyProps, { headComponents: headComponents, htmlAttributes: htmlAttributes, bodyAttributes: bodyAttributes, preBodyComponents: preBodyComponents, postBodyComponents: postBodyComponents, body: bodyHtml, path: pagePath })))}`; callback(null, html); }; exports.default = _default;