Skip to content

Commit

Permalink
feat: use inline JSON to enabling CSP without unsafe-inline
Browse files Browse the repository at this point in the history
  • Loading branch information
ambar authored and gregberge committed Mar 10, 2019
1 parent f35fb3c commit 05e5500
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
8 changes: 7 additions & 1 deletion packages/component/src/loadableReady.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ export default function loadableReady(done = () => {}) {
return Promise.resolve()
}

const requiredChunks = BROWSER ? window[LOADABLE_REQUIRED_CHUNKS_KEY] : null
let requiredChunks = null
if (BROWSER) {
const dataElement = document.getElementById(LOADABLE_REQUIRED_CHUNKS_KEY)
if (dataElement) {
requiredChunks = JSON.parse(dataElement.textContent)
}
}

if (!requiredChunks) {
warn(
Expand Down
15 changes: 10 additions & 5 deletions packages/server/src/ChunkExtractor.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,12 @@ class ChunkExtractor {
createChunkAsset({ filename, chunk, type, linkType }) {
return {
filename,
scriptType: extensionToScriptType(path.extname(filename).split('?')[0].toLowerCase()),
scriptType: extensionToScriptType(
path
.extname(filename)
.split('?')[0]
.toLowerCase(),
),
chunk,
url: this.resolvePublicUrl(filename),
path: path.join(this.outputPath, filename),
Expand Down Expand Up @@ -238,13 +243,11 @@ class ChunkExtractor {
}

getRequiredChunksScriptContent() {
return `window.${LOADABLE_REQUIRED_CHUNKS_KEY} = ${JSON.stringify(
this.getChunkDependencies(this.chunks),
)};`
return JSON.stringify(this.getChunkDependencies(this.chunks))
}

getRequiredChunksScriptTag(extraProps) {
return `<script${extraPropsToString(
return `<script id="${LOADABLE_REQUIRED_CHUNKS_KEY}" type="application/json"${extraPropsToString(
extraProps,
)}>${this.getRequiredChunksScriptContent()}</script>`
}
Expand All @@ -253,6 +256,8 @@ class ChunkExtractor {
return (
<script
key="required"
id={LOADABLE_REQUIRED_CHUNKS_KEY}
type="application/json"
dangerouslySetInnerHTML={{
__html: this.getRequiredChunksScriptContent(),
}}
Expand Down
24 changes: 16 additions & 8 deletions packages/server/src/ChunkExtractor.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,15 @@ describe('ChunkExtrator', () => {
describe('#getScriptTags', () => {
it('should return main script tag without chunk', () => {
expect(extractor.getScriptTags()).toMatchInlineSnapshot(`
"<script>window.__LOADABLE_REQUIRED_CHUNKS__ = [];</script>
"<script id=\\"__LOADABLE_REQUIRED_CHUNKS__\\" type=\\"application/json\\">[]</script>
<script async data-chunk=\\"main\\" src=\\"/dist/node/main.js\\"></script>"
`)
})

it('should return other chunks if referenced', () => {
extractor.addChunk('letters-A')
expect(extractor.getScriptTags()).toMatchInlineSnapshot(`
"<script>window.__LOADABLE_REQUIRED_CHUNKS__ = [\\"letters-A\\"];</script>
"<script id=\\"__LOADABLE_REQUIRED_CHUNKS__\\" type=\\"application/json\\">[\\"letters-A\\"]</script>
<script async data-chunk=\\"letters-A\\" src=\\"/dist/node/letters-A.js\\"></script>
<script async data-chunk=\\"main\\" src=\\"/dist/node/main.js\\"></script>"
`)
Expand All @@ -60,7 +60,7 @@ describe('ChunkExtrator', () => {
it('should allow for query params in chunk names', () => {
extractor.addChunk('letters-E')
expect(extractor.getScriptTags()).toMatchInlineSnapshot(`
"<script>window.__LOADABLE_REQUIRED_CHUNKS__ = [\\"letters-E\\"];</script>
"<script id=\\"__LOADABLE_REQUIRED_CHUNKS__\\" type=\\"application/json\\">[\\"letters-E\\"]</script>
<script async data-chunk=\\"letters-E\\" src=\\"/dist/node/letters-E.js?param\\"></script>
<script async data-chunk=\\"main\\" src=\\"/dist/node/main.js\\"></script>"
`)
Expand All @@ -70,7 +70,7 @@ describe('ChunkExtrator', () => {
extractor.addChunk('letters-A')
expect(extractor.getScriptTags({ nonce: 'testnonce' }))
.toMatchInlineSnapshot(`
"<script nonce=\\"testnonce\\">window.__LOADABLE_REQUIRED_CHUNKS__ = [\\"letters-A\\"];</script>
"<script id=\\"__LOADABLE_REQUIRED_CHUNKS__\\" type=\\"application/json\\" nonce=\\"testnonce\\">[\\"letters-A\\"]</script>
<script async data-chunk=\\"letters-A\\" src=\\"/dist/node/letters-A.js\\" nonce=\\"testnonce\\"></script>
<script async data-chunk=\\"main\\" src=\\"/dist/node/main.js\\" nonce=\\"testnonce\\"></script>"
`)
Expand All @@ -84,9 +84,11 @@ Array [
<script
dangerouslySetInnerHTML={
Object {
"__html": "window.__LOADABLE_REQUIRED_CHUNKS__ = [];",
"__html": "[]",
}
}
id="__LOADABLE_REQUIRED_CHUNKS__"
type="application/json"
/>,
<script
async={true}
Expand All @@ -104,9 +106,11 @@ Array [
<script
dangerouslySetInnerHTML={
Object {
"__html": "window.__LOADABLE_REQUIRED_CHUNKS__ = [\\"letters-A\\"];",
"__html": "[\\"letters-A\\"]",
}
}
id="__LOADABLE_REQUIRED_CHUNKS__"
type="application/json"
/>,
<script
async={true}
Expand All @@ -129,9 +133,11 @@ Array [
<script
dangerouslySetInnerHTML={
Object {
"__html": "window.__LOADABLE_REQUIRED_CHUNKS__ = [\\"letters-E\\"];",
"__html": "[\\"letters-E\\"]",
}
}
id="__LOADABLE_REQUIRED_CHUNKS__"
type="application/json"
/>,
<script
async={true}
Expand All @@ -155,10 +161,12 @@ Array [
<script
dangerouslySetInnerHTML={
Object {
"__html": "window.__LOADABLE_REQUIRED_CHUNKS__ = [\\"letters-A\\"];",
"__html": "[\\"letters-A\\"]",
}
}
id="__LOADABLE_REQUIRED_CHUNKS__"
nonce="testnonce"
type="application/json"
/>,
<script
async={true}
Expand Down

0 comments on commit 05e5500

Please sign in to comment.