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

Remove Route Handlers #53462

Merged
merged 1 commit into from
Aug 1, 2023
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
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { EdgeRouteModuleWrapper } from 'next/dist/server/web/edge-route-module-wrapper'

import RouteModule from 'ROUTE_MODULE'
import { AppRouteRouteModule } from 'next/dist/server/future/route-modules/app-route/module'
import { RouteKind } from 'next/dist/server/future/route-kind'
import * as userland from 'ENTRY'
import { PAGE, PATHNAME, KIND } from 'BOOTSTRAP_CONFIG'
import { PAGE, PATHNAME } from 'BOOTSTRAP_CONFIG'

// TODO: (wyattjoh) - perform the option construction in Rust to allow other modules to accept different options
const routeModule = new RouteModule({
const routeModule = new AppRouteRouteModule({
userland,
definition: {
kind: RouteKind.APP_ROUTE,
page: PAGE,
kind: KIND,
pathname: PATHNAME,
// The following aren't used in production.
filename: '',
Expand All @@ -22,6 +23,8 @@ const routeModule = new RouteModule({
// @ts-expect-error - exposed for edge support
globalThis._ENTRIES = {
middleware_edge: {
default: EdgeRouteModuleWrapper.wrap(routeModule, { page: `/${PAGE}` }),
default: EdgeRouteModuleWrapper.wrap(routeModule, {
page: `/${PAGE}`,
}),
},
}
9 changes: 5 additions & 4 deletions packages/next-swc/crates/next-core/js/src/entry/app/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
// the other imports
import startHandler from '../../internal/nodejs-proxy-handler'

import RouteModule from 'ROUTE_MODULE'
import AppRouteRouteModule from 'next/dist/server/future/route-modules/app-route/module'
import { RouteKind } from 'next/dist/server/future/route-kind'
import * as userland from 'ENTRY'
import { PAGE, PATHNAME, KIND } from 'BOOTSTRAP_CONFIG'
import { PAGE, PATHNAME } from 'BOOTSTRAP_CONFIG'

const routeModule = new RouteModule({
const routeModule = new AppRouteRouteModule({
userland,
definition: {
kind: RouteKind.APP_ROUTE,
page: PAGE,
kind: KIND,
pathname: PATHNAME,
// The following aren't used in production.
filename: '',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ import {
NextRequestAdapter,
signalFromNodeResponse,
} from 'next/dist/server/web/spec-extension/adapters/next-request'
import { RouteHandlerManagerContext } from 'next/dist/server/future/route-handler-managers/route-handler-manager'

import { attachRequestMeta } from './next-request-helpers'

import type { RouteModule } from 'next/dist/server/future/route-modules/route-module'
import type {
AppRouteRouteHandlerContext,
AppRouteRouteModule,
} from 'next/dist/server/future/route-modules/app-route/module'

export default (routeModule: RouteModule) => {
export default (routeModule: AppRouteRouteModule) => {
startHandler(async ({ request, response, params }) => {
const req = new NodeNextRequest(request)
const res = new NodeNextResponse(response)

const parsedUrl = parseUrl(req.url!, true)
attachRequestMeta(req, parsedUrl, request.headers.host!)

const context: RouteHandlerManagerContext = {
const context: AppRouteRouteHandlerContext = {
params,
prerenderManifest: {
version: -1 as any, // letting us know this doesn't conform to spec
Expand Down
18 changes: 0 additions & 18 deletions packages/next-swc/crates/next-core/js/types/rust.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,28 +56,10 @@ declare module 'ENTRY' {
export = module
}

declare module 'ROUTE_MODULE' {
import {
RouteModule,
type RouteModuleOptions,
} from 'next/dist/server/future/route-modules/route-module'

/**
* This is the implementation class for the route module. This provides base
* typing for the options and context.
*/
export default class<O extends RouteModuleOptions> extends RouteModule {
constructor(options: O)
}
}

declare module 'BOOTSTRAP_CONFIG' {
import type { RouteKind } from 'next/dist/server/future/route-kind'

export const NAME: string
export const PAGE: string
export const PATHNAME: string
export const KIND: RouteKind
}

declare module 'APP_BOOTSTRAP' {
Expand Down
38 changes: 4 additions & 34 deletions packages/next-swc/crates/next-core/src/bootstrap.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
use anyhow::{bail, Result};
use indexmap::{indexmap, IndexMap};
use indexmap::IndexMap;
use turbo_tasks::{Value, ValueToString, Vc};
use turbo_tasks_fs::{File, FileSystemPath};
use turbopack_binding::turbopack::{
core::{
asset::AssetContent,
chunk::EvaluatableAsset,
context::AssetContext,
issue::{IssueSeverity, OptionIssueSource},
module::Module,
reference_type::{EcmaScriptModulesReferenceSubType, InnerAssets, ReferenceType},
resolve::parse::Request,
reference_type::{InnerAssets, ReferenceType},
source::Source,
virtual_source::VirtualSource,
},
ecmascript::{resolve::esm_resolve, utils::StringifyJs, EcmascriptModuleAsset},
ecmascript::utils::StringifyJs,
};

#[turbo_tasks::function]
Expand All @@ -25,39 +23,12 @@ pub async fn route_bootstrap(
bootstrap_asset: Vc<Box<dyn Source>>,
config: Vc<BootstrapConfig>,
) -> Result<Vc<Box<dyn EvaluatableAsset>>> {
let resolve_origin =
if let Some(m) = Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(asset).await? {
Vc::upcast(m)
} else {
bail!("asset does not represent an ecmascript module");
};

// TODO: this is where you'd switch the route kind to the one you need
let route_module_kind = "app-route";

let resolved_route_module = esm_resolve(
resolve_origin,
Request::parse_string(format!(
"next/dist/server/future/route-modules/{}/module",
route_module_kind
)),
Value::new(EcmaScriptModulesReferenceSubType::Undefined),
OptionIssueSource::none(),
IssueSeverity::Error.cell(),
);
let route_module = match *resolved_route_module.first_module().await? {
Some(module) => module,
None => bail!("could not find app asset"),
};

Ok(bootstrap(
asset,
context,
base_path,
bootstrap_asset,
Vc::cell(indexmap! {
"ROUTE_MODULE".to_string() => route_module,
}),
Vc::cell(IndexMap::new()),
config,
))
}
Expand Down Expand Up @@ -105,7 +76,6 @@ pub async fn bootstrap(
let mut config = config.await?.clone_value();
config.insert("PAGE".to_string(), path.to_string());
config.insert("PATHNAME".to_string(), pathname);
config.insert("KIND".to_string(), "APP_ROUTE".to_string());

let config_asset = context.process(
Vc::upcast(VirtualSource::new(
Expand Down
73 changes: 21 additions & 52 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,12 @@ import type { NextFontManifest } from '../build/webpack/plugins/next-font-manife
import type { PagesRouteModule } from './future/route-modules/pages/module'
import type { AppPageRouteModule } from './future/route-modules/app-page/module'
import type { NodeNextRequest, NodeNextResponse } from './base-http/node'
import type { AppRouteRouteMatch } from './future/route-matches/app-route-route-match'
import type { RouteDefinition } from './future/route-definitions/route-definition'
import type { WebNextRequest, WebNextResponse } from './base-http/web'
import type { PagesAPIRouteMatch } from './future/route-matches/pages-api-route-match'
import type {
AppRouteRouteHandlerContext,
AppRouteRouteModule,
} from './future/route-modules/app-route/module'

import { format as formatUrl, parse as parseUrl } from 'url'
import { getRedirectStatus } from '../lib/redirect-status'
Expand Down Expand Up @@ -88,10 +90,6 @@ import {
MatchOptions,
RouteMatcherManager,
} from './future/route-matcher-managers/route-matcher-manager'
import {
RouteHandlerManager,
type RouteHandlerManagerContext,
} from './future/route-handler-managers/route-handler-manager'
import { LocaleRouteNormalizer } from './future/normalizers/locale-route-normalizer'
import { DefaultRouteMatcherManager } from './future/route-matcher-managers/default-route-matcher-manager'
import { AppPageRouteMatcherProvider } from './future/route-matcher-providers/app-page-route-matcher-provider'
Expand All @@ -110,13 +108,11 @@ import {
toNodeOutgoingHttpHeaders,
} from './web/utils'
import { NEXT_QUERY_PARAM_PREFIX } from '../lib/constants'
import {
isRouteMatch,
parsedUrlQueryToParams,
type RouteMatch,
} from './future/route-matches/route-match'
import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path'
import { signalFromNodeResponse } from './web/spec-extension/adapters/next-request'
import {
NextRequestAdapter,
signalFromNodeResponse,
} from './web/spec-extension/adapters/next-request'

export type FindComponentsResult = {
components: LoadComponentsReturnType
Expand Down Expand Up @@ -343,7 +339,6 @@ export default abstract class Server<ServerOptions extends Options = Options> {

// TODO-APP: (wyattjoh): Make protected again. Used for turbopack in route-resolver.ts right now.
public readonly matchers: RouteMatcherManager
protected readonly handlers: RouteHandlerManager
protected readonly i18nProvider?: I18NProvider
protected readonly localeNormalizer?: LocaleRouteNormalizer
protected readonly isRenderWorker?: boolean
Expand Down Expand Up @@ -462,9 +457,8 @@ export default abstract class Server<ServerOptions extends Options = Options> {
this.appPathRoutes = this.getAppPathRoutes()

// Configure the routes.
const { matchers, handlers } = this.getRoutes()
const { matchers } = this.getRoutes()
this.matchers = matchers
this.handlers = handlers

// Start route compilation. We don't wait for the routes to finish loading
// because we use the `waitTillReady` promise below in `handleRequest` to
Expand Down Expand Up @@ -508,7 +502,6 @@ export default abstract class Server<ServerOptions extends Options = Options> {

protected getRoutes(): {
matchers: RouteMatcherManager
handlers: RouteHandlerManager
} {
// Create a new manifest loader that get's the manifests from the server.
const manifestLoader = new ServerManifestLoader((name) => {
Expand All @@ -524,7 +517,6 @@ export default abstract class Server<ServerOptions extends Options = Options> {

// Configure the matchers and handlers.
const matchers: RouteMatcherManager = new DefaultRouteMatcherManager()
const handlers = new RouteHandlerManager()

// Match pages under `pages/`.
matchers.push(
Expand Down Expand Up @@ -555,7 +547,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
)
}

return { matchers, handlers }
return { matchers }
}

public logError(err: Error): void {
Expand Down Expand Up @@ -1806,27 +1798,11 @@ export default abstract class Server<ServerOptions extends Options = Options> {
// served by the server.
let result: RenderResult

// Get the match for the page if it exists.
const match: RouteMatch<RouteDefinition<RouteKind>> | undefined =
getRequestMeta(req, '_nextMatch') ??
// If the match can't be found, rely on the loaded route module. This
// should only be required during development when we add FS routes.
((this.renderOpts.dev || process.env.NEXT_RUNTIME === 'edge') &&
components.routeModule
? {
definition: components.routeModule.definition,
params: opts.params
? parsedUrlQueryToParams(opts.params)
: undefined,
}
: undefined)
if (components.routeModule?.definition.kind === RouteKind.APP_ROUTE) {
const routeModule = components.routeModule as AppRouteRouteModule

if (
match &&
isRouteMatch<AppRouteRouteMatch>(match, RouteKind.APP_ROUTE)
) {
const context: RouteHandlerManagerContext = {
params: match.params,
const context: AppRouteRouteHandlerContext = {
params: opts.params,
prerenderManifest: this.getPrerenderManifest(),
staticGenerationContext: {
originalPathname: components.ComponentMod.originalPathname,
Expand All @@ -1837,14 +1813,13 @@ export default abstract class Server<ServerOptions extends Options = Options> {
}

try {
// Handle the match and collect the response if it's a static response.
const response = await this.handlers.handle(
match,
const request = NextRequestAdapter.fromBaseNextRequest(
req,
context,
signalFromNodeResponse((res as NodeNextResponse).originalResponse)
)

const response = await routeModule.handle(request, context)

;(req as any).fetchMetrics = (
context.staticGenerationContext as any
).fetchMetrics
Expand Down Expand Up @@ -1903,11 +1878,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
// If we've matched a page while not in edge where the module exports a
// `routeModule`, then we should be able to render it using the provided
// `render` method.
else if (
match &&
isRouteMatch(match, RouteKind.PAGES) &&
components.routeModule
) {
else if (components.routeModule?.definition.kind === RouteKind.PAGES) {
const module = components.routeModule as PagesRouteModule

// Due to the way we pass data by mutating `renderOpts`, we can't extend
Expand All @@ -1922,12 +1893,10 @@ export default abstract class Server<ServerOptions extends Options = Options> {
(req as NodeNextRequest).originalRequest ?? (req as WebNextRequest),
(res as NodeNextResponse).originalResponse ??
(res as WebNextResponse),
{ page: pathname, params: match.params, query, renderOpts }
{ page: pathname, params: opts.params, query, renderOpts }
)
} else if (
match &&
isRouteMatch(match, RouteKind.APP_PAGE) &&
components.routeModule
components.routeModule?.definition.kind === RouteKind.APP_PAGE
) {
const module = components.routeModule as AppPageRouteModule

Expand All @@ -1941,7 +1910,7 @@ export default abstract class Server<ServerOptions extends Options = Options> {
(req as NodeNextRequest).originalRequest ?? (req as WebNextRequest),
(res as NodeNextResponse).originalResponse ??
(res as WebNextResponse),
{ page: pathname, params: match.params, query, renderOpts }
{ page: pathname, params: opts.params, query, renderOpts }
)
} else {
// If we didn't match a page, we should fallback to using the legacy
Expand Down
3 changes: 1 addition & 2 deletions packages/next/src/server/dev/next-dev-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,6 @@ export default class DevServer extends Server {
ensurer,
this.dir
)
const handlers = routes.handlers
const extensions = this.nextConfig.pageExtensions
const fileReader = new CachedFileReader(new DefaultFileReader())

Expand Down Expand Up @@ -241,7 +240,7 @@ export default class DevServer extends Server {
)
}

return { matchers, handlers }
return { matchers }
}

protected getBuildId(): string {
Expand Down
Loading