Skip to content

Commit

Permalink
add page context logic
Browse files Browse the repository at this point in the history
  • Loading branch information
vordgi committed May 17, 2024
1 parent aed5242 commit 7191c04
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 4 deletions.
9 changes: 7 additions & 2 deletions packages/next/src/build/templates/app-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,12 @@ 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 } =
routeModule
const {
requestAsyncStorage,
staticGenerationAsyncStorage,
pageContextAsyncStorage,
serverHooks,
} = routeModule

const originalPathname = 'VAR_ORIGINAL_PATHNAME'

Expand All @@ -45,6 +49,7 @@ export {
routeModule,
requestAsyncStorage,
staticGenerationAsyncStorage,
pageContextAsyncStorage,
serverHooks,
originalPathname,
patchFetch,
Expand Down
5 changes: 5 additions & 0 deletions packages/next/src/client/components/get-page-context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { pageContextAsyncStorage } from './page-context-async-storage.external'

export const getPageContext = <T>() => {
return pageContextAsyncStorage.getStore() as T
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import type { PageContextAsyncStorage } from './page-context-async-storage.external'
import { createAsyncLocalStorage } from './async-local-storage'

export const pageContextAsyncStorage: PageContextAsyncStorage =
createAsyncLocalStorage()
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import type { AsyncLocalStorage } from 'async_hooks'

// Share the instance module in the next-shared layer
import { pageContextAsyncStorage } from './page-context-async-storage-instance' with { 'turbopack-transition': 'next-shared' }

export type PageStore = { [key: string]: unknown }

export type PageContextAsyncStorage = AsyncLocalStorage<PageStore>

export { pageContextAsyncStorage }
51 changes: 49 additions & 2 deletions packages/next/src/server/app-render/app-render.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import type {
import type { StaticGenerationStore } from '../../client/components/static-generation-async-storage.external'
import type { RequestStore } from '../../client/components/request-async-storage.external'
import type { NextParsedUrlQuery } from '../request-meta'
import type { LoaderTree } from '../lib/app-dir-module'
import { getLayoutOrPageModule, type LoaderTree } from '../lib/app-dir-module'
import type { AppPageModule } from '../future/route-modules/app-page/module'
import type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin'
import type { Revalidate } from '../lib/revalidate'
Expand Down Expand Up @@ -113,6 +113,7 @@ import {
import { createServerModuleMap } from './action-utils'
import { isNodeNextRequest } from '../base-http/helpers'
import { parseParameter } from '../../shared/lib/router/utils/route-regex'
import { PageContextAsyncStorageWrapper } from '../async-storage/page-context-async-storage-wrapper'

export type GetDynamicParamFromSegment = (
// [slug] / [[slug]] / [...slug]
Expand Down Expand Up @@ -1487,6 +1488,52 @@ export type AppPageRender = (
renderOpts: RenderOpts
) => Promise<RenderResult<AppPageRenderResultMetadata>>

async function getPage(treeArg: any): Promise<any> {
const [, parallelRoutes, { page }] = treeArg
const isPage = typeof page !== 'undefined'
if (isPage) {
const [mod] = await getLayoutOrPageModule(treeArg)
return mod
}
for (const key in parallelRoutes) {
const childTree = parallelRoutes[key]
const mod = await getPage(childTree)
if (mod) return mod
}
}

async function renderToHTMLOrFlightImplWrapper(
req: BaseNextRequest,
res: BaseNextResponse,
pagePath: string,
query: NextParsedUrlQuery,
renderOpts: RenderOpts,
baseCtx: AppRenderBaseContext,
requestEndedState: { ended?: boolean }
) {
const pageModule = await getPage(renderOpts.ComponentMod.tree)

let data = null
if (typeof pageModule.createPageContext === 'function') {
data = await pageModule.createPageContext({ params: renderOpts.params })
}

return PageContextAsyncStorageWrapper.wrap(
renderOpts.ComponentMod.pageContextAsyncStorage,
data,
() =>
renderToHTMLOrFlightImpl(
req,
res,
pagePath,
query,
renderOpts,
baseCtx,
requestEndedState
)
)
}

export const renderToHTMLOrFlight: AppPageRender = (
req,
res,
Expand All @@ -1509,7 +1556,7 @@ export const renderToHTMLOrFlight: AppPageRender = (
requestEndedState: { ended: false },
},
(staticGenerationStore) =>
renderToHTMLOrFlightImpl(
renderToHTMLOrFlightImplWrapper(
req,
res,
pagePath,
Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/server/app-render/entry-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import LayoutRouter from '../../client/components/layout-router'
import RenderFromTemplateContext from '../../client/components/render-from-template-context'
import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external'
import { requestAsyncStorage } from '../../client/components/request-async-storage.external'
import { pageContextAsyncStorage } from '../../client/components/page-context-async-storage.external'
import { actionAsyncStorage } from '../../client/components/action-async-storage.external'
import { ClientPageRoot } from '../../client/components/client-page'
import {
Expand Down Expand Up @@ -43,6 +44,7 @@ export {
RenderFromTemplateContext,
staticGenerationAsyncStorage,
requestAsyncStorage,
pageContextAsyncStorage,
actionAsyncStorage,
createUntrackedSearchParams,
createDynamicallyTrackedSearchParams,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { AsyncStorageWrapper } from './async-storage-wrapper'
import type { PageStore } from '../../client/components/page-context-async-storage.external'
import type { AsyncLocalStorage } from 'async_hooks'

type PageContext = { [key: string]: unknown }

export const PageContextAsyncStorageWrapper: AsyncStorageWrapper<
PageStore,
PageContext
> = {
wrap<Result>(
storage: AsyncLocalStorage<PageStore>,
ctx: PageContext,
callback: (store: PageStore) => Result
): Result {
// renderOpts.params
const store: PageStore = ctx

return storage.run(store, callback, store)
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { DynamicServerError } from '../../../../client/components/hooks-server-c

import { requestAsyncStorage } from '../../../../client/components/request-async-storage.external'
import { staticGenerationAsyncStorage } from '../../../../client/components/static-generation-async-storage.external'
import { pageContextAsyncStorage } from '../../../../client/components/page-context-async-storage.external'
import { actionAsyncStorage } from '../../../../client/components/action-async-storage.external'
import * as sharedModules from './shared-modules'
import { getIsServerAction } from '../../../lib/server-action-request-meta'
Expand Down Expand Up @@ -136,6 +137,11 @@ export class AppRouteRouteModule extends RouteModule<
*/
public readonly staticGenerationAsyncStorage = staticGenerationAsyncStorage

/**
* A reference to the page context async storage.
*/
public readonly pageContextAsyncStorage = pageContextAsyncStorage

/**
* An interface to call server hooks which interact with the underlying
* storage.
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/server/typescript/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const NEXT_TS_ERRORS = {
export const ALLOWED_EXPORTS = [
'config',
'generateStaticParams',
'createPageContext',
'metadata',
'generateMetadata',
'viewport',
Expand Down

0 comments on commit 7191c04

Please sign in to comment.