3bf8b2b4fe
This updates to handle detecting `getStaticProps`/`getServerSideProps` correctly during build when `experimental-edge` is being used. This also fixes not parsing dynamic route params correctly with the edge runtime and sets up the handling needed for the static generation for app opened in the below mentioned PR. ## Bug - [x] Related issues linked using `fixes #number` - [x] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` Fixes: [slack thread](https://vercel.slack.com/archives/C0289CGVAR2/p1661554455121189) x-ref: https://github.com/vercel/next.js/pull/39884
109 lines
3.2 KiB
TypeScript
109 lines
3.2 KiB
TypeScript
import type { NodejsRequestData, FetchEventResult, RequestData } from '../types'
|
|
import { getServerError } from 'next/dist/compiled/@next/react-dev-overlay/dist/middleware'
|
|
import { getModuleContext } from './context'
|
|
import { EdgeFunctionDefinition } from '../../../build/webpack/plugins/middleware-plugin'
|
|
import { requestToBodyStream } from '../../body-streams'
|
|
import type { EdgeRuntime } from 'next/dist/compiled/edge-runtime'
|
|
|
|
export const ErrorSource = Symbol('SandboxError')
|
|
|
|
const FORBIDDEN_HEADERS = [
|
|
'content-length',
|
|
'content-encoding',
|
|
'transfer-encoding',
|
|
]
|
|
|
|
type RunnerFn = (params: {
|
|
name: string
|
|
env: string[]
|
|
onWarning?: (warn: Error) => void
|
|
paths: string[]
|
|
request: NodejsRequestData
|
|
useCache: boolean
|
|
edgeFunctionEntry: Pick<EdgeFunctionDefinition, 'wasm' | 'assets'>
|
|
distDir: string
|
|
}) => Promise<FetchEventResult>
|
|
|
|
/**
|
|
* Decorates the runner function making sure all errors it can produce are
|
|
* tagged with `edge-server` so they can properly be rendered in dev.
|
|
*/
|
|
function withTaggedErrors(fn: RunnerFn): RunnerFn {
|
|
return (params) =>
|
|
fn(params)
|
|
.then((result) => ({
|
|
...result,
|
|
waitUntil: result?.waitUntil?.catch((error) => {
|
|
// TODO: used COMPILER_NAMES.edgeServer instead. Verify that it does not increase the runtime size.
|
|
throw getServerError(error, 'edge-server')
|
|
}),
|
|
}))
|
|
.catch((error) => {
|
|
// TODO: used COMPILER_NAMES.edgeServer instead
|
|
throw getServerError(error, 'edge-server')
|
|
})
|
|
}
|
|
|
|
export const getRuntimeContext = async (params: {
|
|
name: string
|
|
onWarning?: any
|
|
useCache: boolean
|
|
env: string[]
|
|
edgeFunctionEntry: any
|
|
distDir: string
|
|
paths: string[]
|
|
}): Promise<EdgeRuntime<any>> => {
|
|
const { runtime, evaluateInContext } = await getModuleContext({
|
|
moduleName: params.name,
|
|
onWarning: params.onWarning ?? (() => {}),
|
|
useCache: params.useCache !== false,
|
|
env: params.env,
|
|
edgeFunctionEntry: params.edgeFunctionEntry,
|
|
distDir: params.distDir,
|
|
})
|
|
|
|
for (const paramPath of params.paths) {
|
|
evaluateInContext(paramPath)
|
|
}
|
|
return runtime
|
|
}
|
|
|
|
export const run = withTaggedErrors(async (params) => {
|
|
const runtime = await getRuntimeContext(params)
|
|
const subreq = params.request.headers[`x-middleware-subrequest`]
|
|
const subrequests = typeof subreq === 'string' ? subreq.split(':') : []
|
|
if (subrequests.includes(params.name)) {
|
|
return {
|
|
waitUntil: Promise.resolve(),
|
|
response: new runtime.context.Response(null, {
|
|
headers: {
|
|
'x-middleware-next': '1',
|
|
},
|
|
}),
|
|
}
|
|
}
|
|
|
|
const edgeFunction: (args: {
|
|
request: RequestData
|
|
}) => Promise<FetchEventResult> =
|
|
runtime.context._ENTRIES[`middleware_${params.name}`].default
|
|
|
|
const cloned = !['HEAD', 'GET'].includes(params.request.method)
|
|
? params.request.body?.cloneBodyStream()
|
|
: undefined
|
|
|
|
try {
|
|
const result = await edgeFunction({
|
|
request: {
|
|
...params.request,
|
|
body: cloned && requestToBodyStream(runtime.context, cloned),
|
|
},
|
|
})
|
|
for (const headerName of FORBIDDEN_HEADERS) {
|
|
result.response.headers.delete(headerName)
|
|
}
|
|
return result
|
|
} finally {
|
|
await params.request.body?.finalize()
|
|
}
|
|
})
|