From b701de60cd696c7a50666ab8b6ed6470d61574da Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Sat, 19 Feb 2022 22:13:48 +0100 Subject: [PATCH 1/3] Improve type imports in server/render and optimize the Edge SSR loader (#34552) * reorganize imports * code refactoring * remove unused variables * fix test Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../next-middleware-ssr-loader/render.ts | 38 ++----------- packages/next/server/dev/hot-reloader.ts | 4 +- packages/next/server/render.tsx | 56 +++++++++++-------- .../test/index.test.js | 5 -- 4 files changed, 41 insertions(+), 62 deletions(-) diff --git a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts index beefd6dcb861..8fa95529ea3a 100644 --- a/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts +++ b/packages/next/build/webpack/loaders/next-middleware-ssr-loader/render.ts @@ -4,7 +4,6 @@ import type { BuildManifest } from '../../../../server/get-page-files' import type { ReactLoadableManifest } from '../../../../server/load-components' import { NextRequest } from '../../../../server/web/spec-extension/request' -import { toNodeHeaders } from '../../../../server/web/utils' import WebServer from '../../../../server/web-server' import { @@ -12,20 +11,6 @@ import { WebNextResponse, } from '../../../../server/base-http/web' -const createHeaders = (args?: any) => ({ - ...args, - 'x-middleware-ssr': '1', - 'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate', -}) - -function sendError(req: any, error: Error) { - const defaultMessage = 'An error occurred while rendering ' + req.url + '.' - return new Response((error && error.message) || defaultMessage, { - status: 500, - headers: createHeaders(), - }) -} - // Polyfilled for `path-browserify` inside the Web Server. process.cwd = () => '' @@ -123,31 +108,20 @@ export function getRender({ const requestHandler = server.getRequestHandler() return async function render(request: NextRequest) { - const { nextUrl: url, cookies, headers } = request - const { pathname, searchParams } = url - + const { nextUrl: url } = request + const { searchParams } = url const query = Object.fromEntries(searchParams) - const req = { - url: pathname, - cookies, - headers: toNodeHeaders(headers), - } // Preflight request if (request.method === 'HEAD') { + // Hint the client that the matched route is a SSR page. return new Response(null, { - headers: createHeaders(), + headers: { + 'x-middleware-ssr': '1', + }, }) } - // @TODO: We should move this into server/render. - if (Document.getInitialProps) { - const err = new Error( - '`getInitialProps` in Document component is not supported with the Edge Runtime.' - ) - return sendError(req, err) - } - const renderServerComponentData = isServerComponent ? query.__flight__ !== undefined : false diff --git a/packages/next/server/dev/hot-reloader.ts b/packages/next/server/dev/hot-reloader.ts index 92847d189629..0c6454f8072b 100644 --- a/packages/next/server/dev/hot-reloader.ts +++ b/packages/next/server/dev/hot-reloader.ts @@ -336,6 +336,8 @@ export default class HotReloader { ) ) + const hasEdgeRuntimePages = this.runtime === 'edge' + return webpackConfigSpan .traceChild('generate-webpack-config') .traceAsyncFn(() => @@ -363,7 +365,7 @@ export default class HotReloader { }), // For the edge runtime, we need an extra compiler to generate the // web-targeted server bundle for now. - this.runtime === 'edge' + hasEdgeRuntimePages ? getBaseWebpackConfig(this.dir, { dev: true, isServer: true, diff --git a/packages/next/server/render.tsx b/packages/next/server/render.tsx index c5be24e7da9c..e4f121fdcd61 100644 --- a/packages/next/server/render.tsx +++ b/packages/next/server/render.tsx @@ -1,10 +1,29 @@ -import { IncomingMessage, ServerResponse } from 'http' -import { ParsedUrlQuery, stringify as stringifyQuery } from 'querystring' +import type { IncomingMessage, ServerResponse } from 'http' +import type { NextRouter } from '../shared/lib/router/router' +import type { HtmlProps } from '../shared/lib/html-context' +import type { DomainLocale } from './config' +import type { + AppType, + DocumentInitialProps, + DocumentProps, + DocumentContext, + NextComponentType, + RenderPage, + RenderPageResult, +} from '../shared/lib/utils' +import type { ImageConfigComplete } from './image-config' +import type { Redirect } from '../lib/load-custom-routes' +import type { NextApiRequestCookies, __ApiPreviewProps } from './api-utils' +import type { FontManifest } from './font-utils' +import type { LoadComponentsReturnType, ManifestItem } from './load-components' +import type { GetServerSideProps, GetStaticProps, PreviewData } from '../types' +import type { UnwrapPromise } from '../lib/coalesced-function' + import React from 'react' +import { ParsedUrlQuery, stringify as stringifyQuery } from 'querystring' import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-webpack' import { renderToReadableStream } from 'next/dist/compiled/react-server-dom-webpack/writer.browser.server' import { StyleRegistry, createStyleRegistry } from 'styled-jsx' -import { UnwrapPromise } from '../lib/coalesced-function' import { GSP_NO_RETURNED_VALUE, GSSP_COMPONENT_MEMBER_ERROR, @@ -15,56 +34,38 @@ import { SSG_GET_INITIAL_PROPS_CONFLICT, UNSTABLE_REVALIDATE_RENAME_ERROR, } from '../lib/constants' -import { isSerializableProps } from '../lib/is-serializable-props' -import { GetServerSideProps, GetStaticProps, PreviewData } from '../types' -import { isInAmpMode } from '../shared/lib/amp' -import { AmpStateContext } from '../shared/lib/amp-context' import { SERVER_PROPS_ID, STATIC_PROPS_ID, STATIC_STATUS_PAGES, } from '../shared/lib/constants' +import { isSerializableProps } from '../lib/is-serializable-props' +import { isInAmpMode } from '../shared/lib/amp' +import { AmpStateContext } from '../shared/lib/amp-context' import { defaultHead } from '../shared/lib/head' import { HeadManagerContext } from '../shared/lib/head-manager-context' import Loadable from '../shared/lib/loadable' import { LoadableContext } from '../shared/lib/loadable-context' import { RouterContext } from '../shared/lib/router-context' -import { NextRouter } from '../shared/lib/router/router' import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic' import { - AppType, ComponentsEnhancer, - DocumentInitialProps, - DocumentProps, - DocumentContext, getDisplayName, isResSent, loadGetInitialProps, - NextComponentType, - RenderPage, - RenderPageResult, } from '../shared/lib/utils' - import { HtmlContext } from '../shared/lib/html-context' -import type { HtmlProps } from '../shared/lib/html-context' - -import type { NextApiRequestCookies, __ApiPreviewProps } from './api-utils' import { denormalizePagePath } from './denormalize-page-path' -import type { FontManifest } from './font-utils' -import type { LoadComponentsReturnType, ManifestItem } from './load-components' import { normalizePagePath } from './normalize-page-path' import { getRequestMeta, NextParsedUrlQuery } from './request-meta' import { allowedStatusCodes, getRedirectStatus, - Redirect, } from '../lib/load-custom-routes' -import { DomainLocale } from './config' import RenderResult from './render-result' import isError from '../lib/is-error' import { readableStreamTee } from './web/utils' import { ImageConfigContext } from '../shared/lib/image-config-context' -import { ImageConfigComplete } from './image-config' import { FlushEffectsContext } from '../shared/lib/flush-effects' let optimizeAmp: typeof import('./optimize-amp').default @@ -1248,6 +1249,13 @@ export async function renderToHTML( */ const generateStaticHTML = supportsDynamicHTML !== true const renderDocument = async () => { + if (runtime === 'edge' && Document.getInitialProps) { + // In the Edge runtime, Document.getInitialProps isn't supported. + throw new Error( + '`getInitialProps` in Document component is not supported with the Edge Runtime.' + ) + } + if (!runtime && Document.getInitialProps) { const renderPage: RenderPage = ( options: ComponentsEnhancer = {} diff --git a/test/integration/react-streaming-and-server-components/test/index.test.js b/test/integration/react-streaming-and-server-components/test/index.test.js index 8f8e7e0fb805..826ca4d5d142 100644 --- a/test/integration/react-streaming-and-server-components/test/index.test.js +++ b/test/integration/react-streaming-and-server-components/test/index.test.js @@ -247,12 +247,7 @@ const documentSuite = { runTests: (context) => { it('should error when custom _document has getInitialProps method', async () => { const res = await fetchViaHTTP(context.appPort, '/') - const html = await res.text() - expect(res.status).toBe(500) - expect(html).toContain( - '`getInitialProps` in Document component is not supported with the Edge Runtime.' - ) }) }, beforeAll: () => documentPage.write(documentWithGip), From 94ad03385b3ff55fa8e9c6434bde1d2bcb90ef73 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Sat, 19 Feb 2022 23:26:54 +0100 Subject: [PATCH 2/3] remove commons chunk config (#34445) This removes the config for the `commons` chunk. I think the idea was that modules are that in all pages are put into a `commons` chunk, but that breaks when next/dynamic comes into play, which also creates chunks. So the `totalPages` condition is broken and could lead to too many modules placed into the commons chunk. Example: 2 pages, each has one next/dynamic. Both on demand chunks include module A. page 1 includes module B and next/dynamic on page 2 includes module B. A and B are placed into commons. commonjs chunk is loaded in page 1 and both next/dynamic. Page 1 would load module A even while it doesn't need it. ## 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` --- packages/next/build/webpack-config.ts | 5 ----- test/.stats-app/stats-config.js | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/next/build/webpack-config.ts b/packages/next/build/webpack-config.ts index d54d3c9f8c2b..f030cf3139e4 100644 --- a/packages/next/build/webpack-config.ts +++ b/packages/next/build/webpack-config.ts @@ -791,11 +791,6 @@ export default async function getBaseWebpackConfig( minChunks: 1, reuseExistingChunk: true, }, - commons: { - name: 'commons', - minChunks: totalPages, - priority: 20, - }, middleware: { chunks: (chunk: webpack.compilation.Chunk) => chunk.name?.match(MIDDLEWARE_ROUTE), diff --git a/test/.stats-app/stats-config.js b/test/.stats-app/stats-config.js index 82741d746daa..7996360ebeb5 100644 --- a/test/.stats-app/stats-config.js +++ b/test/.stats-app/stats-config.js @@ -9,7 +9,7 @@ const imagePageData = fs.readFileSync( const clientGlobs = [ { - name: 'Client Bundles (main, webpack, commons)', + name: 'Client Bundles (main, webpack)', globs: [ '.next/static/runtime/+(main|webpack)-*', '.next/static/chunks/!(polyfills*)', From bf8b835e2e1fd4b8364d7411d630d139478e8ea5 Mon Sep 17 00:00:00 2001 From: Amirhossein Beigi Date: Sat, 19 Feb 2022 14:33:32 -0800 Subject: [PATCH 3/3] fix: change showcase url (#34590) ## 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` --- docs/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/faq.md b/docs/faq.md index cd97832dfbcf..fe9ca6838034 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -7,7 +7,7 @@ description: Get to know more about Next.js with the frequently asked questions.
Is Next.js production ready?

Yes! Next.js is used by many of the top websites in the world. See the - Showcase for more info.

+ Showcase for more info.