Skip to content

Commit

Permalink
[dynamicIO] warn for disallowed dynamic in dev (#71526)
Browse files Browse the repository at this point in the history
Previously our rules for allowed dynamic were only enforced in builds.
This is not tenable for serious adoption because you can't spend all day
working on your site and then find out its broken when you build /
deploy.

To address this I've added a simulated prerendering during dev that
should enforce the same rules for rendered routes in dev that would
apply during a build. There is no way to avoid doing additional work to
implement this feature because we need the abort mechanism of SSR to
actually find the dynamic holes that should be disallowed. I was able to
avoid completely duplicating the RSC render however by capturing the
stream chunks available before the first task completes and stashing
them away as a simulated halted RSC payload.

I did have to introduce prospective renders to the RSC render and the
validating SSR render however to work around issues of lazy module
initialization where functions like Math.random and new Date() in module
scope would incorrectly trigger dynamic validation when you would not
expect them to.
  • Loading branch information
gnoff authored Oct 21, 2024
1 parent de26339 commit b18c027
Show file tree
Hide file tree
Showing 37 changed files with 1,432 additions and 1,027 deletions.
26 changes: 6 additions & 20 deletions packages/next/src/client/components/client-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,27 +40,13 @@ export function ClientPageRoot({
)
}

if (store.isStaticGeneration) {
// We are in a prerender context
const { createPrerenderSearchParamsFromClient } =
require('../../server/request/search-params') as typeof import('../../server/request/search-params')
clientSearchParams = createPrerenderSearchParamsFromClient(store)
const { createSearchParamsFromClient } =
require('../../server/request/search-params') as typeof import('../../server/request/search-params')
clientSearchParams = createSearchParamsFromClient(searchParams, store)

const { createPrerenderParamsFromClient } =
require('../../server/request/params') as typeof import('../../server/request/params')

clientParams = createPrerenderParamsFromClient(params, store)
} else {
const { createRenderSearchParamsFromClient } =
require('../../server/request/search-params') as typeof import('../../server/request/search-params')
clientSearchParams = createRenderSearchParamsFromClient(
searchParams,
store
)
const { createRenderParamsFromClient } =
require('../../server/request/params') as typeof import('../../server/request/params')
clientParams = createRenderParamsFromClient(params, store)
}
const { createParamsFromClient } =
require('../../server/request/params') as typeof import('../../server/request/params')
clientParams = createParamsFromClient(params, store)

return <Component params={clientParams} searchParams={clientSearchParams} />
} else {
Expand Down
10 changes: 2 additions & 8 deletions packages/next/src/client/components/client-segment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,10 @@ export function ClientSegmentRoot({
)
}

const { createPrerenderParamsFromClient } =
const { createParamsFromClient } =
require('../../server/request/params') as typeof import('../../server/request/params')
clientParams = createParamsFromClient(params, store)

if (store.isStaticGeneration) {
clientParams = createPrerenderParamsFromClient(params, store)
} else {
const { createRenderParamsFromClient } =
require('../../server/request/params') as typeof import('../../server/request/params')
clientParams = createRenderParamsFromClient(params, store)
}
return <Component {...slots} params={clientParams} />
} else {
const { createRenderParamsFromClient } =
Expand Down
Loading

0 comments on commit b18c027

Please sign in to comment.