Revert "support runtime: edge in api endpoints" (#37337)

Revert "support `runtime: edge` in api endpoints (#36947)"

This reverts commit 3d1a287207.
This commit is contained in:
Shu Ding 2022-05-31 15:24:40 +02:00 committed by GitHub
parent 3d1a287207
commit ed0b580fc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 35 additions and 271 deletions

View file

@ -164,15 +164,6 @@ export function getEdgeServerEntry(opts: {
return `next-middleware-loader?${stringify(loaderParams)}!`
}
if (opts.page.startsWith('/api/')) {
const loaderParams: MiddlewareLoaderOptions = {
absolutePagePath: opts.absolutePagePath,
page: opts.page,
}
return `next-edge-function-loader?${stringify(loaderParams)}!`
}
const loaderParams: MiddlewareSSRLoaderQuery = {
absolute500Path: opts.pages['/500'] || '',
absoluteAppPath: opts.pages['/_app'],
@ -418,9 +409,7 @@ export function runDependingOnPageType<T>(params: {
if (params.page === MIDDLEWARE_FILE) {
return [params.onEdgeServer()]
} else if (params.page.match(API_ROUTE)) {
return params.pageRuntime === 'edge'
? [params.onEdgeServer()]
: [params.onServer()]
return [params.onServer()]
} else if (params.page === '/_document') {
return [params.onServer()]
} else if (

View file

@ -94,6 +94,7 @@ import {
getUnresolvedModuleFromError,
copyTracedFiles,
isReservedPage,
isCustomErrorPage,
isServerComponentPage,
} from './utils'
import getBaseWebpackConfig from './webpack-config'
@ -1254,7 +1255,10 @@ export default async function build(
isHybridAmp,
ssgPageRoutes,
initialRevalidateSeconds: false,
runtime: pageRuntime,
runtime:
!isReservedPage(page) && !isCustomErrorPage(page)
? pageRuntime
: undefined,
pageDuration: undefined,
ssgPageDurations: undefined,
})

View file

@ -1232,7 +1232,6 @@ export default async function getBaseWebpackConfig(
'next-flight-client-entry-loader',
'noop-loader',
'next-middleware-loader',
'next-edge-function-loader',
'next-middleware-ssr-loader',
'next-middleware-wasm-loader',
'next-app-loader',

View file

@ -7,7 +7,6 @@ import { webpack5 } from 'next/dist/compiled/webpack/webpack'
export function getModuleBuildInfo(webpackModule: webpack5.Module) {
return webpackModule.buildInfo as {
nextEdgeMiddleware?: EdgeMiddlewareMeta
nextEdgeApiFunction?: EdgeMiddlewareMeta
nextEdgeSSR?: EdgeSSRMeta
nextUsedEnvVars?: Set<string>
nextWasmMiddlewareBinding?: WasmBinding

View file

@ -1,43 +0,0 @@
import { getModuleBuildInfo } from './get-module-build-info'
import { stringifyRequest } from '../stringify-request'
export type EdgeFunctionLoaderOptions = {
absolutePagePath: string
page: string
}
export default function middlewareLoader(this: any) {
const { absolutePagePath, page }: EdgeFunctionLoaderOptions =
this.getOptions()
const stringifiedPagePath = stringifyRequest(this, absolutePagePath)
const buildInfo = getModuleBuildInfo(this._module)
buildInfo.nextEdgeApiFunction = {
page: page || '/',
}
return `
import { adapter } from 'next/dist/server/web/adapter'
// The condition is true when the "process" module is provided
if (process !== global.process) {
// prefer local process but global.process has correct "env"
process.env = global.process.env;
global.process = process;
}
var mod = require(${stringifiedPagePath})
var handler = mod.middleware || mod.default;
if (typeof handler !== 'function') {
throw new Error('The Edge Function "pages${page}" must export a \`default\` function');
}
export default function (opts) {
return adapter({
...opts,
page: ${JSON.stringify(page)},
handler,
})
}
`
}

View file

@ -14,26 +14,24 @@ import {
NEXT_CLIENT_SSR_ENTRY_SUFFIX,
} from '../../../shared/lib/constants'
interface EdgeFunctionDefinition {
env: string[]
files: string[]
name: string
page: string
regexp: string
wasm?: WasmBinding[]
}
export interface MiddlewareManifest {
version: 1
sortedMiddleware: string[]
clientInfo: [location: string, isSSR: boolean][]
middleware: { [page: string]: EdgeFunctionDefinition }
functions: { [page: string]: EdgeFunctionDefinition }
middleware: {
[page: string]: {
env: string[]
files: string[]
name: string
page: string
regexp: string
wasm?: WasmBinding[]
}
}
}
interface EntryMetadata {
edgeMiddleware?: EdgeMiddlewareMeta
edgeApiFunction?: EdgeMiddlewareMeta
edgeSSR?: EdgeSSRMeta
env: Set<string>
wasmBindings: Set<WasmBinding>
@ -44,7 +42,6 @@ const middlewareManifest: MiddlewareManifest = {
sortedMiddleware: [],
clientInfo: [],
middleware: {},
functions: {},
version: 1,
}
@ -313,8 +310,6 @@ function getExtractMetadata(params: {
entryMetadata.edgeSSR = buildInfo.nextEdgeSSR
} else if (buildInfo?.nextEdgeMiddleware) {
entryMetadata.edgeMiddleware = buildInfo.nextEdgeMiddleware
} else if (buildInfo?.nextEdgeApiFunction) {
entryMetadata.edgeApiFunction = buildInfo.nextEdgeApiFunction
}
/**
@ -391,19 +386,16 @@ function getCreateAssets(params: {
// There should always be metadata for the entrypoint.
const metadata = metadataByEntry.get(entrypoint.name)
const page =
metadata?.edgeMiddleware?.page ||
metadata?.edgeSSR?.page ||
metadata?.edgeApiFunction?.page
const page = metadata?.edgeMiddleware?.page || metadata?.edgeSSR?.page
if (!page) {
continue
}
const { namedRegex } = getNamedMiddlewareRegex(page, {
catchAll: !metadata.edgeSSR && !metadata.edgeApiFunction,
catchAll: !metadata.edgeSSR,
})
const edgeFunctionDefinition: EdgeFunctionDefinition = {
middlewareManifest.middleware[page] = {
env: Array.from(metadata.env),
files: getEntryFiles(entrypoint.getFiles(), metadata),
name: entrypoint.name,
@ -411,12 +403,6 @@ function getCreateAssets(params: {
regexp: namedRegex,
wasm: Array.from(metadata.wasmBindings),
}
if (metadata.edgeApiFunction /* || metadata.edgeSSR */) {
middlewareManifest.functions[page] = edgeFunctionDefinition
} else {
middlewareManifest.middleware[page] = edgeFunctionDefinition
}
}
middlewareManifest.sortedMiddleware = getSortedRoutes(

View file

@ -19,7 +19,7 @@ function requestToBodyStream(request: IncomingMessage): BodyStream {
return transform.readable as unknown as ReadableStream<Uint8Array>
}
export function bodyStreamToNodeStream(bodyStream: BodyStream): Readable {
function bodyStreamToNodeStream(bodyStream: BodyStream): Readable {
const reader = bodyStream.getReader()
return Readable.from(
(async function* () {

View file

@ -354,9 +354,7 @@ export default class DevServer extends Server {
onClient: () => {},
onServer: () => {},
onEdgeServer: () => {
if (!pageName.startsWith('/api/')) {
routedMiddleware.push(pageName)
}
routedMiddleware.push(pageName)
ssrMiddleware.add(pageName)
},
})

View file

@ -72,9 +72,9 @@ import { getCustomRoute } from './server-route-utils'
import { urlQueryToSearchParams } from '../shared/lib/router/utils/querystring'
import ResponseCache from '../server/response-cache'
import { removeTrailingSlash } from '../shared/lib/router/utils/remove-trailing-slash'
import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info'
import { clonableBodyForRequest } from './body-streams'
import { getMiddlewareRegex } from '../shared/lib/router/utils/route-regex'
import { bodyStreamToNodeStream, clonableBodyForRequest } from './body-streams'
import { getNextPathnameInfo } from '../shared/lib/router/utils/get-next-pathname-info'
export * from './base-server'
@ -540,19 +540,6 @@ export default class NextNodeServer extends BaseServer {
page: string,
builtPagePath: string
): Promise<boolean> {
const handledAsEdgeFunction = await this.runEdgeFunctionApiEndpoint({
req,
res,
query,
params,
page,
builtPagePath,
})
if (handledAsEdgeFunction) {
return true
}
const pageModule = await require(builtPagePath)
query = { ...query, ...params }
@ -1044,15 +1031,11 @@ export default class NextNodeServer extends BaseServer {
}
/**
* Get information for the edge function located in the provided page
* folder. If the edge function info can't be found it will throw
* Get information for the middleware located in the provided page
* folder. If the middleware info can't be found it will throw
* an error.
*/
protected getEdgeFunctionInfo(params: {
page: string
/** Whether we should look for a middleware or not */
middleware: boolean
}) {
protected getMiddlewareInfo(page: string) {
const manifest: MiddlewareManifest = require(join(
this.serverDistDir,
MIDDLEWARE_MANIFEST
@ -1061,14 +1044,12 @@ export default class NextNodeServer extends BaseServer {
let foundPage: string
try {
foundPage = denormalizePagePath(normalizePagePath(params.page))
foundPage = denormalizePagePath(normalizePagePath(page))
} catch (err) {
throw pageNotFoundError(params.page)
throw pageNotFoundError(page)
}
let pageInfo = params.middleware
? manifest.middleware[foundPage]
: manifest.functions[foundPage]
let pageInfo = manifest.middleware[foundPage]
if (!pageInfo) {
throw pageNotFoundError(foundPage)
}
@ -1094,10 +1075,7 @@ export default class NextNodeServer extends BaseServer {
_isSSR?: boolean
): Promise<boolean> {
try {
return (
this.getEdgeFunctionInfo({ page: pathname, middleware: true }).paths
.length > 0
)
return this.getMiddlewareInfo(pathname).paths.length > 0
} catch (_) {}
return false
@ -1164,10 +1142,7 @@ export default class NextNodeServer extends BaseServer {
}
await this.ensureMiddleware(middleware.page, middleware.ssr)
const middlewareInfo = this.getEdgeFunctionInfo({
page: middleware.page,
middleware: true,
})
const middlewareInfo = this.getMiddlewareInfo(middleware.page)
result = await run({
name: middlewareInfo.name,
@ -1436,80 +1411,4 @@ export default class NextNodeServer extends BaseServer {
this.warnIfQueryParametersWereDeleted = () => {}
}
}
private async runEdgeFunctionApiEndpoint(params: {
req: NodeNextRequest
res: NodeNextResponse
query: ParsedUrlQuery
params: Params | false
page: string
builtPagePath: string
}): Promise<boolean> {
let middlewareInfo: ReturnType<typeof this.getEdgeFunctionInfo> | undefined
try {
middlewareInfo = this.getEdgeFunctionInfo({
page: params.page,
middleware: false,
})
} catch {
return false
}
// For middleware to "fetch" we must always provide an absolute URL
const url = getRequestMeta(params.req, '__NEXT_INIT_URL')!
if (!url.startsWith('http')) {
throw new Error(
'To use middleware you must provide a `hostname` and `port` to the Next.js Server'
)
}
const result = await run({
name: middlewareInfo.name,
paths: middlewareInfo.paths,
env: middlewareInfo.env,
wasm: middlewareInfo.wasm,
request: {
headers: params.req.headers,
method: params.req.method,
nextConfig: {
basePath: this.nextConfig.basePath,
i18n: this.nextConfig.i18n,
trailingSlash: this.nextConfig.trailingSlash,
},
url,
page: {
name: params.page,
...(params.params && { params: params.params }),
},
// TODO(gal): complete body
// body: originalBody?.cloneBodyStream(),
},
useCache: !this.nextConfig.experimental.runtime,
onWarning: (_warning: Error) => {
// if (params.onWarning) {
// warning.message += ` "./${middlewareInfo.name}"`
// params.onWarning(warning)
// }
},
})
params.res.statusCode = result.response.status
params.res.statusMessage = result.response.statusText
result.response.headers.forEach((value, key) => {
params.res.appendHeader(key, value)
})
if (result.response.body) {
// TODO(gal): not sure that we always need to stream
bodyStreamToNodeStream(result.response.body).pipe(
params.res.originalResponse
)
} else {
params.res.originalResponse.end()
}
return true
}
}

View file

@ -1,7 +0,0 @@
export default (req) => {
return new Response(`Hello from ${req.url}`)
}
export const config = {
runtime: 'edge',
}

View file

@ -1,3 +0,0 @@
export default (req, res) => {
res.send('Hello, world')
}

View file

@ -12,7 +12,6 @@ import {
renderViaHTTP,
waitFor,
} from 'next-test-utils'
import { readJson } from 'fs-extra'
const appDir = join(__dirname, '../switchable-runtime')
@ -175,31 +174,6 @@ describe('Switchable runtime (prod)', () => {
})
})
it('should build /api/hello as an api route with edge runtime', async () => {
const response = await fetchViaHTTP(context.appPort, '/api/hello')
const text = await response.text()
expect(text).toMatch(/Hello from .+\/api\/hello/)
const manifest = await readJson(
join(context.appDir, '.next/server/middleware-manifest.json')
)
expect(manifest).toMatchObject({
functions: {
'/api/hello': {
env: [],
files: [
'server/edge-runtime-webpack.js',
'server/pages/api/hello.js',
],
name: 'pages/api/hello',
page: '/api/hello',
regexp: '^/api/hello$',
wasm: [],
},
},
})
})
it('should display correct tree view with page types in terminal', async () => {
const stdoutLines = splitLines(context.stdout).filter((line) =>
/^[┌├└/]/.test(line)
@ -207,8 +181,6 @@ describe('Switchable runtime (prod)', () => {
const expectedOutputLines = splitLines(`
/_app
/404
/api/hello
λ /api/node
/edge
/edge-rsc
/node
@ -220,16 +192,12 @@ describe('Switchable runtime (prod)', () => {
λ /node-ssr
/static
`)
const mappedOutputLines = expectedOutputLines.map((_line, index) => {
/** @type {string} */
const str = stdoutLines[index]
const beginningOfPath = str.indexOf('/')
const endOfPath = str.indexOf(' ', beginningOfPath)
return str.slice(0, endOfPath)
const isMatched = expectedOutputLines.every((line, index) => {
const matched = stdoutLines[index].startsWith(line)
return matched
})
expect(mappedOutputLines).toEqual(expectedOutputLines)
expect(isMatched).toBe(true)
})
it('should prefetch data for static pages', async () => {
@ -371,29 +339,4 @@ describe('Switchable runtime (dev)', () => {
'This is a static RSC page.'
)
})
it('should build /api/hello as an api route with edge runtime', async () => {
const response = await fetchViaHTTP(context.appPort, '/api/hello')
const text = await response.text()
expect(text).toMatch(/Hello from .+\/api\/hello/)
const manifest = await readJson(
join(context.appDir, '.next/server/middleware-manifest.json')
)
expect(manifest).toMatchObject({
functions: {
'/api/hello': {
env: [],
files: [
'server/edge-runtime-webpack.js',
'server/pages/api/hello.js',
],
name: 'pages/api/hello',
page: '/api/hello',
regexp: '^/api/hello$',
wasm: [],
},
},
})
})
})