diff --git a/e2e-tests/production-runtime/cypress/integration/slices/slices.js b/e2e-tests/production-runtime/cypress/integration/slices/slices.js
index 89b60cb89f9df..5bb5f05345dc8 100644
--- a/e2e-tests/production-runtime/cypress/integration/slices/slices.js
+++ b/e2e-tests/production-runtime/cypress/integration/slices/slices.js
@@ -41,4 +41,10 @@ describe(`Slices`, () => {
.invoke(`text`)
.should(`contain`, `2`)
})
+
+ it(`Slice with static query works`, () => {
+ cy.getTestElement(`footer-static-query-title`).contains(
+ `Gatsby Default Starter`
+ )
+ })
})
diff --git a/e2e-tests/production-runtime/cypress/integration/ssr.js b/e2e-tests/production-runtime/cypress/integration/ssr.js
index 52b3a1aa4d655..16a177955a9a6 100644
--- a/e2e-tests/production-runtime/cypress/integration/ssr.js
+++ b/e2e-tests/production-runtime/cypress/integration/ssr.js
@@ -3,8 +3,11 @@ const paramPath = `/ssr/param-path/`
const wildcardPath = `/ssr/wildcard-path/`
const pathRaking = `/ssr/path-ranking/`
-Cypress.on('uncaught:exception', (err, runnable) => {
- if (err.message.includes('Minified React error #418') || err.message.includes('Minified React error #423')) {
+Cypress.on("uncaught:exception", (err, runnable) => {
+ if (
+ err.message.includes("Minified React error #418") ||
+ err.message.includes("Minified React error #423")
+ ) {
return false
}
})
@@ -50,6 +53,13 @@ describe(`Static path ('${staticPath}')`, () => {
expect(win.location.search).to.equal(queryString)
})
})
+
+ it(`Slice with static query works`, () => {
+ cy.visit(staticPath).waitForRouteChange()
+ cy.getTestElement(`footer-static-query-title`).contains(
+ `Gatsby Default Starter`
+ )
+ })
})
describe(`Param path ('${paramPath}:param')`, () => {
diff --git a/e2e-tests/production-runtime/src/components/footer.js b/e2e-tests/production-runtime/src/components/footer.js
index 205b88c9c015c..83bd49256e8ff 100644
--- a/e2e-tests/production-runtime/src/components/footer.js
+++ b/e2e-tests/production-runtime/src/components/footer.js
@@ -1,10 +1,25 @@
import React, { useContext } from "react"
+import { useStaticQuery, graphql } from "gatsby"
import { AppContext } from "../app-context"
// Use as a Slice
-function Footer({ framework, lang, sliceContext: { framework: frameworkViaContext }}) {
+function Footer({
+ framework,
+ lang,
+ sliceContext: { framework: frameworkViaContext },
+}) {
const { posts } = useContext(AppContext)
+ const data = useStaticQuery(graphql`
+ {
+ site {
+ siteMetadata {
+ alias: title
+ }
+ }
+ }
+ `)
+
return (
)
}
diff --git a/e2e-tests/production-runtime/src/pages/ssr/static-path.js b/e2e-tests/production-runtime/src/pages/ssr/static-path.js
index a3617bfb75590..3810bfbc5ca07 100644
--- a/e2e-tests/production-runtime/src/pages/ssr/static-path.js
+++ b/e2e-tests/production-runtime/src/pages/ssr/static-path.js
@@ -1,4 +1,5 @@
import React from "react"
+import { Slice } from "gatsby"
const UseEnv = ({ heading, envVar }) => (
@@ -30,7 +31,7 @@ export default function StaticPath({ serverData }) {
heading="process.env.FROM_COMMAND_LINE"
envVar={process.env.FROM_COMMAND_LINE}
/>
-
@@ -51,10 +52,11 @@ export default function StaticPath({ serverData }) {
heading="serverData.envVars.FROM_COMMAND_LINE"
envVar={serverData?.envVars?.FROM_COMMAND_LINE}
/>
-
+
)
}
@@ -63,7 +65,8 @@ export async function getServerData(arg) {
const VERY_SECRET_ALIAS_VAR = process.env.VERY_SECRET_VAR
const EXISTING_VAR = process.env.EXISTING_VAR
const FROM_COMMAND_LINE = process.env.FROM_COMMAND_LINE
- const GATSBY_PREFIXED_FROM_COMMAND_LINE = process.env.GATSBY_PREFIXED_FROM_COMMAND_LINE
+ const GATSBY_PREFIXED_FROM_COMMAND_LINE =
+ process.env.GATSBY_PREFIXED_FROM_COMMAND_LINE
return {
props: {
@@ -72,7 +75,7 @@ export async function getServerData(arg) {
VERY_SECRET_ALIAS_VAR,
EXISTING_VAR,
FROM_COMMAND_LINE,
- GATSBY_PREFIXED_FROM_COMMAND_LINE
+ GATSBY_PREFIXED_FROM_COMMAND_LINE,
},
},
}
diff --git a/packages/gatsby/src/commands/build-html.ts b/packages/gatsby/src/commands/build-html.ts
index efc1cc3f5bb1b..85b061f4a65d0 100644
--- a/packages/gatsby/src/commands/build-html.ts
+++ b/packages/gatsby/src/commands/build-html.ts
@@ -778,11 +778,18 @@ export async function buildSlices({
try {
const slices = Array.from(state.slices.entries())
+ const staticQueriesBySliceTemplate = {}
+ for (const slice of state.slices.values()) {
+ staticQueriesBySliceTemplate[slice.componentPath] =
+ state.staticQueriesByTemplate.get(slice.componentPath)
+ }
+
await workerPool.single.renderSlices({
publicDir: path.join(program.directory, `public`),
htmlComponentRendererPath,
slices,
slicesProps,
+ staticQueriesBySliceTemplate,
})
} catch (err) {
const prettyError = createErrorFromString(
diff --git a/packages/gatsby/src/commands/build.ts b/packages/gatsby/src/commands/build.ts
index 65f0e002006e2..f8f58c7bc89ff 100644
--- a/packages/gatsby/src/commands/build.ts
+++ b/packages/gatsby/src/commands/build.ts
@@ -56,7 +56,7 @@ import {
import { createGraphqlEngineBundle } from "../schema/graphql-engine/bundle-webpack"
import {
createPageSSRBundle,
- writeQueryContext,
+ copyStaticQueriesToEngine,
} from "../utils/page-ssr-module/bundle-webpack"
import { shouldGenerateEngines } from "../utils/engines-helpers"
import reporter from "gatsby-cli/lib/reporter"
@@ -379,15 +379,38 @@ module.exports = async function build(
})
}
- // create scope so we don't leak state object
+ const engineTemplatePaths = new Set()
{
- const state = store.getState()
- await writeQueryContext({
- staticQueriesByTemplate: state.staticQueriesByTemplate,
- components: state.components,
+ let SSGCount = 0
+ let DSGCount = 0
+ let SSRCount = 0
+
+ for (const page of store.getState().pages.values()) {
+ if (page.mode === `SSR`) {
+ SSRCount++
+ engineTemplatePaths.add(page.componentPath)
+ } else if (page.mode === `DSG`) {
+ DSGCount++
+ engineTemplatePaths.add(page.componentPath)
+ } else {
+ SSGCount++
+ }
+ }
+
+ telemetry.addSiteMeasurement(`BUILD_END`, {
+ totalPagesCount: store.getState().pages.size, // total number of pages
+ SSRCount,
+ DSGCount,
+ SSGCount,
})
}
+ await copyStaticQueriesToEngine({
+ engineTemplatePaths,
+ staticQueriesByTemplate: store.getState().staticQueriesByTemplate,
+ components: store.getState().components,
+ })
+
if (!(_CFLAGS_.GATSBY_MAJOR === `5` && process.env.GATSBY_SLICES)) {
if (process.send && shouldGenerateEngines()) {
await waitMaterializePageMode
@@ -577,29 +600,9 @@ module.exports = async function build(
}
}
- {
- let SSGCount = 0
- let DSGCount = 0
- let SSRCount = 0
- for (const page of store.getState().pages.values()) {
- if (page.mode === `SSR`) {
- SSRCount++
- } else if (page.mode === `DSG`) {
- DSGCount++
- } else {
- SSGCount++
- }
- }
-
- telemetry.addSiteMeasurement(`BUILD_END`, {
- pagesCount: toRegenerate.length, // number of html files that will be written
- totalPagesCount: store.getState().pages.size, // total number of pages
- SSRCount,
- DSGCount,
- SSGCount,
- })
- }
-
+ telemetry.addSiteMeasurement(`BUILD_END`, {
+ totalPagesCount: store.getState().pages.size, // total number of pages
+ })
const postBuildActivityTimer = report.activityTimer(`onPostBuild`, {
parentSpan: buildSpan,
})
diff --git a/packages/gatsby/src/utils/page-ssr-module/bundle-webpack.ts b/packages/gatsby/src/utils/page-ssr-module/bundle-webpack.ts
index 29e0249d613f2..c85b298bcda0f 100644
--- a/packages/gatsby/src/utils/page-ssr-module/bundle-webpack.ts
+++ b/packages/gatsby/src/utils/page-ssr-module/bundle-webpack.ts
@@ -10,7 +10,6 @@ import {
getScriptsAndStylesForTemplate,
readWebpackStats,
} from "../client-assets-for-template"
-import { writeStaticQueryContext } from "../static-query-utils"
import { IGatsbyState } from "../../redux/types"
import { store } from "../../redux"
@@ -20,27 +19,45 @@ const extensions = [`.mjs`, `.js`, `.json`, `.node`, `.ts`, `.tsx`]
const outputDir = path.join(process.cwd(), `.cache`, `page-ssr`)
const cacheLocation = path.join(process.cwd(), `.cache`, `webpack`, `page-ssr`)
-export async function writeQueryContext({
- staticQueriesByTemplate,
+export async function copyStaticQueriesToEngine({
+ engineTemplatePaths,
components,
+ staticQueriesByTemplate,
}: {
- staticQueriesByTemplate: IGatsbyState["staticQueriesByTemplate"]
+ engineTemplatePaths: Set
components: IGatsbyState["components"]
+ staticQueriesByTemplate: IGatsbyState["staticQueriesByTemplate"]
}): Promise {
- const waitingForWrites: Array> = []
- for (const pageTemplate of components.values()) {
- const staticQueryHashes =
- staticQueriesByTemplate.get(pageTemplate.componentPath) || []
+ const staticQueriesToCopy = new Set()
+
+ for (const component of components.values()) {
+ // figuring out needed slices for each pages using componentPath is not straightforward
+ // so for now we just collect static queries for all slices + engine templates
+ if (component.isSlice || engineTemplatePaths.has(component.componentPath)) {
+ const staticQueryHashes =
+ staticQueriesByTemplate.get(component.componentPath) || []
+
+ for (const hash of staticQueryHashes) {
+ staticQueriesToCopy.add(hash)
+ }
+ }
+ }
+
+ const sourceDir = path.join(process.cwd(), `public`, `page-data`, `sq`, `d`)
+ const destDir = path.join(outputDir, `sq`)
+
+ await fs.ensureDir(destDir)
+ await fs.emptyDir(destDir)
+
+ const promisesToAwait: Array> = []
+ for (const hash of staticQueriesToCopy) {
+ const sourcePath = path.join(sourceDir, `${hash}.json`)
+ const destPath = path.join(destDir, `${hash}.json`)
- waitingForWrites.push(
- writeStaticQueryContext(
- staticQueryHashes,
- pageTemplate.componentChunkName
- )
- )
+ promisesToAwait.push(fs.copy(sourcePath, destPath))
}
- return Promise.all(waitingForWrites).then(() => {})
+ await Promise.all(promisesToAwait)
}
export async function createPageSSRBundle({
diff --git a/packages/gatsby/src/utils/page-ssr-module/entry.ts b/packages/gatsby/src/utils/page-ssr-module/entry.ts
index 29647fe8cf0d1..1069d24c51441 100644
--- a/packages/gatsby/src/utils/page-ssr-module/entry.ts
+++ b/packages/gatsby/src/utils/page-ssr-module/entry.ts
@@ -314,16 +314,10 @@ export async function renderPageData({
}
}
}
-
-const readStaticQueryContext = async (
- templatePath: string
+const readStaticQuery = async (
+ staticQueryHash: string
): Promise> => {
- const filePath = path.join(
- __dirname,
- `sq-context`,
- templatePath,
- `sq-context.json`
- )
+ const filePath = path.join(__dirname, `sq`, `${staticQueryHash}.json`)
const rawSQContext = await fs.readFile(filePath, `utf-8`)
return JSON.parse(rawSQContext)
@@ -399,20 +393,19 @@ export async function renderHTML({
readStaticQueryContextActivity.start()
}
- const uniqueUsedComponentChunkNames = [data.page.componentChunkName]
+ const staticQueryHashes = new Set(pageData.staticQueryHashes)
for (const singleSliceData of Object.values(sliceData)) {
- if (
- singleSliceData.componentChunkName &&
- !uniqueUsedComponentChunkNames.includes(
- singleSliceData.componentChunkName
- )
- ) {
- uniqueUsedComponentChunkNames.push(singleSliceData.componentChunkName)
+ for (const staticQueryHash of singleSliceData.staticQueryHashes) {
+ staticQueryHashes.add(staticQueryHash)
}
}
const contextsToMerge = await Promise.all(
- uniqueUsedComponentChunkNames.map(readStaticQueryContext)
+ Array.from(staticQueryHashes).map(async staticQueryHash => {
+ return {
+ [staticQueryHash]: await readStaticQuery(staticQueryHash),
+ }
+ })
)
staticQueryContext = Object.assign({}, ...contextsToMerge)
diff --git a/packages/gatsby/src/utils/static-query-utils.ts b/packages/gatsby/src/utils/static-query-utils.ts
index df5d539e8db0f..ce24f46cfc418 100644
--- a/packages/gatsby/src/utils/static-query-utils.ts
+++ b/packages/gatsby/src/utils/static-query-utils.ts
@@ -5,8 +5,6 @@ const { join } = path.posix
import type { IScriptsAndStyles } from "./client-assets-for-template"
import { IPageDataWithQueryResult } from "./page-data"
-const outputDir = path.join(process.cwd(), `.cache`, `page-ssr`)
-
export const getStaticQueryPath = (hash: string): string =>
join(`page-data`, `sq`, `d`, `${hash}.json`)
@@ -66,24 +64,3 @@ export const getStaticQueryContext = async (
return { staticQueryContext }
}
-
-export const writeStaticQueryContext = async (
- staticQueryHashes: IPageDataWithQueryResult["staticQueryHashes"],
- templatePath: string
-): Promise<{
- staticQueryContext: IResourcesForTemplate["staticQueryContext"]
-}> => {
- const outputFilePath = path.join(
- outputDir,
- `sq-context`,
- templatePath,
- `sq-context.json`
- )
-
- const { staticQueryContext } = await getStaticQueryContext(staticQueryHashes)
-
- const stringifiedContext = JSON.stringify(staticQueryContext)
- await fs.outputFile(outputFilePath, stringifiedContext)
-
- return { staticQueryContext }
-}
diff --git a/packages/gatsby/src/utils/worker/child/render-html.ts b/packages/gatsby/src/utils/worker/child/render-html.ts
index 8de92cb7873d8..f1b7d1417ae97 100644
--- a/packages/gatsby/src/utils/worker/child/render-html.ts
+++ b/packages/gatsby/src/utils/worker/child/render-html.ts
@@ -66,23 +66,6 @@ const inFlightResourcesForTemplate = new Map<
Promise
>()
-const readStaticQueryContext = async (
- templatePath: string
-): Promise> => {
- const filePath = path.join(
- // TODO: Better way to get this?
- process.cwd(),
- `.cache`,
- `page-ssr`,
- `sq-context`,
- templatePath,
- `sq-context.json`
- )
- const rawSQContext = await fs.readFile(filePath, `utf-8`)
-
- return JSON.parse(rawSQContext)
-}
-
function clearCaches(): void {
clearStaticQueryCaches()
resourcesForTemplateCache.clear()
@@ -703,11 +686,13 @@ export async function renderSlices({
htmlComponentRendererPath,
publicDir,
slicesProps,
+ staticQueriesBySliceTemplate,
}: {
publicDir: string
slices: Array<[string, IGatsbySlice]>
slicesProps: Array
htmlComponentRendererPath: string
+ staticQueriesBySliceTemplate: Record>
}): Promise {
const htmlComponentRenderer = require(htmlComponentRendererPath)
@@ -718,11 +703,12 @@ export async function renderSlices({
`Slice name "${sliceName}" not found when rendering slices`
)
}
+ const slice = sliceEntry[1]
+ const staticQueryHashes =
+ staticQueriesBySliceTemplate[slice.componentPath] || []
- const [_fileName, slice] = sliceEntry
-
- const staticQueryContext = await readStaticQueryContext(
- slice.componentChunkName
+ const { staticQueryContext } = await getStaticQueryContext(
+ staticQueryHashes
)
const MAGIC_CHILDREN_STRING = `__DO_NOT_USE_OR_ELSE__`