Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

provide interception rewrites to edge runtime #61414

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/next-swc/crates/next-api/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -892,6 +892,7 @@ impl AppEndpoint {
"server/middleware-build-manifest.js".to_string(),
"server/middleware-react-loadable-manifest.js".to_string(),
"server/next-font-manifest.js".to_string(),
"server/interception-route-rewrite-manifest.js".to_string(),
];
let mut wasm_paths_from_root = vec![];

Expand Down
3 changes: 2 additions & 1 deletion packages/next/src/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -720,7 +720,6 @@ export default async function build(
.traceAsyncFn(() => loadCustomRoutes(config))

const { headers, rewrites, redirects } = customRoutes
NextBuildContext.rewrites = rewrites
NextBuildContext.originalRewrites = config._originalRewrites
NextBuildContext.originalRedirects = config._originalRedirects

Expand Down Expand Up @@ -984,6 +983,8 @@ export default async function build(
...generateInterceptionRoutesRewrites(appPaths, config.basePath)
)

NextBuildContext.rewrites = rewrites

const totalAppPagesCount = appPaths.length

const pageKeys = {
Expand Down
4 changes: 4 additions & 0 deletions packages/next/src/build/templates/edge-ssr-app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ const subresourceIntegrityManifest = sriEnabled
: undefined
const nextFontManifest = maybeJSONParse(self.__NEXT_FONT_MANIFEST)

const interceptionRouteRewrites =
maybeJSONParse(self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST) ?? []

const render = getRender({
pagesType: PAGE_TYPES.APP,
dev,
Expand All @@ -65,6 +68,7 @@ const render = getRender({
buildId: 'VAR_BUILD_ID',
nextFontManifest,
incrementalCacheHandler,
interceptionRouteRewrites,
})

export const ComponentMod = pageMod
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/build/webpack-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1803,6 +1803,7 @@ export default async function getBaseWebpackConfig(
new MiddlewarePlugin({
dev,
sriEnabled: !dev && !!config.experimental.sri?.algorithm,
rewrites,
}),
isClient &&
new BuildManifestPlugin({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
WebNextResponse,
} from '../../../../server/base-http/web'
import { SERVER_RUNTIME } from '../../../../lib/constants'
import type { PrerenderManifest } from '../../..'
import type { ManifestRewriteRoute, PrerenderManifest } from '../../..'
import { normalizeAppPath } from '../../../../shared/lib/router/utils/app-paths'
import type { SizeLimit } from '../../../../../types'
import { internal_getCurrentFunctionWaitUntil } from '../../../../server/web/internal-edge-wait-until'
Expand All @@ -31,6 +31,7 @@ export function getRender({
buildManifest,
prerenderManifest,
reactLoadableManifest,
interceptionRouteRewrites,
renderToHTML,
clientReferenceManifest,
subresourceIntegrityManifest,
Expand All @@ -54,6 +55,7 @@ export function getRender({
prerenderManifest: PrerenderManifest
reactLoadableManifest: ReactLoadableManifest
subresourceIntegrityManifest?: Record<string, string>
interceptionRouteRewrites?: ManifestRewriteRoute[]
clientReferenceManifest?: ClientReferenceManifest
serverActionsManifest?: any
serverActions?: {
Expand Down Expand Up @@ -85,6 +87,7 @@ export function getRender({
pathname: isAppPath ? normalizeAppPath(page) : page,
pagesType,
prerenderManifest,
interceptionRouteRewrites,
extendRenderOpts: {
buildId,
runtime: SERVER_RUNTIME.experimentalEdge,
Expand Down
40 changes: 31 additions & 9 deletions packages/next/src/build/webpack/plugins/middleware-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,16 @@ import {
NEXT_FONT_MANIFEST,
SERVER_REFERENCE_MANIFEST,
PRERENDER_MANIFEST,
INTERCEPTION_ROUTE_REWRITE_MANIFEST,
} from '../../../shared/lib/constants'
import type { MiddlewareConfig } from '../../analysis/get-page-static-info'
import type { Telemetry } from '../../../telemetry/storage'
import { traceGlobals } from '../../../trace/shared'
import { EVENT_BUILD_FEATURE_USAGE } from '../../../telemetry/events'
import { normalizeAppPath } from '../../../shared/lib/router/utils/app-paths'
import { INSTRUMENTATION_HOOK_FILENAME } from '../../../lib/constants'
import type { CustomRoutes } from '../../../lib/load-custom-routes'
import { isInterceptionRouteRewrite } from '../../../lib/generate-interception-routes-rewrites'

const KNOWN_SAFE_DYNAMIC_PACKAGES =
require('../../../lib/known-edge-safe-packages.json') as string[]
Expand Down Expand Up @@ -118,10 +121,10 @@ function getEntryFiles(

files.push(
`server/${MIDDLEWARE_BUILD_MANIFEST}.js`,
`server/${MIDDLEWARE_REACT_LOADABLE_MANIFEST}.js`
`server/${MIDDLEWARE_REACT_LOADABLE_MANIFEST}.js`,
`server/${NEXT_FONT_MANIFEST}.js`,
`server/${INTERCEPTION_ROUTE_REWRITE_MANIFEST}.js`
)

files.push(`server/${NEXT_FONT_MANIFEST}.js`)
}

if (hasInstrumentationHook) {
Expand All @@ -144,9 +147,7 @@ function getEntryFiles(
function getCreateAssets(params: {
compilation: webpack.Compilation
metadataByEntry: Map<string, EntryMetadata>
opts: {
sriEnabled: boolean
}
opts: Omit<Options, 'dev'>
}) {
const { compilation, metadataByEntry, opts } = params
return (assets: any) => {
Expand All @@ -161,6 +162,17 @@ function getCreateAssets(params: {
INSTRUMENTATION_HOOK_FILENAME
)

// we only emit this entry for the edge runtime since it doesn't have access to a routes manifest
// and we don't need to provide the entire route manifest, just the interception routes.
const interceptionRewrites = JSON.stringify(
opts.rewrites.beforeFiles.filter(isInterceptionRouteRewrite)
)
assets[`${INTERCEPTION_ROUTE_REWRITE_MANIFEST}.js`] = new sources.RawSource(
`self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST=${JSON.stringify(
interceptionRewrites
)}`
) as unknown as webpack.sources.RawSource

for (const entrypoint of compilation.entrypoints.values()) {
if (!entrypoint.name) {
continue
Expand Down Expand Up @@ -718,13 +730,22 @@ function getExtractMetadata(params: {
}
}
}

interface Options {
dev: boolean
sriEnabled: boolean
rewrites: CustomRoutes['rewrites']
}

export default class MiddlewarePlugin {
private readonly dev: boolean
private readonly sriEnabled: boolean
private readonly dev: Options['dev']
private readonly sriEnabled: Options['sriEnabled']
private readonly rewrites: Options['rewrites']

constructor({ dev, sriEnabled }: { dev: boolean; sriEnabled: boolean }) {
constructor({ dev, sriEnabled, rewrites }: Options) {
this.dev = dev
this.sriEnabled = sriEnabled
this.rewrites = rewrites
}

public apply(compiler: webpack.Compiler) {
Expand Down Expand Up @@ -769,6 +790,7 @@ export default class MiddlewarePlugin {
metadataByEntry,
opts: {
sriEnabled: this.sriEnabled,
rewrites: this.rewrites,
},
})
)
Expand Down
1 change: 1 addition & 0 deletions packages/next/src/client/route-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ declare global {
__RSC_SERVER_MANIFEST?: any
__NEXT_FONT_MANIFEST?: any
__SUBRESOURCE_INTEGRITY_MANIFEST?: string
__INTERCEPTION_ROUTE_REWRITE_MANIFEST?: string
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
isInterceptionRouteAppPath,
} from '../server/future/helpers/interception-routes'
import type { Rewrite } from './load-custom-routes'
import type { ManifestRewriteRoute } from '../build'

// a function that converts normalised paths (e.g. /foo/[bar]/[baz]) to the format expected by pathToRegexp (e.g. /foo/:bar/:baz)
function toPathToRegexpPath(path: string): string {
Expand Down Expand Up @@ -88,7 +87,7 @@ export function generateInterceptionRoutesRewrites(
return rewrites
}

export function isInterceptionRouteRewrite(route: ManifestRewriteRoute) {
export function isInterceptionRouteRewrite(route: Rewrite) {
// When we generate interception rewrites in the above implementation, we always do so with only a single `has` condition.
return route.has?.[0].key === NEXT_URL
}
3 changes: 1 addition & 2 deletions packages/next/src/server/lib/router-utils/filesystem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,6 @@ export async function setupFsCheck(opts: {
)
)
const rewrites = {
// TODO: add interception routes generateInterceptionRoutesRewrites()
beforeFiles: customRoutes.rewrites.beforeFiles.map((item) =>
buildCustomRoute('before_files_rewrite', item)
),
Expand Down Expand Up @@ -393,7 +392,7 @@ export async function setupFsCheck(opts: {
dynamicRoutes,
nextDataRoutes,

interceptionRoutes: undefined as
exportPathMapRoutes: undefined as
| undefined
| ReturnType<typeof buildCustomRoute<Rewrite>>[],

Expand Down
9 changes: 6 additions & 3 deletions packages/next/src/server/lib/router-utils/resolve-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,12 @@ export function getResolveRoutes(
}

if (params) {
if (fsChecker.interceptionRoutes && route.name === 'before_files_end') {
for (const interceptionRoute of fsChecker.interceptionRoutes) {
const result = await handleRoute(interceptionRoute)
if (
fsChecker.exportPathMapRoutes &&
route.name === 'before_files_end'
) {
for (const exportPathMapRoute of fsChecker.exportPathMapRoutes) {
const result = await handleRoute(exportPathMapRoute)

if (result) {
return result
Expand Down
79 changes: 52 additions & 27 deletions packages/next/src/server/lib/router-utils/setup-dev-bundler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ import { getRouteMatcher } from '../../../shared/lib/router/utils/route-matcher'
import { normalizePathSep } from '../../../shared/lib/page-path/normalize-path-sep'
import { createClientRouterFilter } from '../../../lib/create-client-router-filter'
import { absolutePathToPage } from '../../../shared/lib/page-path/absolute-path-to-page'
import { generateInterceptionRoutesRewrites } from '../../../lib/generate-interception-routes-rewrites'
import {
generateInterceptionRoutesRewrites,
isInterceptionRouteRewrite,
} from '../../../lib/generate-interception-routes-rewrites'
import { store as consoleStore } from '../../../build/output/store'

import {
Expand All @@ -87,6 +90,7 @@ import {
REACT_LOADABLE_MANIFEST,
MIDDLEWARE_REACT_LOADABLE_MANIFEST,
MIDDLEWARE_BUILD_MANIFEST,
INTERCEPTION_ROUTE_REWRITE_MANIFEST,
} from '../../../shared/lib/constants'

import { getMiddlewareRouteMatcher } from '../../../shared/lib/router/utils/middleware-route-matcher'
Expand Down Expand Up @@ -868,15 +872,32 @@ async function startWatcher(opts: SetupOpts) {
'server',
`${MIDDLEWARE_BUILD_MANIFEST}.js`
)
const interceptionRewriteManifestPath = path.join(
distDir,
'server',
`${INTERCEPTION_ROUTE_REWRITE_MANIFEST}.js`
)
deleteCache(buildManifestPath)
deleteCache(middlewareBuildManifestPath)
deleteCache(interceptionRewriteManifestPath)
await writeFileAtomic(
buildManifestPath,
JSON.stringify(buildManifest, null, 2)
)
await writeFileAtomic(
middlewareBuildManifestPath,
`self.__BUILD_MANIFEST=${JSON.stringify(buildManifest)}`
`self.__BUILD_MANIFEST=${JSON.stringify(buildManifest)};`
)

const interceptionRewrites = JSON.stringify(
rewrites.beforeFiles.filter(isInterceptionRouteRewrite)
)

await writeFileAtomic(
interceptionRewriteManifestPath,
`self.__INTERCEPTION_ROUTE_REWRITE_MANIFEST=${JSON.stringify(
interceptionRewrites
)};`
)

const content: ClientBuildManifest = {
Expand Down Expand Up @@ -2340,18 +2361,19 @@ async function startWatcher(opts: SetupOpts) {
? getMiddlewareRouteMatcher(serverFields.middleware?.matchers)
: undefined

opts.fsChecker.interceptionRoutes =
generateInterceptionRoutesRewrites(
Object.keys(appPaths),
opts.nextConfig.basePath
)?.map((item) =>
buildCustomRoute(
'before_files_rewrite',
item,
opts.nextConfig.basePath,
opts.nextConfig.experimental.caseSensitiveRoutes
)
) || []
const interceptionRoutes = generateInterceptionRoutesRewrites(
Object.keys(appPaths),
opts.nextConfig.basePath
).map((item) =>
buildCustomRoute(
'before_files_rewrite',
item,
opts.nextConfig.basePath,
opts.nextConfig.experimental.caseSensitiveRoutes
)
)

opts.fsChecker.rewrites.beforeFiles.push(...interceptionRoutes)

const exportPathMap =
(typeof nextConfig.exportPathMap === 'function' &&
Expand All @@ -2367,19 +2389,22 @@ async function startWatcher(opts: SetupOpts) {
))) ||
{}

for (const [key, value] of Object.entries(exportPathMap || {})) {
opts.fsChecker.interceptionRoutes.push(
buildCustomRoute(
'before_files_rewrite',
{
source: key,
destination: `${value.page}${
value.query ? '?' : ''
}${qs.stringify(value.query)}`,
},
opts.nextConfig.basePath,
opts.nextConfig.experimental.caseSensitiveRoutes
)
const exportPathMapEntries = Object.entries(exportPathMap || {})

if (exportPathMapEntries.length > 0) {
opts.fsChecker.exportPathMapRoutes = exportPathMapEntries.map(
([key, value]) =>
buildCustomRoute(
'before_files_rewrite',
{
source: key,
destination: `${value.page}${
value.query ? '?' : ''
}${qs.stringify(value.query)}`,
},
opts.nextConfig.basePath,
opts.nextConfig.experimental.caseSensitiveRoutes
)
)
}

Expand Down
2 changes: 2 additions & 0 deletions packages/next/src/server/next-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,8 @@ export default class NextNodeServer extends BaseServer {
}

protected getinterceptionRoutePatterns(): RegExp[] {
if (!this.enabledDirectories.app) return []

const routesManifest = this.getRoutesManifest()
return (
routesManifest?.rewrites.beforeFiles
Expand Down
10 changes: 8 additions & 2 deletions packages/next/src/server/web-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { getNamedRouteRegex } from '../shared/lib/router/utils/route-regex'
import { getRouteMatcher } from '../shared/lib/router/utils/route-matcher'
import { IncrementalCache } from './lib/incremental-cache'
import type { PAGE_TYPES } from '../lib/page-types'
import type { Rewrite } from '../lib/load-custom-routes'
import { buildCustomRoute } from '../lib/build-custom-route'

interface WebServerOptions extends Options {
webServerConfig: {
Expand All @@ -44,6 +46,7 @@ interface WebServerOptions extends Options {
| undefined
incrementalCacheHandler?: any
prerenderManifest: PrerenderManifest | undefined
interceptionRouteRewrites?: Rewrite[]
}
}

Expand Down Expand Up @@ -395,7 +398,10 @@ export default class NextWebServer extends BaseServer<WebServerOptions> {
}

protected getinterceptionRoutePatterns(): RegExp[] {
// TODO: This needs to be implemented.
return []
return (
this.serverOptions.webServerConfig.interceptionRouteRewrites?.map(
(rewrite) => new RegExp(buildCustomRoute('rewrite', rewrite).regex)
) ?? []
)
}
}
Loading