diff --git a/packages/gatsby/cache-dir/__tests__/__snapshots__/static-entry.js.snap b/packages/gatsby/cache-dir/__tests__/__snapshots__/static-entry.js.snap index 603e8dfc70d86..2137dd0c59a58 100644 --- a/packages/gatsby/cache-dir/__tests__/__snapshots__/static-entry.js.snap +++ b/packages/gatsby/cache-dir/__tests__/__snapshots__/static-entry.js.snap @@ -1,13 +1,13 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`develop-static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"
"`; +exports[`develop-static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"
"`; -exports[`develop-static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"
div3
div2
div1
"`; +exports[`develop-static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"
div3
div2
div1
"`; -exports[`develop-static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"
div3
div2
div1
"`; +exports[`develop-static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"
div3
div2
div1
"`; -exports[`static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"
"`; +exports[`static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"
"`; -exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"
div3
div2
div1
"`; +exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"
div3
div2
div1
"`; -exports[`static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"
div3
div2
div1
"`; +exports[`static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"
div3
div2
div1
"`; diff --git a/packages/gatsby/cache-dir/__tests__/static-entry.js b/packages/gatsby/cache-dir/__tests__/static-entry.js index 03d857d15a1de..41edef94ab482 100644 --- a/packages/gatsby/cache-dir/__tests__/static-entry.js +++ b/packages/gatsby/cache-dir/__tests__/static-entry.js @@ -17,7 +17,9 @@ jest.mock( }, } }, - { virtual: true } + { + virtual: true, + } ) jest.mock( @@ -38,7 +40,9 @@ jest.mock( ], } }, - { virtual: true } + { + virtual: true, + } ) const MOCK_FILE_INFO = { @@ -61,13 +65,48 @@ const reverseHeadersPlugin = { }, } +const injectValuePlugin = (hookName, methodName, value) => { + return { + plugin: { + [hookName]: staticEntry => { + const method = staticEntry[methodName] + method(value) + }, + }, + } +} + +const checkSanitized = components => { + expect(components.includes(null)).toBeFalsy() + expect( + components.find(val => Array.isArray(val) && val.length === 0) + ).toBeFalsy() +} + +const checkNonEmptyHeadersPlugin = { + plugin: { + onPreRenderHTML: ({ + getHeadComponents, + getPreBodyComponents, + getPostBodyComponents, + }) => { + const headComponents = getHeadComponents() + const preBodyComponents = getPreBodyComponents() + const postBodyComponents = getPostBodyComponents() + checkSanitized(headComponents) + checkSanitized(preBodyComponents) + checkSanitized(postBodyComponents) + }, + }, +} + const fakeStylesPlugin = { plugin: { onRenderBody: ({ setHeadComponents }) => setHeadComponents([ - , - , - , + , + , + , ]), }, } @@ -89,9 +128,9 @@ const fakeComponentsPluginFactory = type => { plugin: { onRenderBody: props => { props[`set${type}BodyComponents`]([ -
div1
, -
div2
, -
div3
, +
div1
, +
div2
, +
div3
, ]) }, }, @@ -133,6 +172,59 @@ describe(`develop-static-entry`, () => { }) }) +describe(`static-entry sanity checks`, () => { + beforeEach(() => { + global.__PATH_PREFIX__ = `` + }) + + const methodsToCheck = [ + `replaceHeadComponents`, + `replacePreBodyComponents`, + `replacePostBodyComponents`, + ] + + methodsToCheck.forEach(methodName => { + test(`${methodName} can filter out null value`, done => { + const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, null) + global.plugins = [plugin, checkNonEmptyHeadersPlugin] + + StaticEntry(`/about/`, (_, html) => { + done() + }) + }) + + test(`${methodName} can filter out null values`, done => { + const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [ + null, + null, + ]) + global.plugins = [plugin, checkNonEmptyHeadersPlugin] + + StaticEntry(`/about/`, (_, html) => { + done() + }) + }) + + test(`${methodName} can filter out empty array`, done => { + const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, []) + global.plugins = [plugin, checkNonEmptyHeadersPlugin] + + StaticEntry(`/about/`, (_, html) => { + done() + }) + }) + + test(`${methodName} can filter out empty arrays`, done => { + const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [[], []]) + global.plugins = [plugin, checkNonEmptyHeadersPlugin] + + StaticEntry(`/about/`, (_, html) => { + done() + }) + }) + }) +}) + describe(`static-entry`, () => { beforeEach(() => { global.__PATH_PREFIX__ = `` diff --git a/packages/gatsby/cache-dir/static-entry.js b/packages/gatsby/cache-dir/static-entry.js index 3e0cb708ba184..d3fbebd1a523c 100644 --- a/packages/gatsby/cache-dir/static-entry.js +++ b/packages/gatsby/cache-dir/static-entry.js @@ -49,6 +49,16 @@ const getPage = path => pagesObjectMap.get(path) const createElement = React.createElement +const sanitizeComponents = components => { + if (Array.isArray(components)) { + // remove falsy items + return 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] : [] + } +} + export default (pagePath, callback) => { let bodyHtml = `` let headComponents = [ @@ -69,7 +79,7 @@ export default (pagePath, callback) => { } const setHeadComponents = components => { - headComponents = headComponents.concat(components) + headComponents = headComponents.concat(sanitizeComponents(components)) } const setHtmlAttributes = attributes => { @@ -81,11 +91,13 @@ export default (pagePath, callback) => { } const setPreBodyComponents = components => { - preBodyComponents = preBodyComponents.concat(components) + preBodyComponents = preBodyComponents.concat(sanitizeComponents(components)) } const setPostBodyComponents = components => { - postBodyComponents = postBodyComponents.concat(components) + postBodyComponents = postBodyComponents.concat( + sanitizeComponents(components) + ) } const setBodyProps = props => { @@ -95,19 +107,19 @@ export default (pagePath, callback) => { const getHeadComponents = () => headComponents const replaceHeadComponents = components => { - headComponents = components + headComponents = sanitizeComponents(components) } const getPreBodyComponents = () => preBodyComponents const replacePreBodyComponents = components => { - preBodyComponents = components + preBodyComponents = sanitizeComponents(components) } const getPostBodyComponents = () => postBodyComponents const replacePostBodyComponents = components => { - postBodyComponents = components + postBodyComponents = sanitizeComponents(components) } const page = getPage(pagePath)