Skip to content

Commit

Permalink
fix(gatsby): re-add prefetch/preload links for child assets (#29693)
Browse files Browse the repository at this point in the history
* fix(gatsby): re-add prefetch/preload links for child assets

* test(artifacts): add test for adding <link> tags for webpack's magic comments
  • Loading branch information
pieh authored Feb 23, 2021
1 parent 249905a commit 170c604
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 25 deletions.
27 changes: 27 additions & 0 deletions integration-tests/artifacts/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,33 @@ describe(`First run (baseline)`, () => {
manifest[runNumber].allPages.sort()
)
})

describe(`should add <link> for webpack's magic comments`, () => {
let htmlContent
beforeAll(() => {
htmlContent = fs.readFileSync(
path.join(
process.cwd(),
`public`,
`dynamic-imports-magic-comments`,
`index.html`
),
`utf-8`
)
})

it(`has prefetch link`, () => {
expect(htmlContent).toMatch(
/<link\s+as="script"\s+rel="prefetch"\s+href="\/magic-comment-prefetch-\w+.js"\s*\/>/g
)
})

it(`has preload link`, () => {
expect(htmlContent).toMatch(
/<link\s+as="script"\s+rel="preload"\s+href="\/magic-comment-preload-\w+.js"\s*\/>/g
)
})
})
})

describe(`page-data files`, () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function forPrefetch() {
return `export-for-prefetch`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function forPreload() {
return `export-for-preload`
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as React from "react"

import(
/* webpackChunkName: "magic-comment-prefetch", webpackPrefetch: true */ `../components/magic-comments/prefetch`
).then(moduleForPrefetch => {
console.log({ forPrefetch: moduleForPrefetch.forPrefetch() })
})

import(
/* webpackChunkName: "magic-comment-preload", webpackPreload: true */ `../components/magic-comments/preload`
).then(moduleForPreload => {
console.log({ forPreload: moduleForPreload.forPreload() })
})

export default function DynamicImportsWithWebpackMagicComments() {
return <div>Sample for dynamic imports with webpack's magic comments</div>
}
23 changes: 23 additions & 0 deletions packages/gatsby/src/utils/gatsby-webpack-stats-extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export class GatsbyWebpackStatsExtractor {
compiler.hooks.done.tapAsync(this.plugin.name, (stats, done) => {
const assets = {}
const assetsMap = {}
const childAssets = {}
for (const chunkGroup of stats.compilation.chunkGroups) {
if (chunkGroup.name) {
const files: Array<string> = []
Expand All @@ -25,11 +26,33 @@ export class GatsbyWebpackStatsExtractor {
f.slice(0, chunkGroup.name.length) === chunkGroup.name
)
.map(filename => `/${filename}`)

for (const [rel, childChunkGroups] of Object.entries(
chunkGroup.getChildrenByOrders(
stats.compilation.moduleGraph,
stats.compilation.chunkGraph
)
)) {
if (!(chunkGroup.name in childAssets)) {
childAssets[chunkGroup.name] = {}
}

const childFiles = []
for (const childChunkGroup of childChunkGroups) {
for (const chunk of childChunkGroup.chunks) {
childFiles.push(...chunk.files)
}
}

childAssets[chunkGroup.name][rel] = childFiles
}
}
}

const webpackStats = {
...stats.toJson({ all: false, chunkGroups: true }),
assetsByChunkName: assets,
childAssetsByChunkName: childAssets,
}
fs.writeFile(
path.join(`public`, `chunk-map.json`),
Expand Down
41 changes: 16 additions & 25 deletions packages/gatsby/src/utils/worker/render-html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,38 +135,29 @@ async function getScriptsAndStylesForTemplate(
handleAsset(asset, `preload`)
}

const namedChunkGroup = webpackStats.namedChunkGroups[chunkName]
if (!namedChunkGroup) {
continue
}

for (const asset of namedChunkGroup.assets) {
handleAsset(asset.name, `preload`)
}

// TODO: figure out childAssets for webpack@5 - there is no longer `childAssets` in webpack.stats.json
// Handling for webpack magic comments, for example:
// import(/* webpackChunkName: "<chunk_name>", webpackPrefetch: true */ `<path_to_module>`)
// will produce
// Shape of webpackStats.childAssetsByChunkName:
// {
// namedChunkGroups: {
// childAssetsByChunkName: {
// <name_of_top_level_chunk>: {
// // [...] some fields we don't care about,
// childAssets: {
// prefetch: [
// "<chunk_name>-<chunk_hash>.js",
// "<chunk_name>-<chunk_hash>.js.map",
// ]
// }
// prefetch: [
// "<chunk_name>-<chunk_hash>.js",
// ]
// }
// }
// }
// for (const [rel, assets] of Object.entries(namedChunkGroup.childAssets)) {
// // @ts-ignore TS doesn't like that assets is not typed and especially that it doesn't know that it's Iterable
// for (const asset of assets) {
// handleAsset(asset, rel)
// }
// }
const childAssets = webpackStats.childAssetsByChunkName[chunkName]
if (!childAssets) {
continue
}

for (const [rel, assets] of Object.entries(childAssets)) {
// @ts-ignore TS doesn't like that assets is not typed and especially that it doesn't know that it's Iterable
for (const asset of assets) {
handleAsset(asset, rel)
}
}
}

// create scripts array, making sure "preload" scripts have priority
Expand Down

0 comments on commit 170c604

Please sign in to comment.