diff --git a/packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts b/packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts index 9b8c41fad87662..c827d6f37deffb 100644 --- a/packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts +++ b/packages/next/src/build/webpack/loaders/next-edge-ssr-loader/index.ts @@ -155,7 +155,11 @@ const edgeSSRLoader: webpack.LoaderDefinitionFunction = ? `import * as userland500Page from ${stringified500Path}` : '' } - const renderToHTML = undefined + + // TODO: re-enable this once we've refactored to use implicit matches + // const renderToHTML = undefined + + import { renderToHTML } from 'next/dist/esm/server/render' import RouteModule from "next/dist/esm/server/future/route-modules/pages/module" const pageMod = { diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index 60ac1e02ff27ee..88edb825c46f6e 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -28,7 +28,7 @@ import { } from '../shared/lib/router/utils/route-matcher' import type { MiddlewareRouteMatch } from '../shared/lib/router/utils/middleware-route-matcher' import type { RouteMatch } from './future/route-matches/route-match' -import type { RenderOpts } from './render' +import { renderToHTML, type RenderOpts } from './render' import fs from 'fs' import { join, relative, resolve, sep, isAbsolute } from 'path' @@ -985,7 +985,16 @@ export default class NextNodeServer extends BaseServer { ) } - throw new Error('Invariant: render should have used routeModule') + // TODO: re-enable this once we've refactored to use implicit matches + // throw new Error('Invariant: render should have used routeModule') + + return renderToHTML( + req.originalRequest, + res.originalResponse, + pathname, + query, + renderOpts + ) } private streamResponseChunk(res: ServerResponse, chunk: any) { diff --git a/test/e2e/custom-app-render/components/page-identifier.jsx b/test/e2e/custom-app-render/components/page-identifier.jsx new file mode 100644 index 00000000000000..ce4f6703995c6d --- /dev/null +++ b/test/e2e/custom-app-render/components/page-identifier.jsx @@ -0,0 +1,9 @@ +import React from 'react' + +export function PageIdentifier({ page }) { + return ( +
+ Page: {page} +
+ ) +} diff --git a/test/e2e/custom-app-render/custom-app-render.test.ts b/test/e2e/custom-app-render/custom-app-render.test.ts new file mode 100644 index 00000000000000..e80d9b77b2f960 --- /dev/null +++ b/test/e2e/custom-app-render/custom-app-render.test.ts @@ -0,0 +1,16 @@ +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'custom-app-render', + { + files: __dirname, + skipDeployment: true, + startCommand: 'node server.js', + }, + ({ next }) => { + it.each(['/', '/render'])('should render %s', async (page) => { + const $ = await next.render$(page) + expect($('#page').data('page')).toBe(page) + }) + } +) diff --git a/test/e2e/custom-app-render/pages/_app.jsx b/test/e2e/custom-app-render/pages/_app.jsx new file mode 100644 index 00000000000000..f90f718a062310 --- /dev/null +++ b/test/e2e/custom-app-render/pages/_app.jsx @@ -0,0 +1,7 @@ +export default function App({ Component, pageProps }) { + return +} + +App.getInitialProps = async () => { + return {} +} diff --git a/test/e2e/custom-app-render/pages/index.jsx b/test/e2e/custom-app-render/pages/index.jsx new file mode 100644 index 00000000000000..383252dd6187c7 --- /dev/null +++ b/test/e2e/custom-app-render/pages/index.jsx @@ -0,0 +1,7 @@ +import React from 'react' + +import { PageIdentifier } from '../components/page-identifier' + +export default function IndexPage() { + return +} diff --git a/test/e2e/custom-app-render/pages/render.jsx b/test/e2e/custom-app-render/pages/render.jsx new file mode 100644 index 00000000000000..109bcd997c54e3 --- /dev/null +++ b/test/e2e/custom-app-render/pages/render.jsx @@ -0,0 +1,7 @@ +import React from 'react' + +import { PageIdentifier } from '../components/page-identifier' + +export default function RenderNodePage() { + return +} diff --git a/test/e2e/custom-app-render/server.js b/test/e2e/custom-app-render/server.js new file mode 100644 index 00000000000000..15634441d6be34 --- /dev/null +++ b/test/e2e/custom-app-render/server.js @@ -0,0 +1,49 @@ +const http = require('http') +const { parse } = require('url') +const next = require('next') + +async function main() { + const dev = process.env.NEXT_TEST_MODE === 'dev' + process.env.NODE_ENV = dev ? 'development' : 'production' + + const port = parseInt(process.env.PORT, 10) || 3000 + + const app = next({ dev, port }) + const handle = app.getRequestHandler() + + await app.prepare() + + const server = http.createServer(async (req, res) => { + try { + const parsedUrl = parse(req.url, true) + const { pathname, query } = parsedUrl + + if (pathname.startsWith('/render')) { + await app.render(req, res, pathname, query) + } else { + await handle(req, res, parsedUrl) + } + } catch (err) { + res.statusCode = 500 + res.end('Internal Server Error') + } + }) + + server.once('error', (err) => { + console.error(err) + process.exit(1) + }) + + server.listen(port, () => { + console.log( + `> started server on url: http://localhost:${port} as ${ + dev ? 'development' : process.env.NODE_ENV + }` + ) + }) +} + +main().catch((err) => { + console.error(err) + process.exit(1) +})