Skip to content

Commit

Permalink
Wait until we know staticQueryHashes are written to page-data.json files
Browse files Browse the repository at this point in the history
We only discover static queries for pages after the component is compiled.

Which means when we lazily add page components, we initially don't know
what static queries should be loaded. To track this, we mark page-data.json
files as not bundled & only after the staticQueryHashes is written do we
accept the page as loaded.
  • Loading branch information
KyleAMathews committed Nov 10, 2020
1 parent 1cef9c0 commit 9fd03ea
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 6 deletions.
10 changes: 7 additions & 3 deletions packages/gatsby/cache-dir/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,9 +114,13 @@ apiRunnerAsync(`onClientEntry`).then(() => {
const preferDefault = m => (m && m.default) || m
let Root = preferDefault(require(`./root`))
domReady(() => {
renderer(<Root />, rootElement, () => {
apiRunner(`onInitialClientRender`)
})
// Hot reloading can by-pass the above loadPage promise so we
// run this again.
loader.loadPage(window.location.pathname).then(() =>
renderer(<Root />, rootElement, () => {
apiRunner(`onInitialClientRender`)
})
)
})
})
})
15 changes: 12 additions & 3 deletions packages/gatsby/cache-dir/gatsby-browser-entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const useStaticQuery = query => {
`Please update React and ReactDOM to 16.8.0 or later to use the useStaticQuery hook.`
)
}
const context = React.useContext(StaticQueryContext)
const context = React.useContext(StaticQueryContext) || {}

// query is a stringified number like `3303882` when wrapped with graphql, If a user forgets
// to wrap the query in a grqphql, then casting it to a Number results in `NaN` allowing us to
Expand All @@ -71,8 +71,17 @@ useStaticQuery(graphql\`${query}\`);
`)
}

if (context?.[query]?.data) {
return context[query].data
// Merge data loaded via socket.io & xhr
//
// TODO just load data over xhr & socket.io just triggers
// re-fetches
const staticQueryData = {
...context,
...loader.getStaticQueryResults(),
}

if (staticQueryData?.[query]?.data) {
return staticQueryData[query].data
} else {
throw new Error(
`The result of this StaticQuery could not be fetched.\n\n` +
Expand Down
22 changes: 22 additions & 0 deletions packages/gatsby/cache-dir/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,26 @@ export class BaseLoader {
throw new Error(`not a valid pageData response`)
}

// Handle the page not being in the bundle yet.
if (!jsonPayload.inDevBundle) {
// Tell the server the user wants to visit this page
// to trigger it including the page component's code in the
// commons bundles.
const req = new XMLHttpRequest()
req.open(`post`, `/___client-page-visited`, true)
req.setRequestHeader(
`Content-Type`,
`application/json;charset=UTF-8`
)
req.send(
JSON.stringify({ chunkName: jsonPayload.componentChunkName })
)

return new Promise(resolve =>
setTimeout(() => resolve(this.fetchPageDataJson(loadObj)), 100)
)
}

return Object.assign(loadObj, {
status: PageResourceStatus.Success,
payload: jsonPayload,
Expand Down Expand Up @@ -520,6 +540,8 @@ export const publicLoader = {
},
enqueue: rawPath => instance.prefetch(rawPath),

getStaticQueryResults: () => instance.staticQueryDb,

// Real methods
getResourceURLsForPathname: rawPath =>
instance.getResourceURLsForPathname(rawPath),
Expand Down
8 changes: 8 additions & 0 deletions packages/gatsby/src/utils/page-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface IPageData {
componentChunkName: IGatsbyPage["componentChunkName"]
matchPath?: IGatsbyPage["matchPath"]
path: IGatsbyPage["path"]
inDevBundle: boolean
staticQueryHashes: Array<string>
}

Expand Down Expand Up @@ -66,6 +67,7 @@ export async function writePageData(
componentChunkName,
matchPath,
path: pagePath,
inDevBundle,
staticQueryHashes,
}: IPageData
): Promise<IPageDataWithQueryResult> {
Expand All @@ -82,6 +84,8 @@ export async function writePageData(
componentChunkName,
path: pagePath,
matchPath,
// TODO how to exclude from production build?
inDevBundle,
result,
staticQueryHashes,
}
Expand Down Expand Up @@ -121,6 +125,7 @@ export async function flush(): Promise<void> {
pages,
program,
staticQueriesByTemplate,
clientVisitedPages,
} = store.getState()

const { pagePaths, templatePaths } = pendingPageDataWrites
Expand Down Expand Up @@ -149,10 +154,13 @@ export async function flush(): Promise<void> {
const staticQueryHashes =
staticQueriesByTemplate.get(page.componentPath) || []

const inDevBundle = clientVisitedPages.has(page.componentChunkName)

const result = await writePageData(
path.join(program.directory, `public`),
{
...page,
inDevBundle,
staticQueryHashes,
}
)
Expand Down
25 changes: 25 additions & 0 deletions packages/gatsby/src/utils/start-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,31 @@ export async function startServer(
app.post(`/___client-page-visited`, (req, res, next) => {
if (req.body?.chunkName) {
createClientVisitedPage(req.body.chunkName)

// Find the component page for this componentChunkName.
const pages = store.getState().pages
function getByChunkName(map, searchValue): void | string {
for (const [key, value] of map.entries()) {
if (value.componentChunkName === searchValue) return key
}

return undefined
}
const pageKey = getByChunkName(pages, req.body.chunkName)

// Trigger Gatsby to rewrite the page data for the pages
// owned by this component so staticQueryHashes are written.
if (pageKey) {
const page = pages.get(pageKey)
if (page) {
store.dispatch({
type: `ADD_PENDING_TEMPLATE_DATA_WRITE`,
payload: {
componentPath: page.component,
},
})
}
}
res.send(`ok`)
} else {
next()
Expand Down

0 comments on commit 9fd03ea

Please sign in to comment.