Skip to content

Commit

Permalink
refactor: enforce typings on component modules
Browse files Browse the repository at this point in the history
  • Loading branch information
wyattjoh committed Oct 5, 2023
1 parent feca3ce commit 2da74a3
Show file tree
Hide file tree
Showing 20 changed files with 119 additions and 114 deletions.
12 changes: 6 additions & 6 deletions packages/next/src/build/templates/app-page.ts
@@ -1,13 +1,13 @@
import type { LoaderTree } from '../../server/lib/app-dir-module'

// @ts-ignore this need to be imported from next/dist to be external
import * as module from 'next/dist/server/future/route-modules/app-page/module.compiled'
import { RouteKind } from '../../server/future/route-kind'

const AppPageRouteModule =
module.AppPageRouteModule as unknown as typeof import('../../server/future/route-modules/app-page/module').AppPageRouteModule
import { AppPageRouteModule } from 'next/dist/server/future/route-modules/app-page/module.compiled'
import { RouteKind } from 'next/dist/server/future/route-kind'

// These are injected by the loader afterwards.

/**
* The tree created in next-app-loader that holds component segments and modules
*/
declare const tree: LoaderTree
declare const pages: any

Expand Down
13 changes: 5 additions & 8 deletions packages/next/src/build/templates/app-route.ts
@@ -1,17 +1,14 @@
import '../../server/node-polyfill-headers'

// @ts-ignore this need to be imported from next/dist to be external
import * as module from 'next/dist/server/future/route-modules/app-route/module.compiled'

import type { AppRouteRouteModuleOptions } from '../../server/future/route-modules/app-route/module'
import { RouteKind } from '../../server/future/route-kind'
import {
AppRouteRouteModule,
type AppRouteRouteModuleOptions,
} from 'next/dist/server/future/route-modules/app-route/module.compiled'
import { RouteKind } from 'next/dist/server/future/route-kind'

// @ts-expect-error - replaced by webpack/turbopack loader
import * as userland from 'VAR_USERLAND'

const AppRouteRouteModule =
module.AppRouteRouteModule as unknown as typeof import('../../server/future/route-modules/app-route/module').AppRouteRouteModule

// These are injected by the loader afterwards. This is injected as a variable
// instead of a replacement because this could also be `undefined` instead of
// an empty string.
Expand Down
4 changes: 3 additions & 1 deletion packages/next/src/build/templates/middleware.ts
@@ -1,5 +1,7 @@
import '../../server/web/globals'
import type { AdapterOptions } from '../../server/web/adapter'

import '../../server/web/globals'

import { adapter } from '../../server/web/adapter'

// Import the userland code.
Expand Down
8 changes: 2 additions & 6 deletions packages/next/src/build/templates/pages-api.ts
@@ -1,12 +1,8 @@
// @ts-ignore this need to be imported from next/dist to be external
import * as module from 'next/dist/server/future/route-modules/pages-api/module.compiled'
import { PagesAPIRouteModule } from 'next/dist/server/future/route-modules/pages-api/module.compiled'
import { RouteKind } from 'next/dist/server/future/route-kind'

import { RouteKind } from '../../server/future/route-kind'
import { hoist } from './helpers'

const PagesAPIRouteModule =
module.PagesAPIRouteModule as unknown as typeof import('../../server/future/route-modules/pages-api/module').PagesAPIRouteModule

// Import the userland code.
// @ts-expect-error - replaced by webpack/turbopack loader
import * as userland from 'VAR_USERLAND'
Expand Down
4 changes: 3 additions & 1 deletion packages/next/src/build/templates/pages-edge-api.ts
@@ -1,5 +1,7 @@
import '../../server/web/globals'
import type { AdapterOptions } from '../../server/web/adapter'

import '../../server/web/globals'

import { adapter } from '../../server/web/adapter'
import { IncrementalCache } from '../../server/lib/incremental-cache'

Expand Down
8 changes: 2 additions & 6 deletions packages/next/src/build/templates/pages.ts
@@ -1,6 +1,5 @@
// @ts-ignore this need to be imported from next/dist to be external
import * as module from 'next/dist/server/future/route-modules/pages/module.compiled'
import { RouteKind } from '../../server/future/route-kind'
import { PagesRouteModule } from 'next/dist/server/future/route-modules/pages/module.compiled'
import { RouteKind } from 'next/dist/server/future/route-kind'
import { hoist } from './helpers'

// Import the app and document modules.
Expand All @@ -13,9 +12,6 @@ import App from 'VAR_MODULE_APP'
// @ts-expect-error - replaced by webpack/turbopack loader
import * as userland from 'VAR_USERLAND'

const PagesRouteModule =
module.PagesRouteModule as unknown as typeof import('../../server/future/route-modules/pages/module').PagesRouteModule

// Re-export the component (should be the default export).
export default hoist(userland, 'default')

Expand Down
23 changes: 5 additions & 18 deletions packages/next/src/build/utils.ts
Expand Up @@ -14,7 +14,6 @@ import type {
EdgeFunctionDefinition,
MiddlewareManifest,
} from './webpack/plugins/middleware-plugin'
import type { StaticGenerationAsyncStorage } from '../client/components/static-generation-async-storage.external'
import type { WebpackLayerName } from '../lib/constants'

import '../server/require-hook'
Expand Down Expand Up @@ -68,6 +67,7 @@ import { nodeFs } from '../server/lib/node-fs-methods'
import * as ciEnvironment from '../telemetry/ci-info'
import { normalizeAppPath } from '../shared/lib/router/utils/app-paths'
import { denormalizeAppPagePath } from '../shared/lib/page-path/denormalize-app-path'
import { AppPageModule } from '../server/future/route-modules/app-page/module'

const { AppRouteRouteModule } =
require('../server/future/route-modules/app-route/module.compiled') as typeof import('../server/future/route-modules/app-route/module')
Expand Down Expand Up @@ -1469,25 +1469,12 @@ export async function isPageStatic({
| undefined

if (pageType === 'app') {
isClientComponent = isClientReference(componentsResult.ComponentMod)
const tree = componentsResult.ComponentMod.tree

const staticGenerationAsyncStorage: StaticGenerationAsyncStorage =
componentsResult.ComponentMod.staticGenerationAsyncStorage
if (!staticGenerationAsyncStorage) {
throw new Error(
'Invariant: staticGenerationAsyncStorage should be defined on the module'
)
}
const ComponentMod: AppPageModule = componentsResult.ComponentMod

const serverHooks = componentsResult.ComponentMod.serverHooks
if (!serverHooks) {
throw new Error(
'Invariant: serverHooks should be defined on the module'
)
}
isClientComponent = isClientReference(componentsResult.ComponentMod)

const { routeModule } = componentsResult
const { tree, staticGenerationAsyncStorage, serverHooks, routeModule } =
ComponentMod

const generateParams: GenerateParams =
routeModule && AppRouteRouteModule.is(routeModule)
Expand Down
68 changes: 25 additions & 43 deletions packages/next/src/server/app-render/app-render.tsx
Expand Up @@ -10,9 +10,6 @@ import type {
RenderOpts,
Segment,
} from './types'
import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external'
import type { StaticGenerationBailout } from '../../client/components/static-generation-bailout'
import type { RequestAsyncStorage } from '../../client/components/request-async-storage.external'

import React from 'react'
import { createServerComponentRenderer } from './create-server-components-renderer'
Expand Down Expand Up @@ -237,6 +234,7 @@ export const renderToHTMLOrFlight: AppPageRender = (
})

patchFetch(ComponentMod)

/**
* Rules of Static & Dynamic HTML:
*
Expand All @@ -252,12 +250,25 @@ export const renderToHTMLOrFlight: AppPageRender = (
*/
const generateStaticHTML = supportsDynamicHTML !== true

const staticGenerationAsyncStorage: StaticGenerationAsyncStorage =
ComponentMod.staticGenerationAsyncStorage
const requestAsyncStorage: RequestAsyncStorage =
ComponentMod.requestAsyncStorage
const staticGenerationBailout: StaticGenerationBailout =
ComponentMod.staticGenerationBailout
// Pull out the hooks/references from the component.
const {
staticGenerationAsyncStorage,
requestAsyncStorage,
staticGenerationBailout,
LayoutRouter,
RenderFromTemplateContext,
createSearchParamsBailoutProxy,
StaticGenerationSearchParamsBailoutProvider,
serverHooks: { DynamicServerError },
NotFoundBoundary,
renderToReadableStream,
AppRouter,
GlobalError,
tree: loaderTree,
preloadFont,
preconnect,
preloadStyle,
} = ComponentMod

// we wrap the render in an AsyncLocalStorage context
const wrappedRender = async () => {
Expand Down Expand Up @@ -294,11 +305,6 @@ export const renderToHTMLOrFlight: AppPageRender = (
)
: undefined

/**
* The tree created in next-app-loader that holds component segments and modules
*/
const loaderTree: LoaderTree = ComponentMod.tree

/**
* The metadata items array created in next-app-loader with all relevant information
* that we need to resolve the final metadata.
Expand All @@ -312,15 +318,6 @@ export const renderToHTMLOrFlight: AppPageRender = (
requestId = require('next/dist/compiled/nanoid').nanoid()
}

const LayoutRouter =
ComponentMod.LayoutRouter as typeof import('../../client/components/layout-router').default
const RenderFromTemplateContext =
ComponentMod.RenderFromTemplateContext as typeof import('../../client/components/render-from-template-context').default
const createSearchParamsBailoutProxy =
ComponentMod.createSearchParamsBailoutProxy as typeof import('../../client/components/searchparams-bailout-proxy').createSearchParamsBailoutProxy
const StaticGenerationSearchParamsBailoutProvider =
ComponentMod.StaticGenerationSearchParamsBailoutProvider as typeof import('../../client/components/static-generation-searchparams-bailout-provider').default

const isStaticGeneration = staticGenerationStore.isStaticGeneration
// During static generation we need to call the static generation bailout when reading searchParams
const providedSearchParams = isStaticGeneration
Expand Down Expand Up @@ -511,16 +508,16 @@ export const renderToHTMLOrFlight: AppPageRender = (
const ext = /\.(woff|woff2|eot|ttf|otf)$/.exec(fontFilename)![1]
const type = `font/${ext}`
const href = `${assetPrefix}/_next/${fontFilename}`
ComponentMod.preloadFont(href, type, renderOpts.crossOrigin)
preloadFont(href, type, renderOpts.crossOrigin)
}
} else {
try {
let url = new URL(assetPrefix)
ComponentMod.preconnect(url.origin, 'anonymous')
preconnect(url.origin, 'anonymous')
} catch (error) {
// assetPrefix must not be a fully qualified domain name. We assume
// we should preconnect to same origin instead
ComponentMod.preconnect('/', 'anonymous')
preconnect('/', 'anonymous')
}
}
}
Expand All @@ -546,7 +543,7 @@ export const renderToHTMLOrFlight: AppPageRender = (
const precedence =
process.env.NODE_ENV === 'development' ? 'next_' + href : 'next'

ComponentMod.preloadStyle(fullHref, renderOpts.crossOrigin)
preloadStyle(fullHref, renderOpts.crossOrigin)

return (
<link
Expand Down Expand Up @@ -732,9 +729,6 @@ export const renderToHTMLOrFlight: AppPageRender = (
staticGenerationStore.isStaticGeneration &&
defaultRevalidate === 0
) {
const { DynamicServerError } =
ComponentMod.serverHooks as typeof import('../../client/components/hooks-server-context')

const dynamicUsageDescription = `revalidate: 0 configured ${segment}`
staticGenerationStore.dynamicUsageDescription =
dynamicUsageDescription
Expand All @@ -759,8 +753,6 @@ export const renderToHTMLOrFlight: AppPageRender = (
const hasSlotKey = parallelKeys.length > 1

if (hasSlotKey && rootLayoutAtThisLevel) {
const NotFoundBoundary =
ComponentMod.NotFoundBoundary as typeof import('../../client/components/not-found-boundary').NotFoundBoundary
Component = (componentProps: any) => {
const NotFoundComponent = NotFound
const RootLayoutComponent = LayoutOrPage
Expand Down Expand Up @@ -1287,7 +1279,7 @@ export const renderToHTMLOrFlight: AppPageRender = (

// For app dir, use the bundled version of Flight server renderer (renderToReadableStream)
// which contains the subset React.
const flightReadableStream = ComponentMod.renderToReadableStream(
const flightReadableStream = renderToReadableStream(
options
? [options.actionResult, buildIdFlightDataPair]
: buildIdFlightDataPair,
Expand All @@ -1305,16 +1297,6 @@ export const renderToHTMLOrFlight: AppPageRender = (
return generateFlight()
}

// Below this line is handling for rendering to HTML.

// AppRouter is provided by next-app-loader
const AppRouter =
ComponentMod.AppRouter as typeof import('../../client/components/app-router').default

const GlobalError =
/** GlobalError can be either the default error boundary or the overwritten app/global-error.js **/
ComponentMod.GlobalError as typeof import('../../client/components/error-boundary').GlobalError

// Get the nonce from the incoming request if it has one.
const csp = req.headers['content-security-policy']
let nonce: string | undefined
Expand Down
@@ -1,5 +1,6 @@
import type { RenderOpts } from './types'
import type { FlightResponseRef } from './flight-response-ref'
import type { AppPageModule } from '../future/route-modules/app-page/module'

import React, { use } from 'react'
import { createErrorHandler } from './create-error-handler'
Expand All @@ -11,13 +12,7 @@ import { useFlightResponse } from './use-flight-response'
*/
export function createServerComponentRenderer<Props>(
ComponentToRender: (props: Props) => any,
ComponentMod: {
renderToReadableStream: any
__next_app__?: {
require: any
loadChunk: any
}
},
ComponentMod: AppPageModule,
{
inlinedDataTransformStream,
clientReferenceManifest,
Expand Down
8 changes: 2 additions & 6 deletions packages/next/src/server/app-render/entry-base.ts
@@ -1,10 +1,10 @@
const {
export {
renderToReadableStream,
decodeReply,
decodeAction,
decodeFormState,
// eslint-disable-next-line import/no-extraneous-dependencies
} = require('react-server-dom-webpack/server.edge')
} from 'react-server-dom-webpack/server.edge'

import AppRouter from '../../client/components/app-router'
import LayoutRouter from '../../client/components/layout-router'
Expand Down Expand Up @@ -36,10 +36,6 @@ export {
staticGenerationBailout,
createSearchParamsBailoutProxy,
serverHooks,
renderToReadableStream,
decodeReply,
decodeAction,
decodeFormState,
preloadStyle,
preloadFont,
preconnect,
Expand Down
6 changes: 4 additions & 2 deletions packages/next/src/server/app-render/types.ts
@@ -1,9 +1,10 @@
import type { LoadComponentsReturnType } from '../load-components'
import type { ServerRuntime, SizeLimit } from '../../../types'
import { NextConfigComplete } from '../../server/config-shared'
import type { NextConfigComplete } from '../../server/config-shared'
import type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin'
import type { NextFontManifest } from '../../build/webpack/plugins/next-font-manifest-plugin'
import type { ParsedUrlQuery } from 'querystring'
import type { AppPageModule } from '../future/route-modules/app-page/module'

import s from 'next/dist/compiled/superstruct'

Expand Down Expand Up @@ -135,4 +136,5 @@ export interface RenderOptsPartial {
isPrefetch?: boolean
}

export type RenderOpts = LoadComponentsReturnType & RenderOptsPartial
export type RenderOpts = LoadComponentsReturnType<AppPageModule> &
RenderOptsPartial
Expand Up @@ -22,6 +22,13 @@ if (process.env.NEXT_RUNTIME !== 'edge') {
vendoredReactSSR = require('./vendored/ssr/entrypoints')
}

/**
* The AppPageModule is the type of the module exported by the bundled app page
* module.
*/
export type AppPageModule =
typeof import('../../../../build/templates/app-page')

type AppPageUserlandModule = {
/**
* The tree created in next-app-loader that holds component segments and modules
Expand Down
Expand Up @@ -44,6 +44,13 @@ import { staticGenerationAsyncStorage } from '../../../../client/components/stat
import { actionAsyncStorage } from '../../../../client/components/action-async-storage.external'
import * as sharedModules from './shared-modules'

/**
* The AppRouteModule is the type of the module exported by the bundled App
* Route module.
*/
export type AppRouteModule =
typeof import('../../../../build/templates/app-route')

/**
* AppRouteRouteHandlerContext is the context that is passed to the route
* handler for app routes.
Expand Down
Expand Up @@ -16,6 +16,13 @@ type PagesAPIHandleFn = (
res: ServerResponse
) => Promise<void>

/**
* The PagesAPIModule is the type of the module exported by the bundled Pages
* API module.
*/
export type PagesAPIModule =
typeof import('../../../../build/templates/pages-api')

type PagesAPIUserlandModule = {
/**
* The exported handler method.
Expand Down

0 comments on commit 2da74a3

Please sign in to comment.