Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(develop): emit stale page data messages when staticQueryHashes change #28349

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"selector": "adding-static-query-A-to-B-to-A-link",
"status": "from-static-query-results"
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,19 @@ function pageTitleAndDataAssertion(config) {
cy.findByText(`Preview custom 404 page`).click()
}

cy.findByTestId(`${config.prefix || ``}page-path`)
.should(`have.text`, getExpectedCanonicalPath(config))
cy.findByTestId(`${config.prefix || ``}page-path`).should(
`have.text`,
getExpectedCanonicalPath(config)
)

cy.findByTestId(`${config.prefix || ``}query-data-caches-page-title`)
.should(`have.text`, `This is page ${config.page}`)
cy.findByTestId(`${config.prefix || ``}query-data-caches-page-title`).should(
`have.text`,
`This is page ${config.page}`
)

cy.findByTestId(`${config.prefix || ``}${config.queryType}-query-result`)
.should(
cy.findByTestId(
`${config.prefix || ``}${config.queryType}-query-result`
).should(
`have.text`,
`${config.slug} / ${
config.page === config.initialPage ? `initial-page` : `second-page`
Expand Down Expand Up @@ -145,6 +150,7 @@ function runTests(config) {
assertNotReloading()
}

describe(`Keeping caches up-to-date when updating data`, () => {
describe(`Navigate from static page A to page B, invalidate some data resources for static page A, navigate back to static page A`, () => {
describe(`Navigating back with gatsby-link`, () => {
it(`page query (page has trailing slash)`, () => {
Expand Down Expand Up @@ -346,3 +352,65 @@ describe(`Navigate from 404 page A to page B, invalidate some data resources for
})
})
})
})

describe(`Keeping caches up to date when modifying list of static query hashes assigned to a template`, () => {
describe(`using gatsby-link`, () => {
it.only(`Navigate from page A to page B, add static query to page A, navigate back to page A`, () => {
const config = {
slug: `adding-static-query-A-to-B-to-A-link`,
queryType: `static`,
navigateBack: `link`,
initialPage: `A`,
}

cy.visit(`/query-data-caches/${config.slug}/page-A/`).waitForRouteChange()

setupForAssertingNotReloading()

// baseline assertions
pageTitleAndDataAssertion({
...config,
page: config.initialPage,
data: `from-hardcoded-data`,
})

cy.getTestElement(`page-b-link`).click().waitForRouteChange()

// assert we navigated
pageTitleAndDataAssertion({
...config,
page: `B`,
data: `from-static-query-results`,
})

cy.exec(
`npm run update -- --file src/pages/query-data-caches/${config.slug}/page-A.js --replacements "adding-static-query-blank:adding-static-query-with-data" --exact`
)

// TODO: get rid of this wait
// We currently have timing issue when emitting both webpack's HMR and page-data.
// Problem is we need to potentially wait for webpack recompilation before we emit page-data (due to dependency graph traversal).
// Even if we could delay emitting data on the "server" side - this doesn't guarantee that messages are received
// and handled in correct order (ideally they are applied at the exact same time actually, because ordering might still cause issues if we change query text and component render function)
cy.wait(10000)

if (config.navigateBack === `link`) {
cy.getTestElement(`page-a-link`).click().waitForRouteChange()
} else if (config.navigateBack === `history`) {
// this is just making sure page components don't have link to navigate back (asserting correct setup)
cy.getTestElement(`page-a-link`).should(`not.exist`)
cy.go(`back`).waitForRouteChange()
}

// assert data on page we previously visited is updated
pageTitleAndDataAssertion({
...config,
page: config.initialPage,
data: `from-static-query-results`,
})

assertNotReloading()
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function useDataForAddingStaticQueryTest() {
return {
queryDataCachesJson: {
selector: `adding-static-query-A-to-B-to-A-link`,
status: `from-hardcoded-data`,
initialOrSecond: `initial-page`,
},
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { graphql, useStaticQuery } from "gatsby"

export function useDataForAddingStaticQueryTest() {
return useStaticQuery(graphql`
{
queryDataCachesJson(
selector: { eq: "adding-static-query-A-to-B-to-A-link" }
) {
...QueryDataCachesFragmentInitialPage
}
}
`)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from "react"
import { Link } from "gatsby"
import { QueryDataCachesView } from "../../../components/query-data-caches/view"
import { useDataForAddingStaticQueryTest } from "../../../components/query-data-caches/adding-static-query-blank"

export default function AddingStaticQueryToPageTemplatePageA({ path }) {
const data = useDataForAddingStaticQueryTest()
return (
<>
<QueryDataCachesView
data={data}
pageType="A"
dataType="static-query"
path={path}
/>
<Link to="../page-B" data-testid="page-b-link">
Go to page B
</Link>
</>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from "react"
import { Link, graphql, useStaticQuery } from "gatsby"
import { QueryDataCachesView } from "../../../components/query-data-caches/view"

export default function AddingStaticQueryToPageTemplatePageB({ path }) {
const data = useStaticQuery(graphql`
{
queryDataCachesJson(
selector: { eq: "adding-static-query-A-to-B-to-A-link" }
) {
...QueryDataCachesFragmentSecondPage
}
}
`)
return (
<>
<QueryDataCachesView
data={data}
pageType="B"
dataType="static-query"
path={path}
/>
<Link to="../page-A" data-testid="page-a-link">
Go back to page A
</Link>
</>
)
}
10 changes: 6 additions & 4 deletions packages/gatsby/cache-dir/dev-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ class DevLoader extends BaseLoader {
this.handleStaticQueryResultHotUpdate(msg)
} else if (msg.type === `pageQueryResult`) {
this.handlePageQueryResultHotUpdate(msg)
} else if (msg.type === `dirtyQueries`) {
this.handleDirtyPageQueryMessage(msg)
} else if (msg.type === `stalePageData`) {
this.handleStalePageDataMessage(msg)
}
})
} else if (process.env.NODE_ENV !== `test`) {
Expand Down Expand Up @@ -103,6 +103,8 @@ class DevLoader extends BaseLoader {
const cachedPageData = this.pageDataDb.get(pageDataDbCacheKey)?.payload

if (!isEqual(newPageData, cachedPageData)) {
// TODO: if this is update for current page and there are any new static queries added
// that are not yet cached, there is currently no trigger to fetch them (yikes)
// always update canonical key for pageDataDb
this.pageDataDb.set(pageDataDbCacheKey, {
pagePath: pageDataDbCacheKey,
Expand Down Expand Up @@ -146,8 +148,8 @@ class DevLoader extends BaseLoader {
}
}

handleDirtyPageQueryMessage(msg) {
msg.payload.dirtyQueries.forEach(dirtyQueryId => {
handleStalePageDataMessage(msg) {
msg.payload.stalePageDataPaths.forEach(dirtyQueryId => {
if (dirtyQueryId === `/dev-404-page/` || dirtyQueryId === `/404.html`) {
// those pages are not on demand so skipping
return
Expand Down
2 changes: 1 addition & 1 deletion packages/gatsby/cache-dir/ensure-resources.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class EnsureResources extends React.Component {
}

if (
process.env.GATSBY_EXPERIMENTAL_QUERY_ON_DEMAND &&
process.env.BUILD_STAGE === `develop` &&
nextState.pageResources.stale
) {
this.loadResources(nextProps.location.pathname)
Expand Down
7 changes: 2 additions & 5 deletions packages/gatsby/cache-dir/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ export class BaseLoader {
const pagePath = findPath(rawPath)
if (this.pageDataDb.has(pagePath)) {
const pageData = this.pageDataDb.get(pagePath)
if (!process.env.GATSBY_EXPERIMENTAL_QUERY_ON_DEMAND || !pageData.stale) {
if (process.env.BUILD_STAGE !== `develop` || !pageData.stale) {
return Promise.resolve(pageData)
}
}
Expand All @@ -212,10 +212,7 @@ export class BaseLoader {
const pagePath = findPath(rawPath)
if (this.pageDb.has(pagePath)) {
const page = this.pageDb.get(pagePath)
if (
!process.env.GATSBY_EXPERIMENTAL_QUERY_ON_DEMAND ||
!page.payload.stale
) {
if (process.env.BUILD_STAGE !== `develop` || !page.payload.stale) {
return Promise.resolve(page.payload)
}
}
Expand Down
56 changes: 47 additions & 9 deletions packages/gatsby/src/utils/websocket-manager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable no-invalid-this */

import { store, emitter } from "../redux"
import { IAddPendingTemplateDataWriteAction } from "../redux/types"
import { clearDirtyQueriesListToEmitViaWebsocket } from "../redux/actions/internal"
import { Server as HTTPSServer } from "https"
import { Server as HTTPServer } from "http"
Expand Down Expand Up @@ -119,12 +120,34 @@ export class WebsocketManager {
})

if (process.env.GATSBY_EXPERIMENTAL_QUERY_ON_DEMAND) {
emitter.on(`CREATE_PAGE`, this.emitDirtyQueriesIds)
emitter.on(`CREATE_NODE`, this.emitDirtyQueriesIds)
emitter.on(`DELETE_NODE`, this.emitDirtyQueriesIds)
emitter.on(`QUERY_EXTRACTED`, this.emitDirtyQueriesIds)
// page-data marked stale due to dirty query tracking
const boundEmitStalePageDataPathsFromDirtyQueryTracking = this.emitStalePageDataPathsFromDirtyQueryTracking.bind(
this
)
emitter.on(
`CREATE_PAGE`,
boundEmitStalePageDataPathsFromDirtyQueryTracking
)
emitter.on(
`CREATE_NODE`,
boundEmitStalePageDataPathsFromDirtyQueryTracking
)
emitter.on(
`DELETE_NODE`,
boundEmitStalePageDataPathsFromDirtyQueryTracking
)
emitter.on(
`QUERY_EXTRACTED`,
boundEmitStalePageDataPathsFromDirtyQueryTracking
)
}

// page-data marked stale due to static query hashes change
emitter.on(
`ADD_PENDING_TEMPLATE_DATA_WRITE`,
this.emitStalePageDataPathsFromStaticQueriesAssignment.bind(this)
)

return this.websocket
}

Expand Down Expand Up @@ -187,20 +210,35 @@ export class WebsocketManager {
}
}

emitDirtyQueriesIds = (): void => {
emitStalePageDataPathsFromDirtyQueryTracking(): void {
const dirtyQueries = store.getState().queries
.dirtyQueriesListToEmitViaWebsocket

if (dirtyQueries.length > 0) {
if (this.emitStalePageDataPaths(dirtyQueries)) {
store.dispatch(clearDirtyQueriesListToEmitViaWebsocket())
}
}

emitStalePageDataPathsFromStaticQueriesAssignment(
pendingTemplateDataWrite: IAddPendingTemplateDataWriteAction
): void {
this.emitStalePageDataPaths(
Array.from(pendingTemplateDataWrite.payload.pages)
)
}

emitStalePageDataPaths(stalePageDataPaths: Array<string>): boolean {
if (stalePageDataPaths.length > 0) {
if (this.websocket) {
this.websocket.send({
type: `dirtyQueries`,
payload: { dirtyQueries },
type: `stalePageData`,
payload: { stalePageDataPaths },
})

store.dispatch(clearDirtyQueriesListToEmitViaWebsocket())
return true
}
}
return false
}
}

Expand Down