From 14987d96674275c7b1004a4ceb33947499d7247c Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Fri, 12 Apr 2024 19:58:13 +0200 Subject: [PATCH 001/258] use pathToFileUrl to make esm import()s work with absolute windows paths (#64386) ### What? Fixes #64371 Fixes #63359 Closes PACK-2946 --------- Co-authored-by: Tim Neutkens Co-authored-by: Jiachi Liu --- azure-pipelines.yml | 3 ++- packages/next/src/build/swc/index.ts | 2 +- packages/next/src/lib/find-config.test.ts | 1 + packages/next/src/lib/find-config.ts | 21 +++++++++++++++++++-- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a4a63e68955c00..14c69e0bbc3ab7 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -69,8 +69,9 @@ stages: - script: npx playwright@1.35.1 install chromium condition: eq(variables['isDocsOnly'], 'No') + # Test critical app router and CNA tests to cover basic usage cases with windows - script: | - node run-tests.js -c 1 test/production/pages-dir/production/test/index.test.ts test/integration/css-client-nav/test/index.test.js test/integration/rewrites-has-condition/test/index.test.js + node run-tests.js -c 1 test/production/pages-dir/production/test/index.test.ts test/integration/css-client-nav/test/index.test.js test/integration/rewrites-has-condition/test/index.test.js test/integration/create-next-app/examples.test.ts test/integration/create-next-app/index.test.ts test/integration/create-next-app/package-manager/pnpm.test.ts condition: eq(variables['isDocsOnly'], 'No') displayName: 'Run tests' diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index 5219c4797b9a32..86aef60666c6c3 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -1220,7 +1220,7 @@ async function loadWasm(importPath = '') { // the import path must be exact when not in node_modules pkgPath = path.join(importPath, pkg, 'wasm.js') } - let bindings = await import(pkgPath) + let bindings = await import(pathToFileURL(pkgPath).toString()) if (pkg === '@next/swc-wasm-web') { bindings = await bindings.default() } diff --git a/packages/next/src/lib/find-config.test.ts b/packages/next/src/lib/find-config.test.ts index dd00d432162660..ed1cee47c6d78f 100644 --- a/packages/next/src/lib/find-config.test.ts +++ b/packages/next/src/lib/find-config.test.ts @@ -3,6 +3,7 @@ import { join } from 'node:path' import { tmpdir } from 'node:os' import { findConfig } from './find-config' +// Jest does not support `import('file://something')` (file: imports) yet. describe('findConfig()', () => { const exampleConfig = { basePath: '/docs', diff --git a/packages/next/src/lib/find-config.ts b/packages/next/src/lib/find-config.ts index 58b2f6abc3e7a0..4bcce7b6ee771d 100644 --- a/packages/next/src/lib/find-config.ts +++ b/packages/next/src/lib/find-config.ts @@ -1,6 +1,7 @@ import findUp from 'next/dist/compiled/find-up' import { readFile } from 'fs/promises' import JSON5 from 'next/dist/compiled/json5' +import { pathToFileURL } from 'url' type RecursivePartial = { [P in keyof T]?: RecursivePartial @@ -64,11 +65,27 @@ export async function findConfig( const filePath = await findConfigPath(directory, key) + const esmImport = (path: string) => { + // Skip mapping to absolute url with pathToFileURL on windows if it's jest + // https://github.com/nodejs/node/issues/31710#issuecomment-587345749 + if (process.platform === 'win32' && !process.env.JEST_WORKER_ID) { + // on windows import("C:\\path\\to\\file") is not valid, so we need to + // use file:// URLs + return import(pathToFileURL(path).toString()) + } else { + return import(path) + } + } + if (filePath) { if (filePath.endsWith('.js')) { - return isESM ? (await import(filePath)).default : require(filePath) + if (isESM) { + return (await esmImport(filePath)).default + } else { + return require(filePath) + } } else if (filePath.endsWith('.mjs')) { - return (await import(filePath)).default + return (await esmImport(filePath)).default } else if (filePath.endsWith('.cjs')) { return require(filePath) } From 597aa448054da4206807a5bfd4603285e8399cd1 Mon Sep 17 00:00:00 2001 From: Zack Tanner <1939140+ztanner@users.noreply.github.com> Date: Fri, 12 Apr 2024 11:57:35 -0700 Subject: [PATCH 002/258] update publish configs --- .github/workflows/build_and_deploy.yml | 2 +- .github/workflows/build_and_test.yml | 2 +- lerna.json | 2 +- scripts/publish-native.js | 4 +++- scripts/publish-release.js | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index 82ac9931614af7..e585a05bac19cb 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -2,7 +2,7 @@ name: build-and-deploy on: push: - branches: ['canary'] + branches: ['canary', '14-2-1'] workflow_dispatch: env: diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 1606168096e70e..3b025d292054ad 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -2,7 +2,7 @@ name: build-and-test on: push: - branches: ['canary'] + branches: ['canary', '14-2-1'] pull_request: types: [opened, synchronize] diff --git a/lerna.json b/lerna.json index e3dfaeb7b02d4a..caca7005857287 100644 --- a/lerna.json +++ b/lerna.json @@ -11,7 +11,7 @@ "publish": { "npmClient": "npm", "allowBranch": [ - "canary" + "14-2-1" ], "registry": "https://registry.npmjs.org/" } diff --git a/scripts/publish-native.js b/scripts/publish-native.js index 6d91e36941e662..8562c443e438a6 100755 --- a/scripts/publish-native.js +++ b/scripts/publish-native.js @@ -49,7 +49,9 @@ const cwd = process.cwd() `${path.join(nativePackagesDir, platform)}`, `--access`, `public`, - ...(version.includes('canary') ? ['--tag', 'canary'] : []), + ...(version.includes('canary') + ? ['--tag', 'canary'] + : ['--tag', '14-2-1']), ], { stdio: 'inherit' } ) diff --git a/scripts/publish-release.js b/scripts/publish-release.js index 943174990303f1..72d40b01e6cc02 100755 --- a/scripts/publish-release.js +++ b/scripts/publish-release.js @@ -53,7 +53,7 @@ const cwd = process.cwd() '--access', 'public', '--ignore-scripts', - ...(isCanary ? ['--tag', 'canary'] : []), + ...(isCanary ? ['--tag', 'canary'] : ['--tag', '14-2-1']), ], { stdio: 'pipe' } ) From 9d7ce74503d155e8cc29248d9bf99d5ac06907e3 Mon Sep 17 00:00:00 2001 From: Zack Tanner <1939140+ztanner@users.noreply.github.com> Date: Fri, 12 Apr 2024 12:44:49 -0700 Subject: [PATCH 003/258] modify scripts --- scripts/publish-native.js | 4 +--- scripts/publish-release.js | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/scripts/publish-native.js b/scripts/publish-native.js index 8562c443e438a6..6d91e36941e662 100755 --- a/scripts/publish-native.js +++ b/scripts/publish-native.js @@ -49,9 +49,7 @@ const cwd = process.cwd() `${path.join(nativePackagesDir, platform)}`, `--access`, `public`, - ...(version.includes('canary') - ? ['--tag', 'canary'] - : ['--tag', '14-2-1']), + ...(version.includes('canary') ? ['--tag', 'canary'] : []), ], { stdio: 'inherit' } ) diff --git a/scripts/publish-release.js b/scripts/publish-release.js index 72d40b01e6cc02..943174990303f1 100755 --- a/scripts/publish-release.js +++ b/scripts/publish-release.js @@ -53,7 +53,7 @@ const cwd = process.cwd() '--access', 'public', '--ignore-scripts', - ...(isCanary ? ['--tag', 'canary'] : ['--tag', '14-2-1']), + ...(isCanary ? ['--tag', 'canary'] : []), ], { stdio: 'pipe' } ) From c0ae6f6ffdad865de660e897ecbeafda2bca78da Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Fri, 12 Apr 2024 20:30:08 +0000 Subject: [PATCH 004/258] v14.2.1 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 12 ++++++------ packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 14 +++++++------- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/lerna.json b/lerna.json index caca7005857287..b78aad55350932 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.2.0" + "version": "14.2.1" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 83b48948716fcc..7584dd9dd1a11a 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.2.0", + "version": "14.2.1", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index ae2f0d550016cb..893d2a2d31ebd1 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.2.0", + "version": "14.2.1", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.2.0", + "@next/eslint-plugin-next": "14.2.1", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0", "eslint-import-resolver-node": "^0.3.6", diff --git a/packages/eslint-plugin-next/package.json b/packages/eslint-plugin-next/package.json index 2c11193be9e41d..16fffdbabf336b 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.2.0", + "version": "14.2.1", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 4f8d9bb14d616f..de653efc813c43 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.2.0", + "version": "14.2.1", "repository": { "url": "vercel/next.js", "directory": "packages/font" diff --git a/packages/next-bundle-analyzer/package.json b/packages/next-bundle-analyzer/package.json index 4e14d05bf7a220..cd0b550d375477 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.2.0", + "version": "14.2.1", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index f663e425eeda32..96cf21fc7dbfa0 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.2.0", + "version": "14.2.1", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index f5794507391807..c600c0ecebdb78 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.2.0", + "version": "14.2.1", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 0d6ceb3c018dae..5fc307944c3642 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.2.0", + "version": "14.2.1", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 7241ca8f97e128..83c26f5b9597d6 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.2.0", + "version": "14.2.1", "repository": { "url": "vercel/next.js", "directory": "packages/next-plugin-storybook" diff --git a/packages/next-polyfill-module/package.json b/packages/next-polyfill-module/package.json index d8ae1aeb1372d7..fd534c4d2d3f80 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.2.0", + "version": "14.2.1", "description": "A standard library polyfill for ES Modules supporting browsers (Edge 16+, Firefox 60+, Chrome 61+, Safari 10.1+)", "main": "dist/polyfill-module.js", "license": "MIT", diff --git a/packages/next-polyfill-nomodule/package.json b/packages/next-polyfill-nomodule/package.json index 89bc33d386b679..fe6f51e1276036 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.2.0", + "version": "14.2.1", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 3cf26ba6bd0778..04861594297430 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.2.0", + "version": "14.2.1", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 2a585349c902f0..6bbda3dde4ab8e 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.2.0", + "version": "14.2.1", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.2.0", + "@next/env": "14.2.1", "@swc/helpers": "0.5.5", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001579", @@ -149,10 +149,10 @@ "@jest/types": "29.5.0", "@mswjs/interceptors": "0.23.0", "@napi-rs/triples": "1.2.0", - "@next/polyfill-module": "14.2.0", - "@next/polyfill-nomodule": "14.2.0", - "@next/react-refresh-utils": "14.2.0", - "@next/swc": "14.2.0", + "@next/polyfill-module": "14.2.1", + "@next/polyfill-nomodule": "14.2.1", + "@next/react-refresh-utils": "14.2.1", + "@next/swc": "14.2.1", "@opentelemetry/api": "1.6.0", "@playwright/test": "1.41.2", "@taskr/clear": "1.1.0", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index cbe426720a0105..f6225a733384af 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.2.0", + "version": "14.2.1", "description": "An experimental package providing utilities for React Refresh.", "repository": { "url": "vercel/next.js", diff --git a/packages/third-parties/package.json b/packages/third-parties/package.json index ece21bb3675d5b..8b60ac935535cd 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.2.0", + "version": "14.2.1", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -26,7 +26,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.2.0", + "next": "14.2.1", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cbd1f73aa76c24..284e746a4eab4a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -744,7 +744,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.2.0 + specifier: 14.2.1 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.2.0 + specifier: 14.2.1 version: link:../next-env '@swc/helpers': specifier: 0.5.5 @@ -927,16 +927,16 @@ importers: specifier: 1.2.0 version: 1.2.0 '@next/polyfill-module': - specifier: 14.2.0 + specifier: 14.2.1 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.2.0 + specifier: 14.2.1 version: link:../next-polyfill-nomodule '@next/react-refresh-utils': - specifier: 14.2.0 + specifier: 14.2.1 version: link:../react-refresh-utils '@next/swc': - specifier: 14.2.0 + specifier: 14.2.1 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1551,7 +1551,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.2.0 + specifier: 14.2.1 version: link:../next outdent: specifier: 0.8.0 From cb13dc8aae665a5fd0b603a6451b9cf4d045ba21 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Fri, 12 Apr 2024 01:21:28 +0200 Subject: [PATCH 005/258] Fix Server Action error logs for unhandled POST requests (#64315) ## Why Currently, Server Action handlers are just normal routes and they accepting POST requests. The only way to differentiate a normal request (page access, API route, etc.) from a Server Action request is to check that if it's a POST and has a Server Action ID set via headers or body (e.g. `multipart/form-data`). Usually, for existing page and API routes the correct handlers (page renderer, API route handler) will take precedence over Server Action's. But if the route doesn't exist (e.g. 404) it will still go through Server Action's handler and result in an error. And we're eagerly logging out that error because it might be an application failure, like passing a wrong Action ID. ## How In this PR we are making sure that the error is only logged if the Action ID isn't `null`. This means that it's an intentional Server Action request with a wrong ID. If the ID is `null`, we just handle it like 404 and log nothing. Fixes #64214. Closes NEXT-3071 --- .../src/server/app-render/action-handler.ts | 28 ++++++++++++------- .../server/lib/server-action-request-meta.ts | 18 ++++++++---- test/e2e/app-dir/actions/app-action.test.ts | 26 +++++++++++++++++ .../actions/app/non-action-form/page.js | 7 +++++ 4 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 test/e2e/app-dir/actions/app/non-action-form/page.js diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 1c16b73bf14620..55c0234ec89333 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -36,10 +36,7 @@ import { NEXT_CACHE_REVALIDATED_TAGS_HEADER, NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER, } from '../../lib/constants' -import { - getIsServerAction, - getServerActionRequestMetadata, -} from '../lib/server-action-request-meta' +import { getServerActionRequestMetadata } from '../lib/server-action-request-meta' import { isCsrfOriginAllowed } from './csrf-protection' import { warn } from '../../build/output/log' import { RequestCookies, ResponseCookies } from '../web/spec-extension/cookies' @@ -399,11 +396,16 @@ export async function handleAction({ const contentType = req.headers['content-type'] const { serverActionsManifest, page } = ctx.renderOpts - const { actionId, isURLEncodedAction, isMultipartAction, isFetchAction } = - getServerActionRequestMetadata(req) + const { + actionId, + isURLEncodedAction, + isMultipartAction, + isFetchAction, + isServerAction, + } = getServerActionRequestMetadata(req) // If it's not a Server Action, skip handling. - if (!getIsServerAction(req)) { + if (!isServerAction) { return } @@ -578,7 +580,9 @@ export async function handleAction({ try { actionModId = getActionModIdOrError(actionId, serverModuleMap) } catch (err) { - console.error(err) + if (actionId !== null) { + console.error(err) + } return { type: 'not-found', } @@ -667,7 +671,9 @@ export async function handleAction({ try { actionModId = getActionModIdOrError(actionId, serverModuleMap) } catch (err) { - console.error(err) + if (actionId !== null) { + console.error(err) + } return { type: 'not-found', } @@ -718,7 +724,9 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc actionModId = actionModId ?? getActionModIdOrError(actionId, serverModuleMap) } catch (err) { - console.error(err) + if (actionId !== null) { + console.error(err) + } return { type: 'not-found', } diff --git a/packages/next/src/server/lib/server-action-request-meta.ts b/packages/next/src/server/lib/server-action-request-meta.ts index 45e5ff7a7dd8b8..50d8e6eeca9e39 100644 --- a/packages/next/src/server/lib/server-action-request-meta.ts +++ b/packages/next/src/server/lib/server-action-request-meta.ts @@ -10,6 +10,7 @@ export function getServerActionRequestMetadata( isURLEncodedAction: boolean isMultipartAction: boolean isFetchAction: boolean + isServerAction: boolean } { let actionId: string | null let contentType: string | null @@ -34,14 +35,21 @@ export function getServerActionRequestMetadata( req.method === 'POST' ) - return { actionId, isURLEncodedAction, isMultipartAction, isFetchAction } + const isServerAction = Boolean( + isFetchAction || isURLEncodedAction || isMultipartAction + ) + + return { + actionId, + isURLEncodedAction, + isMultipartAction, + isFetchAction, + isServerAction, + } } export function getIsServerAction( req: IncomingMessage | BaseNextRequest | NextRequest ): boolean { - const { isFetchAction, isURLEncodedAction, isMultipartAction } = - getServerActionRequestMetadata(req) - - return Boolean(isFetchAction || isURLEncodedAction || isMultipartAction) + return getServerActionRequestMetadata(req).isServerAction } diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 2c1b0bec893ca1..b1b147b93c0d08 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -139,6 +139,32 @@ createNextDescribe( ).toBeGreaterThanOrEqual(currentTimestamp) }) + it('should not log errors for non-action form POSTs', async () => { + const logs: string[] = [] + next.on('stdout', (log) => { + logs.push(log) + }) + next.on('stderr', (log) => { + logs.push(log) + }) + + const browser = await next.browser('/non-action-form') + await browser.elementByCss('button').click() + + await check(() => browser.url(), next.url + '/', true, 2) + + // we don't have access to runtime logs on deploy + if (!isNextDeploy) { + await check(() => { + return logs.some((log) => + log.includes('Failed to find Server Action "null"') + ) + ? 'error' + : '' + }, '') + } + }) + it('should support setting cookies in route handlers with the correct overrides', async () => { const res = await next.fetch('/handler') const setCookieHeader = res.headers.get('set-cookie') diff --git a/test/e2e/app-dir/actions/app/non-action-form/page.js b/test/e2e/app-dir/actions/app/non-action-form/page.js new file mode 100644 index 00000000000000..d1f4aec571f166 --- /dev/null +++ b/test/e2e/app-dir/actions/app/non-action-form/page.js @@ -0,0 +1,7 @@ +export default function Page() { + return ( +
+ +
+ ) +} From c262f3886be03c6c3d0097661cce394dd044900e Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Sat, 13 Apr 2024 00:03:11 +0200 Subject: [PATCH 006/258] Improve rendering performance (#64408) This PR improves the server rendering performance a bit, especially for the App Router. It has mainly 2 changes. A rough benchmark test with a 300kB Lorem Ipsum page, SSR is about 18% faster. ### Improve `getServerInsertedHTML` - Avoid an extra `renderToReadableStream` if we already know the content will be empty - Avoid `await stream.allReady` for better parallelism with `streamToString()` - Increase the `progressiveChunkSize` ### Improve `createHeadInsertionTransformStream` - Only do chunk splitting and enqueuing if the inserted string is not empty --- packages/next/src/build/index.ts | 9 +++--- .../make-get-server-inserted-html.tsx | 27 +++++++++++++--- .../stream-utils/node-web-streams-helper.ts | 32 ++++++++++++------- 3 files changed, 47 insertions(+), 21 deletions(-) diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 144e8c8d4f976d..6d3ba360073500 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -2981,12 +2981,13 @@ export default async function build( if (i18n) { if (additionalSsgFile) return + const localeExt = page === '/' ? path.extname(file) : '' + const relativeDestNoPages = relativeDest.slice( + 'pages/'.length + ) + for (const locale of i18n.locales) { const curPath = `/${locale}${page === '/' ? '' : page}` - const localeExt = page === '/' ? path.extname(file) : '' - const relativeDestNoPages = relativeDest.slice( - 'pages/'.length - ) if (isSsg && ssgNotFoundPaths.includes(curPath)) { continue diff --git a/packages/next/src/server/app-render/make-get-server-inserted-html.tsx b/packages/next/src/server/app-render/make-get-server-inserted-html.tsx index ab9a22e85f7417..976733f19644fc 100644 --- a/packages/next/src/server/app-render/make-get-server-inserted-html.tsx +++ b/packages/next/src/server/app-render/make-get-server-inserted-html.tsx @@ -60,6 +60,18 @@ export function makeGetServerInsertedHTML({ } } + const serverInsertedHTML = renderServerInsertedHTML() + + // Skip React rendering if we know the content is empty. + if ( + !hasUnflushedPolyfills && + errorMetaTags.length === 0 && + Array.isArray(serverInsertedHTML) && + serverInsertedHTML.length === 0 + ) { + return '' + } + const stream = await renderToReadableStream( <> { @@ -69,16 +81,21 @@ export function makeGetServerInsertedHTML({ return