Skip to content

Commit f7dbc8b

Browse files
danielkovsidharthachatterjee
authored andcommittedMar 19, 2019
fix(gatsby): filter null values in headComponents, preBodyComponents and postBodyComponents (gatsbyjs#12555)
1 parent 7c759f4 commit f7dbc8b

File tree

3 files changed

+124
-20
lines changed

3 files changed

+124
-20
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`develop-static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><style>.style3 </style><style>.style2 </style><style>.style1 </style><script src=\\"/socket.io/socket.io.js\\"></script></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><script src=\\"/commons.js\\"></script></body></html>"`;
3+
exports[`develop-static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><style> .style3 </style><style> .style2 </style><style> .style1 </style><script src=\\"/socket.io/socket.io.js\\"></script></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><script src=\\"/commons.js\\"></script></body></html>"`;
44
5-
exports[`develop-static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><div>div3</div><div>div2</div><div>div1</div><script src=\\"/commons.js\\"></script></body></html>"`;
5+
exports[`develop-static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><div> div3 </div><div> div2 </div><div> div1 </div><script src=\\"/commons.js\\"></script></body></html>"`;
66
7-
exports[`develop-static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><div>div3</div><div>div2</div><div>div1</div><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><script src=\\"/commons.js\\"></script></body></html>"`;
7+
exports[`develop-static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><script src=\\"/socket.io/socket.io.js\\"></script></head><body><div> div3 </div><div> div2 </div><div> div1 </div><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"></div><script src=\\"/commons.js\\"></script></body></html>"`;
88
9-
exports[`static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><style>.style3 </style><style>.style2 </style><style>.style1 </style><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\"></div></div><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.page={\\"path\\":\\"/about/\\",\\"componentChunkName\\":\\"page-component---src-pages-test-js\\",\\"jsonName\\":\\"about.json\\"};/*]]>*/</script><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script></body></html>"`;
9+
exports[`static-entry onPreRenderHTML can be used to replace headComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><style> .style3 </style><style> .style2 </style><style> .style1 </style><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\"></div></div><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.page={\\"path\\":\\"/about/\\",\\"componentChunkName\\":\\"page-component---src-pages-test-js\\",\\"jsonName\\":\\"about.json\\"};/*]]>*/</script><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script></body></html>"`;
1010
11-
exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\"></div></div><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.page={\\"path\\":\\"/about/\\",\\"componentChunkName\\":\\"page-component---src-pages-test-js\\",\\"jsonName\\":\\"about.json\\"};/*]]>*/</script><div>div3</div><div>div2</div><div>div1</div></body></html>"`;
11+
exports[`static-entry onPreRenderHTML can be used to replace postBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\"></div></div><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.page={\\"path\\":\\"/about/\\",\\"componentChunkName\\":\\"page-component---src-pages-test-js\\",\\"jsonName\\":\\"about.json\\"};/*]]>*/</script><div> div3 </div><div> div2 </div><div> div1 </div></body></html>"`;
1212
13-
exports[`static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><div>div3</div><div>div2</div><div>div1</div><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\"></div></div><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.page={\\"path\\":\\"/about/\\",\\"componentChunkName\\":\\"page-component---src-pages-test-js\\",\\"jsonName\\":\\"about.json\\"};/*]]>*/</script><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script></body></html>"`;
13+
exports[`static-entry onPreRenderHTML can be used to replace preBodyComponents 1`] = `"<!DOCTYPE html><html><head><meta charSet=\\"utf-8\\"/><meta http-equiv=\\"x-ua-compatible\\" content=\\"ie=edge\\"/><meta name=\\"viewport\\" content=\\"width=device-width, initial-scale=1, shrink-to-fit=no\\"/><meta name=\\"generator\\" content=\\"Gatsby 2.0.0\\"/></head><body><div> div3 </div><div> div2 </div><div> div1 </div><noscript id=\\"gatsby-noscript\\">This app works best with JavaScript enabled.</noscript><div id=\\"___gatsby\\"><div style=\\"outline:none\\" tabindex=\\"-1\\" role=\\"group\\"></div></div><script id=\\"gatsby-script-loader\\">/*<![CDATA[*/window.page={\\"path\\":\\"/about/\\",\\"componentChunkName\\":\\"page-component---src-pages-test-js\\",\\"jsonName\\":\\"about.json\\"};/*]]>*/</script><script id=\\"gatsby-chunk-mapping\\">/*<![CDATA[*/window.___chunkMapping={};/*]]>*/</script></body></html>"`;

‎packages/gatsby/cache-dir/__tests__/static-entry.js

+100-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ jest.mock(
1717
},
1818
}
1919
},
20-
{ virtual: true }
20+
{
21+
virtual: true,
22+
}
2123
)
2224

2325
jest.mock(
@@ -38,7 +40,9 @@ jest.mock(
3840
],
3941
}
4042
},
41-
{ virtual: true }
43+
{
44+
virtual: true,
45+
}
4246
)
4347

4448
const MOCK_FILE_INFO = {
@@ -61,13 +65,48 @@ const reverseHeadersPlugin = {
6165
},
6266
}
6367

68+
const injectValuePlugin = (hookName, methodName, value) => {
69+
return {
70+
plugin: {
71+
[hookName]: staticEntry => {
72+
const method = staticEntry[methodName]
73+
method(value)
74+
},
75+
},
76+
}
77+
}
78+
79+
const checkSanitized = components => {
80+
expect(components.includes(null)).toBeFalsy()
81+
expect(
82+
components.find(val => Array.isArray(val) && val.length === 0)
83+
).toBeFalsy()
84+
}
85+
86+
const checkNonEmptyHeadersPlugin = {
87+
plugin: {
88+
onPreRenderHTML: ({
89+
getHeadComponents,
90+
getPreBodyComponents,
91+
getPostBodyComponents,
92+
}) => {
93+
const headComponents = getHeadComponents()
94+
const preBodyComponents = getPreBodyComponents()
95+
const postBodyComponents = getPostBodyComponents()
96+
checkSanitized(headComponents)
97+
checkSanitized(preBodyComponents)
98+
checkSanitized(postBodyComponents)
99+
},
100+
},
101+
}
102+
64103
const fakeStylesPlugin = {
65104
plugin: {
66105
onRenderBody: ({ setHeadComponents }) =>
67106
setHeadComponents([
68-
<style key="style1">.style1 {}</style>,
69-
<style key="style2">.style2 {}</style>,
70-
<style key="style3">.style3 {}</style>,
107+
<style key="style1"> .style1 {} </style>,
108+
<style key="style2"> .style2 {} </style>,
109+
<style key="style3"> .style3 {} </style>,
71110
]),
72111
},
73112
}
@@ -89,9 +128,9 @@ const fakeComponentsPluginFactory = type => {
89128
plugin: {
90129
onRenderBody: props => {
91130
props[`set${type}BodyComponents`]([
92-
<div key="div1">div1</div>,
93-
<div key="div2">div2</div>,
94-
<div key="div3">div3</div>,
131+
<div key="div1"> div1 </div>,
132+
<div key="div2"> div2 </div>,
133+
<div key="div3"> div3 </div>,
95134
])
96135
},
97136
},
@@ -133,6 +172,59 @@ describe(`develop-static-entry`, () => {
133172
})
134173
})
135174

175+
describe(`static-entry sanity checks`, () => {
176+
beforeEach(() => {
177+
global.__PATH_PREFIX__ = ``
178+
})
179+
180+
const methodsToCheck = [
181+
`replaceHeadComponents`,
182+
`replacePreBodyComponents`,
183+
`replacePostBodyComponents`,
184+
]
185+
186+
methodsToCheck.forEach(methodName => {
187+
test(`${methodName} can filter out null value`, done => {
188+
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, null)
189+
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
190+
191+
StaticEntry(`/about/`, (_, html) => {
192+
done()
193+
})
194+
})
195+
196+
test(`${methodName} can filter out null values`, done => {
197+
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [
198+
null,
199+
null,
200+
])
201+
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
202+
203+
StaticEntry(`/about/`, (_, html) => {
204+
done()
205+
})
206+
})
207+
208+
test(`${methodName} can filter out empty array`, done => {
209+
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [])
210+
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
211+
212+
StaticEntry(`/about/`, (_, html) => {
213+
done()
214+
})
215+
})
216+
217+
test(`${methodName} can filter out empty arrays`, done => {
218+
const plugin = injectValuePlugin(`onPreRenderHTML`, methodName, [[], []])
219+
global.plugins = [plugin, checkNonEmptyHeadersPlugin]
220+
221+
StaticEntry(`/about/`, (_, html) => {
222+
done()
223+
})
224+
})
225+
})
226+
})
227+
136228
describe(`static-entry`, () => {
137229
beforeEach(() => {
138230
global.__PATH_PREFIX__ = ``

‎packages/gatsby/cache-dir/static-entry.js

+18-6
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,16 @@ const getPage = path => pagesObjectMap.get(path)
4949

5050
const createElement = React.createElement
5151

52+
const sanitizeComponents = components => {
53+
if (Array.isArray(components)) {
54+
// remove falsy items
55+
return components.filter(val => (Array.isArray(val) ? val.length > 0 : val))
56+
} else {
57+
// we also accept single components, so we need to handle this case as well
58+
return components ? [components] : []
59+
}
60+
}
61+
5262
export default (pagePath, callback) => {
5363
let bodyHtml = ``
5464
let headComponents = [
@@ -69,7 +79,7 @@ export default (pagePath, callback) => {
6979
}
7080

7181
const setHeadComponents = components => {
72-
headComponents = headComponents.concat(components)
82+
headComponents = headComponents.concat(sanitizeComponents(components))
7383
}
7484

7585
const setHtmlAttributes = attributes => {
@@ -81,11 +91,13 @@ export default (pagePath, callback) => {
8191
}
8292

8393
const setPreBodyComponents = components => {
84-
preBodyComponents = preBodyComponents.concat(components)
94+
preBodyComponents = preBodyComponents.concat(sanitizeComponents(components))
8595
}
8696

8797
const setPostBodyComponents = components => {
88-
postBodyComponents = postBodyComponents.concat(components)
98+
postBodyComponents = postBodyComponents.concat(
99+
sanitizeComponents(components)
100+
)
89101
}
90102

91103
const setBodyProps = props => {
@@ -95,19 +107,19 @@ export default (pagePath, callback) => {
95107
const getHeadComponents = () => headComponents
96108

97109
const replaceHeadComponents = components => {
98-
headComponents = components
110+
headComponents = sanitizeComponents(components)
99111
}
100112

101113
const getPreBodyComponents = () => preBodyComponents
102114

103115
const replacePreBodyComponents = components => {
104-
preBodyComponents = components
116+
preBodyComponents = sanitizeComponents(components)
105117
}
106118

107119
const getPostBodyComponents = () => postBodyComponents
108120

109121
const replacePostBodyComponents = components => {
110-
postBodyComponents = components
122+
postBodyComponents = sanitizeComponents(components)
111123
}
112124

113125
const page = getPage(pagePath)

0 commit comments

Comments
 (0)