Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor the middleware SSR loader (#31508)
Initial step for #31506, to move the adapter logic out of the loader output string so it will be easier to reuse code in the future. Also, more options are passed to the loader to align with the serverless loader. ## Bug - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Errors have helpful link attached, see `contributing.md` ## Feature - [ ] Implements an existing feature request or RFC. Make sure the feature request has been accepted for implementation before opening a PR. - [ ] Related issues linked using `fixes #number` - [ ] Integration tests added - [ ] Documentation added - [ ] Telemetry added. In case of a feature if it's used or not. - [ ] Errors have helpful link attached, see `contributing.md` ## Documentation / Examples - [ ] Make sure the linting passes by running `yarn lint`
- Loading branch information
Showing
4 changed files
with
185 additions
and
148 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
133 changes: 133 additions & 0 deletions
133
packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
import { NextRequest } from '../../../../server/web/spec-extension/request' | ||
import { renderToHTML } from '../../../../server/web/render' | ||
import RenderResult from '../../../../server/render-result' | ||
|
||
export function getRender({ | ||
App, | ||
Document, | ||
pageMod, | ||
errorMod, | ||
rscManifest, | ||
buildManifest, | ||
reactLoadableManifest, | ||
isServerComponent, | ||
restRenderOpts, | ||
}: { | ||
App: any | ||
Document: any | ||
pageMod: any | ||
errorMod: any | ||
rscManifest: object | ||
buildManifest: any | ||
reactLoadableManifest: any | ||
isServerComponent: boolean | ||
restRenderOpts: any | ||
}) { | ||
return async function render(request: NextRequest) { | ||
const url = request.nextUrl | ||
const { pathname, searchParams } = url | ||
|
||
const query = Object.fromEntries(searchParams) | ||
|
||
// Preflight request | ||
if (request.method === 'HEAD') { | ||
return new Response('OK.', { | ||
headers: { 'x-middleware-ssr': '1' }, | ||
}) | ||
} | ||
|
||
const renderServerComponentData = isServerComponent | ||
? query.__flight__ !== undefined | ||
: false | ||
delete query.__flight__ | ||
|
||
const req = { url: pathname } | ||
const renderOpts = { | ||
...restRenderOpts, | ||
// Locales are not supported yet. | ||
// locales: i18n?.locales, | ||
// locale: detectedLocale, | ||
// defaultLocale, | ||
// domainLocales: i18n?.domains, | ||
dev: process.env.NODE_ENV !== 'production', | ||
App, | ||
Document, | ||
buildManifest, | ||
Component: pageMod.default, | ||
pageConfig: pageMod.config || {}, | ||
getStaticProps: pageMod.getStaticProps, | ||
getServerSideProps: pageMod.getServerSideProps, | ||
getStaticPaths: pageMod.getStaticPaths, | ||
reactLoadableManifest, | ||
env: process.env, | ||
supportsDynamicHTML: true, | ||
concurrentFeatures: true, | ||
renderServerComponentData, | ||
serverComponentManifest: isServerComponent ? rscManifest : null, | ||
ComponentMod: null, | ||
} | ||
|
||
const transformStream = new TransformStream() | ||
const writer = transformStream.writable.getWriter() | ||
const encoder = new TextEncoder() | ||
|
||
let result: RenderResult | null | ||
try { | ||
result = await renderToHTML( | ||
req as any, | ||
{} as any, | ||
pathname, | ||
query, | ||
renderOpts | ||
) | ||
} catch (err: any) { | ||
const errorRes = { statusCode: 500, err } | ||
try { | ||
result = await renderToHTML( | ||
req as any, | ||
errorRes as any, | ||
'/_error', | ||
query, | ||
{ | ||
...renderOpts, | ||
Component: errorMod.default, | ||
getStaticProps: errorMod.getStaticProps, | ||
getServerSideProps: errorMod.getServerSideProps, | ||
getStaticPaths: errorMod.getStaticPaths, | ||
} | ||
) | ||
} catch (err2: any) { | ||
return new Response( | ||
( | ||
err2 || 'An error occurred while rendering ' + pathname + '.' | ||
).toString(), | ||
{ | ||
status: 500, | ||
headers: { 'x-middleware-ssr': '1' }, | ||
} | ||
) | ||
} | ||
} | ||
|
||
if (!result) { | ||
return new Response( | ||
'An error occurred while rendering ' + pathname + '.', | ||
{ | ||
status: 500, | ||
headers: { 'x-middleware-ssr': '1' }, | ||
} | ||
) | ||
} | ||
|
||
result.pipe({ | ||
write: (str: string) => writer.write(encoder.encode(str)), | ||
end: () => writer.close(), | ||
// Not implemented: cork/uncork/on/removeListener | ||
} as any) | ||
|
||
return new Response(transformStream.readable, { | ||
headers: { 'x-middleware-ssr': '1' }, | ||
status: 200, | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters