Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 8bc5716

Browse files
committed
fix: support ppr dynamic shells
1 parent 4585d6b commit 8bc5716

File tree

4 files changed

+105
-13
lines changed

4 files changed

+105
-13
lines changed

‎src/build/content/prerendered.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,30 @@ export const copyPrerenderedContent = async (ctx: PluginContext): Promise<void>
209209
await writeCacheEntry(key, value, lastModified, ctx)
210210
}),
211211
),
212-
...ctx.getFallbacks(manifest).map(async (route) => {
213-
const key = routeToFilePath(route)
214-
const value = await buildPagesCacheValue(
215-
join(ctx.publishDir, 'server/pages', key),
216-
undefined,
217-
shouldUseEnumKind,
218-
true, // there is no corresponding json file for fallback, so we are skipping it for this entry
219-
)
212+
...ctx.getFallbacks(manifest).map((route) =>
213+
limitConcurrentPrerenderContentHandling(async () => {
214+
const key = routeToFilePath(route)
215+
const value = await buildPagesCacheValue(
216+
join(ctx.publishDir, 'server/pages', key),
217+
undefined,
218+
shouldUseEnumKind,
219+
true, // there is no corresponding json file for fallback, so we are skipping it for this entry
220+
)
220221

221-
await writeCacheEntry(key, value, Date.now(), ctx)
222-
}),
222+
await writeCacheEntry(key, value, Date.now(), ctx)
223+
}),
224+
),
225+
...ctx.getShells(manifest).map((route) =>
226+
limitConcurrentPrerenderContentHandling(async () => {
227+
const key = routeToFilePath(route)
228+
const value = await buildAppCacheValue(
229+
join(ctx.publishDir, 'server/app', key),
230+
shouldUseAppPageKind,
231+
)
232+
233+
await writeCacheEntry(key, value, Date.now(), ctx)
234+
}),
235+
),
223236
])
224237

225238
// app router 404 pages are not in the prerender manifest

‎src/build/plugin-context.ts

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,13 @@ import type {
1010
NetlifyPluginOptions,
1111
NetlifyPluginUtils,
1212
} from '@netlify/build'
13-
import type { PrerenderManifest, RoutesManifest } from 'next/dist/build/index.js'
1413
import type { MiddlewareManifest } from 'next/dist/build/webpack/plugins/middleware-plugin.js'
1514
import type { PagesManifest } from 'next/dist/build/webpack/plugins/pages-manifest-plugin.js'
1615
import type { NextConfigComplete } from 'next/dist/server/config-shared.js'
16+
import type {
17+
PrerenderManifest,
18+
RoutesManifest,
19+
} from 'next-with-cache-handler-v2/dist/build/index.js'
1720
import { satisfies } from 'semver'
1821

1922
const MODULE_DIR = fileURLToPath(new URL('.', import.meta.url))
@@ -337,7 +340,7 @@ export class PluginContext {
337340

338341
#fallbacks: string[] | null = null
339342
/**
340-
* Get an array of localized fallback routes
343+
* Get an array of localized fallback routes for Pages Router
341344
*
342345
* Example return value for non-i18n site: `['blog/[slug]']`
343346
*
@@ -356,7 +359,7 @@ export class PluginContext {
356359
// - `string` - when user use pages router with `fallback: true`, and then it's html file path
357360
// - `null` - when user use pages router with `fallback: 'block'` or app router with `export const dynamicParams = true`
358361
// - `false` - when user use pages router with `fallback: false` or app router with `export const dynamicParams = false`
359-
if (typeof meta.fallback === 'string') {
362+
if (typeof meta.fallback === 'string'&&meta.renderingMode!=='PARTIALLY_STATIC') {
360363
for (const locale of locales) {
361364
const localizedRoute = posixJoin(locale, route.replace(/^\/+/g, ''))
362365
fallbacks.push(localizedRoute)
@@ -400,6 +403,26 @@ export class PluginContext {
400403
return this.#fullyStaticHtmlPages
401404
}
402405

406+
#shells: string[] | null = null
407+
/**
408+
* Get an array of static shells for App Router's PPR dynamic routes
409+
*/
410+
getShells(prerenderManifest: PrerenderManifest): string[] {
411+
if (!this.#shells) {
412+
this.#shells = Object.entries(prerenderManifest.dynamicRoutes).reduce(
413+
(shells, [route, meta]) => {
414+
if (typeof meta.fallback === 'string' && meta.renderingMode === 'PARTIALLY_STATIC') {
415+
shells.push(route)
416+
}
417+
return shells
418+
},
419+
[] as string[],
420+
)
421+
}
422+
423+
return this.#shells
424+
}
425+
403426
/** Fails a build with a message and an optional error */
404427
failBuild(message: string, error?: unknown): never {
405428
return this.utils.build.failBuild(message, error instanceof Error ? { error } : undefined)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { Suspense } from 'react'
2+
import { connection } from 'next/server'
3+
4+
export async function generateStaticParams() {
5+
return [{ dynamic: '1' }, { dynamic: '2' }]
6+
}
7+
8+
async function getData(params) {
9+
await connection()
10+
const res = await fetch(`https://api.tvmaze.com/shows/${params.id}`, {
11+
next: {
12+
tags: [`show-${params.id}`],
13+
},
14+
})
15+
await new Promise((res) => setTimeout(res, 3000))
16+
return res.json()
17+
}
18+
19+
async function Content(params) {
20+
const data = await getData(params)
21+
22+
return (
23+
<dl>
24+
<dt>Show</dt>
25+
<dd>{data.name}</dd>
26+
<dt>Param</dt>
27+
<dd>{params.id}</dd>
28+
<dt>Time</dt>
29+
<dd data-testid="date-now">{new Date().toISOString()}</dd>
30+
</dl>
31+
)
32+
}
33+
34+
export default async function DynamicPage({ params }) {
35+
const { dynamic } = await params
36+
37+
return (
38+
<main>
39+
<h1>Dynamic Page: {dynamic}</h1>
40+
<Suspense fallback={<div>loading...</div>}>
41+
<Content id={dynamic} />
42+
</Suspense>
43+
</main>
44+
)
45+
}

‎tests/integration/simple-app.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,10 @@ test.skipIf(process.env.NEXT_VERSION !== 'canary')<FixtureTestContext>(
394394
const blobEntries = await getBlobEntries(ctx)
395395
expect(blobEntries.map(({ key }) => decodeBlobKey(key)).sort()).toEqual(
396396
[
397+
'/1',
398+
'/2',
397399
'/404',
400+
'/[dynamic]',
398401
shouldHaveAppRouterGlobalErrorInPrerenderManifest() ? '/_global-error' : undefined,
399402
shouldHaveAppRouterNotFoundInPrerenderManifest() ? '/_not-found' : undefined,
400403
'/index',
@@ -407,6 +410,14 @@ test.skipIf(process.env.NEXT_VERSION !== 'canary')<FixtureTestContext>(
407410
const home = await invokeFunction(ctx)
408411
expect(home.statusCode).toBe(200)
409412
expect(load(home.body)('h1').text()).toBe('Home')
413+
414+
const dynamicPrerendered = await invokeFunction(ctx, { url: '/1' })
415+
expect(dynamicPrerendered.statusCode).toBe(200)
416+
expect(load(dynamicPrerendered.body)('h1').text()).toBe('Dynamic Page: 1')
417+
418+
const dynamicNotPrerendered = await invokeFunction(ctx, { url: '/3' })
419+
expect(dynamicNotPrerendered.statusCode).toBe(200)
420+
expect(load(dynamicNotPrerendered.body)('h1').text()).toBe('Dynamic Page: 3')
410421
},
411422
)
412423

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /