Skip to content

Commit

Permalink
removes static-generation-bailout entirely by refactoring last usages…
Browse files Browse the repository at this point in the history
… to other dynamic apis and bailout techniques
  • Loading branch information
gnoff committed Jan 23, 2024
1 parent d59e4b8 commit d61b0d6
Show file tree
Hide file tree
Showing 12 changed files with 464 additions and 342 deletions.
1 change: 0 additions & 1 deletion docs/02-app/02-api-reference/04-functions/next-request.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,6 @@ The following options are available:
| -------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `basePath` | `string` | The [base path](/docs/app/api-reference/next-config-js/basePath) of the URL. |
| `buildId` | `string` \| `undefined` | The build identifier of the Next.js application. Can be [customized](/docs/app/api-reference/next-config-js/generateBuildId). |
| `url` | `URL` | The URL object. |
| `pathname` | `string` | The pathname of the URL. |
| `searchParams` | `Object` | The search parameters of the URL. |

Expand Down
11 changes: 2 additions & 9 deletions packages/next/src/build/templates/app-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,8 @@ const routeModule = new AppRouteRouteModule({
// Pull out the exports that we need to expose from the module. This should
// be eliminated when we've moved the other routes to the new format. These
// are used to hook into the route.
const {
requestAsyncStorage,
staticGenerationAsyncStorage,
serverHooks,
headerHooks,
staticGenerationBailout,
} = routeModule
const { requestAsyncStorage, staticGenerationAsyncStorage, serverHooks } =
routeModule

const originalPathname = 'VAR_ORIGINAL_PATHNAME'

Expand All @@ -51,8 +46,6 @@ export {
requestAsyncStorage,
staticGenerationAsyncStorage,
serverHooks,
headerHooks,
staticGenerationBailout,
originalPathname,
patchFetch,
}
17 changes: 12 additions & 5 deletions packages/next/src/client/components/draft-mode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { DraftModeProvider } from '../../server/async-storage/draft-mode-provider'

import { staticGenerationBailout } from './static-generation-bailout'
import { staticGenerationAsyncStorage } from './static-generation-async-storage.external'
import { trackDynamicDataAccessed } from '../../server/app-render/dynamic-rendering'

export class DraftMode {
/**
Expand All @@ -15,14 +16,20 @@ export class DraftMode {
return this._provider.isEnabled
}
public enable() {
if (staticGenerationBailout('draftMode().enable()')) {
return
const store = staticGenerationAsyncStorage.getStore()
if (store) {
// We we have a store we want to track dynamic data access to ensure we
// don't statically generate routes that manipulate draft mode.
trackDynamicDataAccessed(store, 'draftMode().enable()')
}
return this._provider.enable()
}
public disable() {
if (staticGenerationBailout('draftMode().disable()')) {
return
const store = staticGenerationAsyncStorage.getStore()
if (store) {
// We we have a store we want to track dynamic data access to ensure we
// don't statically generate routes that manipulate draft mode.
trackDynamicDataAccessed(store, 'draftMode().disable()')
}
return this._provider.disable()
}
Expand Down
70 changes: 0 additions & 70 deletions packages/next/src/client/components/static-generation-bailout.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
import type { AppConfigDynamic } from '../../build/utils'

import React from 'react'
import { DynamicServerError } from './hooks-server-context'
import { staticGenerationAsyncStorage } from './static-generation-async-storage.external'

const hasPostpone = typeof React.unstable_postpone === 'function'

const NEXT_STATIC_GEN_BAILOUT = 'NEXT_STATIC_GEN_BAILOUT'

export class StaticGenBailoutError extends Error {
Expand All @@ -21,65 +13,3 @@ export function isStaticGenBailoutError(

return error.code === NEXT_STATIC_GEN_BAILOUT
}

type BailoutOpts = { dynamic?: AppConfigDynamic; link?: string }

export type StaticGenerationBailout = (
reason: string,
opts?: BailoutOpts
) => boolean | never

function formatErrorMessage(reason: string, opts?: BailoutOpts) {
const { dynamic, link } = opts || {}
const suffix = link ? ` See more info here: ${link}` : ''
return `Page${
dynamic ? ` with \`dynamic = "${dynamic}"\`` : ''
} couldn't be rendered statically because it used \`${reason}\`.${suffix}`
}

export const staticGenerationBailout: StaticGenerationBailout = (
reason,
{ dynamic, link } = {}
) => {
const staticGenerationStore = staticGenerationAsyncStorage.getStore()
if (!staticGenerationStore) return false

if (staticGenerationStore.forceStatic) {
return true
}

if (staticGenerationStore.dynamicShouldError) {
throw new StaticGenBailoutError(
formatErrorMessage(reason, { link, dynamic: dynamic ?? 'error' })
)
}

if (staticGenerationStore.prerenderState && hasPostpone) {
throw React.unstable_postpone(formatErrorMessage(reason, { link, dynamic }))
}

// As this is a bailout, we don't want to revalidate, so set the revalidate
// to 0.
staticGenerationStore.revalidate = 0

if (staticGenerationStore.isStaticGeneration) {
const err = new DynamicServerError(
formatErrorMessage(reason, {
dynamic,
// this error should be caught by Next to bail out of static generation
// in case it's uncaught, this link provides some additional context as to why
link: 'https://nextjs.org/docs/messages/dynamic-server-error',
})
)
staticGenerationStore.dynamicUsageDescription = reason
staticGenerationStore.dynamicUsageStack = err.stack

throw err
}

return false
}

// export function interuptStaticGeneration(store: StaticGenerationStore) {
// if (store.)
// }
24 changes: 15 additions & 9 deletions packages/next/src/server/app-render/create-component-tree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { validateRevalidate } from '../lib/patch-fetch'
import { PARALLEL_ROUTE_DEFAULT_PATH } from '../../client/components/parallel-route-default'
import { getTracer } from '../lib/trace/tracer'
import { NextNodeServerSpan } from '../lib/trace/constants'
import { StaticGenBailoutError } from '../../client/components/static-generation-bailout'

type ComponentTree = {
seedData: CacheNodeSeedData
Expand Down Expand Up @@ -80,7 +81,6 @@ async function createComponentTreeInternal({
renderOpts: { nextConfigOutput, experimental },
staticGenerationStore,
componentMod: {
staticGenerationBailout,
NotFoundBoundary,
LayoutRouter,
RenderFromTemplateContext,
Expand Down Expand Up @@ -185,12 +185,10 @@ async function createComponentTreeInternal({
if (!dynamic || dynamic === 'auto') {
dynamic = 'error'
} else if (dynamic === 'force-dynamic') {
staticGenerationStore.forceDynamic = true
staticGenerationStore.dynamicShouldError = true
staticGenerationBailout(`output: export`, {
dynamic,
link: 'https://nextjs.org/docs/advanced-features/static-html-export',
})
// force-dynamic is always incompatible with 'export'. We must interrupt the build
throw new StaticGenBailoutError(
`Page with \`dynamic = "force-dynamic"\` couldn't be exported. \`output: "export"\` requires all pages be renderable statically because there is not runtime server to dynamic render routes in this output format. Learn more: https://nextjs.org/docs/app/building-your-application/deploying/static-exports`
)
}
}

Expand All @@ -204,10 +202,18 @@ async function createComponentTreeInternal({
staticGenerationStore.forceDynamic = true

// TODO: (PPR) remove this bailout once PPR is the default
if (!staticGenerationStore.prerenderState) {
if (
staticGenerationStore.isStaticGeneration &&
!staticGenerationStore.prerenderState
) {
// If the postpone API isn't available, we can't postpone the render and
// therefore we can't use the dynamic API.
staticGenerationBailout(`force-dynamic`, { dynamic })
const err = new DynamicServerError(
`Page with \`dynamic = "force-dynamic"\` won't be rendered statically.`
)
staticGenerationStore.dynamicUsageDescription = err.message
staticGenerationStore.dynamicUsageStack = err.stack
throw err
}
} else {
staticGenerationStore.dynamicShouldError = false
Expand Down
2 changes: 0 additions & 2 deletions packages/next/src/server/app-render/entry-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import RenderFromTemplateContext from '../../client/components/render-from-templ
import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external'
import { requestAsyncStorage } from '../../client/components/request-async-storage.external'
import { actionAsyncStorage } from '../../client/components/action-async-storage.external'
import { staticGenerationBailout } from '../../client/components/static-generation-bailout'
import { ClientPageRoot } from '../../client/components/client-page'
import {
createUntrackedSearchParams,
Expand Down Expand Up @@ -45,7 +44,6 @@ export {
staticGenerationAsyncStorage,
requestAsyncStorage,
actionAsyncStorage,
staticGenerationBailout,
createUntrackedSearchParams,
createDynamicallyTrackedSearchParams,
serverHooks,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
* @param urlString the url to clean
* @returns the cleaned url
*/
export function cleanURL(urlString: string): string {
const url = new URL(urlString)
url.host = 'localhost:3000'
url.search = ''
url.protocol = 'http'
return url.toString()

export function cleanURL(url: string | URL): URL {
const u = new URL(url)
u.host = 'localhost:3000'
u.search = ''
u.protocol = 'http'
return u
}

This file was deleted.

Loading

0 comments on commit d61b0d6

Please sign in to comment.