"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = exports.sanitizeComponents = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); const React = require(`react`); const fs = require(`fs`); const { join } = require(`path`); const { renderToString, renderToStaticMarkup } = require(`react-dom/server`); const { ServerLocation, Router, isRedirect } = require(`@reach/router`); const { get, merge, isObject, flatten, uniqBy, flattenDeep, replace } = require(`lodash`); const apiRunner = require(`./api-runner-ssr`); const syncRequires = require(`./sync-requires`); const { version: gatsbyVersion } = require(`gatsby/package.json`); 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 getPageDataPath = path => { const fixedPagePath = path === `/` ? `index` : path; return join(`page-data`, fixedPagePath, `page-data.json`); }; const getPageDataUrl = pagePath => { const pageDataPath = getPageDataPath(pagePath); return `${__PATH_PREFIX__}/${pageDataPath}`; }; const getPageDataFile = pagePath => { const pageDataPath = getPageDataPath(pagePath); return join(process.cwd(), `public`, pageDataPath); }; const loadPageDataSync = pagePath => { const pageDataPath = getPageDataPath(pagePath); const pageDataFile = join(process.cwd(), `public`, pageDataPath); try { const pageDataJson = fs.readFileSync(pageDataFile); return JSON.parse(pageDataJson); } catch (error) { // not an error if file is not found. There's just no page data return null; } }; const createElement = React.createElement; const sanitizeComponents = components => { const componentsArray = ensureArray(components); return componentsArray.map(component => { // Ensure manifest is always loaded from content server // And not asset server when an assetPrefix is used if (__ASSET_PREFIX__ && component.props.rel === `manifest`) { return React.cloneElement(component, { href: replace(component.props.href, __ASSET_PREFIX__, ``) }); } return component; }); }; exports.sanitizeComponents = sanitizeComponents; const ensureArray = components => { if (Array.isArray(components)) { // remove falsy items and flatten return flattenDeep(components.filter(val => Array.isArray(val) ? val.length > 0 : val)); } else { // we also accept single components, so we need to handle this case as well return components ? [components] : []; } }; 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(sanitizeComponents(components)); }; const setHtmlAttributes = attributes => { htmlAttributes = merge(htmlAttributes, attributes); }; const setBodyAttributes = attributes => { bodyAttributes = merge(bodyAttributes, attributes); }; const setPreBodyComponents = components => { preBodyComponents = preBodyComponents.concat(sanitizeComponents(components)); }; const setPostBodyComponents = components => { postBodyComponents = postBodyComponents.concat(sanitizeComponents(components)); }; const setBodyProps = props => { bodyProps = merge({}, bodyProps, props); }; const getHeadComponents = () => headComponents; const replaceHeadComponents = components => { headComponents = sanitizeComponents(components); }; const getPreBodyComponents = () => preBodyComponents; const replacePreBodyComponents = components => { preBodyComponents = sanitizeComponents(components); }; const getPostBodyComponents = () => postBodyComponents; const replacePostBodyComponents = components => { postBodyComponents = sanitizeComponents(components); }; const pageDataRaw = fs.readFileSync(getPageDataFile(pagePath)); const pageData = JSON.parse(pageDataRaw); const pageDataUrl = getPageDataUrl(pagePath); const { componentChunkName } = pageData; class RouteHandler extends React.Component { render() { const props = Object.assign({}, this.props, {}, pageData.result, { // pathContext was deprecated in v2. Renamed to pageContext pathContext: pageData.result ? pageData.result.pageContext : undefined }); const pageElement = createElement(syncRequires.components[componentChunkName], props); const wrappedPage = apiRunner(`wrapPageElement`, { element: pageElement, props }, pageElement, ({ result }) => { return { element: result, props }; }).pop(); return wrappedPage; } } const routerElement = createElement(ServerLocation, { url: `${__BASE_PATH__}${pagePath}` }, createElement(Router, { id: `gatsby-focus-wrapper`, baseuri: `${__BASE_PATH__}` }, 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`, 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, loadPageDataSync, bodyHtml, scripts, styles, pathPrefix: __PATH_PREFIX__ }); scripts.slice(0).reverse().forEach(script => { // Add preload/prefetch s for scripts. headComponents.push(React.createElement("link", { as: "script", rel: script.rel, key: script.name, href: `${__PATH_PREFIX__}/${script.name}` })); }); if (pageData) { headComponents.push(React.createElement("link", { as: "fetch", rel: "preload", key: pageDataUrl, href: pageDataUrl, crossOrigin: "anonymous" })); } styles.slice(0).reverse().forEach(style => { // Add s for styles that should be prefetched // otherwise, inline as a