diff --git a/.eslintrc.json b/.eslintrc.json index feb49b2ecbbff..8c46d8c02736f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -162,10 +162,7 @@ }, { "files": ["packages/**"], - "excludedFiles": [ - "packages/next/taskfile*.js", - "packages/next/webpack.config.js" - ], + "excludedFiles": ["packages/next/taskfile.js"], "rules": { "no-shadow": ["warn", { "builtinGlobals": false }], "import/no-extraneous-dependencies": [ diff --git a/.vscode/settings.json b/.vscode/settings.json index 2de2ef61939c7..3b28ea4bab515 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,19 +18,15 @@ ], // Disable Jest autoRun as otherwise it will start running all tests the first time. "jest.autoRun": "off", - // Debugging. "debug.javascript.unmapMissingSources": true, - "files.exclude": { "**/node_modules": false, "node_modules": true, "*[!test]**/node_modules": true }, - // Ensure enough terminal history is preserved when running tests. "terminal.integrated.scrollback": 10000, - // Configure todo-tree to exclude node_modules, dist, and compiled. "todo-tree.filtering.excludeGlobs": [ "**/node_modules", @@ -48,10 +44,8 @@ "[x]", "TODO-APP" ], - // Disable TypeScript surveys. "typescript.surveys.enabled": false, - // Enable file nesting for unit test files. "explorer.fileNesting.enabled": true, "explorer.fileNesting.patterns": { @@ -82,5 +76,6 @@ "language": "markdown", "scheme": "file" } - ] + ], + "typescript.tsdk": "node_modules/typescript/lib" } diff --git a/bench/basic-app/app/api/app/route.js b/bench/basic-app/app/api/app/route.js deleted file mode 100644 index 944ba5a8e827f..0000000000000 --- a/bench/basic-app/app/api/app/route.js +++ /dev/null @@ -1,5 +0,0 @@ -export function GET() { - return { name: 'John Doe' } -} - -export const dynamic = 'force-dynamic' diff --git a/bench/basic-app/app/layout.js b/bench/basic-app/app/layout.js deleted file mode 100644 index 8ebf54889577d..0000000000000 --- a/bench/basic-app/app/layout.js +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react' - -export default function Layout({ children }) { - return ( - - - My App - - {children} - - ) -} diff --git a/bench/basic-app/app/page.js b/bench/basic-app/app/page.js deleted file mode 100644 index 83dc3aa56c9a0..0000000000000 --- a/bench/basic-app/app/page.js +++ /dev/null @@ -1,7 +0,0 @@ -import React from 'react' - -export default function Page() { - return

My Page

-} - -export const dynamic = 'force-dynamic' diff --git a/bench/basic-app/next.config.js b/bench/basic-app/next.config.js deleted file mode 100644 index 0957c472383fa..0000000000000 --- a/bench/basic-app/next.config.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - experimental: { - serverMinification: true, - }, -} diff --git a/bench/basic-app/pages/api/index.js b/bench/basic-app/pages/api/index.js deleted file mode 100644 index 8f603094bd288..0000000000000 --- a/bench/basic-app/pages/api/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export default function handler(req, res) { - res.status(200).json({ name: 'John Doe' }) -} diff --git a/bench/basic-app/pages/pages/index.js b/bench/basic-app/pages/pages/index.js deleted file mode 100644 index e06229eee0637..0000000000000 --- a/bench/basic-app/pages/pages/index.js +++ /dev/null @@ -1,7 +0,0 @@ -export default () => 'Hello World' - -export function getServerSideProps() { - return { - props: {}, - } -} diff --git a/lerna.json b/lerna.json index 9473ac4b6bb84..a589ef7b023c6 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "13.4.20-canary.20" + "version": "13.4.20-canary.21" } diff --git a/package.json b/package.json index 5582290ae2d4c..21a75dfea9279 100644 --- a/package.json +++ b/package.json @@ -101,7 +101,7 @@ "@types/node-fetch": "2.6.1", "@types/react": "18.2.8", "@types/react-dom": "18.2.4", - "@types/relay-runtime": "13.0.0", + "@types/relay-runtime": "14.1.13", "@types/selenium-webdriver": "4.0.15", "@types/sharp": "0.29.3", "@types/string-hash": "1.1.1", @@ -226,7 +226,7 @@ "tree-kill": "1.2.2", "tsec": "0.2.1", "turbo": "1.10.9", - "typescript": "5.1.3", + "typescript": "5.2.2", "unfetch": "4.2.0", "wait-port": "0.2.2", "webpack": "5.86.0", diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index cca799bdb09c9..93dd0606ab6e7 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8e028a9ab6d75..d8032af352f66 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "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": "13.4.20-canary.20", + "@next/eslint-plugin-next": "13.4.20-canary.21", "@rushstack/eslint-patch": "^1.3.3", "@typescript-eslint/parser": "^5.4.2 || ^6.0.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 61d7b0aa5012f..2d2c6da7a230c 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": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "ESLint plugin for NextJS.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 590100e487387..20b38c3da5458 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "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 11e767e1d13e3..ba98bb5b04259 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 42ac260ab258e..60c2888bcfe50 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index dbac7a4a5d26e..38d1e9f40a0bd 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 75739c7731f17..01daaf6790025 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 1af2a0530ad19..fd6347ce0ca81 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "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 f333bb9010080..d7bb163c02bc2 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "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 c7b23dcd1e426..63889fce9a931 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/crates/next-api/src/app.rs b/packages/next-swc/crates/next-api/src/app.rs index 12ed8e5498879..295b57369a6d3 100644 --- a/packages/next-swc/crates/next-api/src/app.rs +++ b/packages/next-swc/crates/next-api/src/app.rs @@ -8,7 +8,7 @@ use next_core::{ mode::NextMode, next_app::{ get_app_client_references_chunks, get_app_client_shared_chunks, get_app_page_entry, - get_app_route_entry, AppEntry, + get_app_route_entry, AppEntry, AppPage, }, next_client::{ get_client_module_options_context, get_client_resolve_options_context, @@ -344,8 +344,7 @@ impl AppProject { .map(|(pathname, app_entrypoint)| async { Ok(( pathname.clone(), - *app_entry_point_to_route(self, app_entrypoint.clone(), pathname.clone()) - .await?, + *app_entry_point_to_route(self, app_entrypoint.clone()).await?, )) }) .try_join() @@ -360,13 +359,9 @@ impl AppProject { pub async fn app_entry_point_to_route( app_project: Vc, entrypoint: AppEntrypoint, - pathname: String, ) -> Vc { match entrypoint { - AppEntrypoint::AppPage { - original_name, - loader_tree, - } => Route::AppPage { + AppEntrypoint::AppPage { page, loader_tree } => Route::AppPage { html_endpoint: Vc::upcast( AppEndpoint { ty: AppEndpointType::Page { @@ -374,8 +369,7 @@ pub async fn app_entry_point_to_route( loader_tree, }, app_project, - pathname: pathname.clone(), - original_name: original_name.clone(), + page: page.clone(), } .cell(), ), @@ -386,22 +380,17 @@ pub async fn app_entry_point_to_route( loader_tree, }, app_project, - pathname, - original_name, + page, } .cell(), ), }, - AppEntrypoint::AppRoute { - original_name, - path, - } => Route::AppRoute { + AppEntrypoint::AppRoute { page, path } => Route::AppRoute { endpoint: Vc::upcast( AppEndpoint { ty: AppEndpointType::Route { path }, app_project, - pathname, - original_name, + page, } .cell(), ), @@ -431,8 +420,7 @@ enum AppEndpointType { struct AppEndpoint { ty: AppEndpointType, app_project: Vc, - pathname: String, - original_name: String, + page: AppPage, } #[turbo_tasks::value_impl] @@ -444,8 +432,7 @@ impl AppEndpoint { self.app_project.edge_rsc_module_context(), loader_tree, self.app_project.app_dir(), - self.pathname.clone(), - self.original_name.clone(), + self.page.clone(), self.app_project.project().project_path(), ) } @@ -456,8 +443,7 @@ impl AppEndpoint { self.app_project.rsc_module_context(), self.app_project.edge_rsc_module_context(), Vc::upcast(FileSource::new(path)), - self.pathname.clone(), - self.original_name.clone(), + self.page.clone(), self.app_project.project().project_path(), ) } diff --git a/packages/next-swc/crates/next-build/src/next_app/app_entries.rs b/packages/next-swc/crates/next-build/src/next_app/app_entries.rs index 973b30ea7d548..9c7271ecdd66d 100644 --- a/packages/next-swc/crates/next-build/src/next_app/app_entries.rs +++ b/packages/next-swc/crates/next-build/src/next_app/app_entries.rs @@ -187,31 +187,23 @@ pub async fn get_app_entries( let mut entries = entrypoints .await? .iter() - .map(|(pathname, entrypoint)| async move { + .map(|(_, entrypoint)| async move { Ok(match entrypoint { - Entrypoint::AppPage { - original_name, - loader_tree, - } => get_app_page_entry( + Entrypoint::AppPage { page, loader_tree } => get_app_page_entry( rsc_context, // TODO add edge support rsc_context, *loader_tree, app_dir, - pathname.clone(), - original_name.clone(), + page.clone(), project_root, ), - Entrypoint::AppRoute { - original_name, - path, - } => get_app_route_entry( + Entrypoint::AppRoute { page, path } => get_app_route_entry( rsc_context, // TODO add edge support rsc_context, Vc::upcast(FileSource::new(*path)), - pathname.clone(), - original_name.clone(), + page.clone(), project_root, ), }) diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 5b50aff1185cf..38bcb02a3cda6 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -39,6 +39,7 @@ turbopack-binding = { workspace = true, features = [ "__turbo_tasks_hash", "__turbopack", "__turbopack_build", + "__turbopack_cli_utils", "__turbopack_core", "__turbopack_dev", "__turbopack_dev_server", diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx index 38f27b3c1c7a3..fdec9ffc360fe 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-edge-renderer.tsx @@ -2,8 +2,6 @@ // the other imports import startOperationStreamHandler from '../internal/operation-stream' -import 'next/dist/server/node-polyfill-fetch' - import { join } from 'path' import { parse as parseUrl } from 'node:url' diff --git a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx index 25437fec08ef4..951f91570d92d 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app-renderer.tsx @@ -3,15 +3,13 @@ import startOperationStreamHandler from '../internal/operation-stream' import '../polyfill/app-polyfills.ts' -// TODO: when actions are supported, this should be removed/changed -process.env.__NEXT_PRIVATE_PREBUNDLED_REACT = 'next' -import 'next/dist/server/require-hook' import type { IncomingMessage } from 'node:http' import type { RenderData } from 'types/turbopack' import type { RenderOpts } from 'next/dist/server/app-render/types' +import { renderToHTMLOrFlight } from 'next/dist/server/app-render/app-render' import { RSC_VARY_HEADER } from 'next/dist/client/components/app-router-headers' import { headersFromEntries, initProxiedHeaders } from '../internal/headers' import { parse, ParsedUrlQuery } from 'node:querystring' @@ -25,10 +23,6 @@ import { join } from 'node:path' import { nodeFs } from 'next/dist/server/lib/node-fs-methods' import { IncrementalCache } from 'next/dist/server/lib/incremental-cache' -const { - renderToHTMLOrFlight, -} = require('next/dist/compiled/next-server/app-page.runtime.dev') - installRequireAndChunkLoad() const MIME_TEXT_HTML_UTF8 = 'text/html; charset=utf-8' diff --git a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx index c4e1bce96aa5e..abdf23d0fd7d3 100644 --- a/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx +++ b/packages/next-swc/crates/next-core/js/src/entry/app/hydrate.tsx @@ -6,7 +6,7 @@ import { createFromReadableStream } from 'next/dist/compiled/react-server-dom-we import { callServer } from 'next/dist/client/app-call-server' import { linkGc } from 'next/dist/client/app-link-gc' -import { HeadManagerContext } from 'next/dist/shared/lib/head-manager-context.shared-runtime' +import { HeadManagerContext } from 'next/dist/shared/lib/head-manager-context' import { initializeHMR } from '@vercel/turbopack-next/dev/client' diff --git a/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx b/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx index cecafb35f77a7..6182b2d7d4539 100644 --- a/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx +++ b/packages/next-swc/crates/next-core/js/src/internal/page-server-handler.tsx @@ -3,12 +3,11 @@ import { IPC } from '@vercel/turbopack-node/ipc/index' import 'next/dist/server/node-polyfill-fetch.js' -import 'next/dist/server/require-hook' import './shims' import type { IncomingMessage, ServerResponse } from 'node:http' -import type { RenderOpts } from 'next/dist/server/render' +import { renderToHTML, RenderOpts } from 'next/dist/server/render' import { getRedirectStatus } from 'next/dist/lib/redirect-status' import { PERMANENT_REDIRECT_STATUS } from 'next/dist/shared/lib/constants' import { buildStaticPaths } from 'next/dist/build/utils' @@ -22,9 +21,6 @@ import type { RenderData } from 'types/turbopack' import type { ChunkGroup } from 'types/next' import type { NextComponentType } from 'next/types' import { parse } from 'node:querystring' -const { - renderToHTML, -} = require('next/dist/compiled/next-server/pages.runtime.dev') const ipc = IPC as Ipc diff --git a/packages/next-swc/crates/next-core/js/tsconfig.json b/packages/next-swc/crates/next-core/js/tsconfig.json index a10e864117372..f7c18306acf89 100644 --- a/packages/next-swc/crates/next-core/js/tsconfig.json +++ b/packages/next-swc/crates/next-core/js/tsconfig.json @@ -4,23 +4,19 @@ "strict": true, "noFallthroughCasesInSwitch": true, "skipLibCheck": true, - // interop constraints "allowSyntheticDefaultImports": true, "esModuleInterop": true, - // js support "allowJs": true, "checkJs": false, - // environment "jsx": "react-jsx", "lib": ["ESNext", "DOM"], "target": "esnext", - // modules "baseUrl": ".", - "module": "esnext", + "module": "node16", "moduleResolution": "node16", "paths": { "@vercel/turbopack-next/*": ["src/*"], @@ -31,7 +27,6 @@ }, "resolveJsonModule": true, "types": ["react/next"], - // emit "noEmit": true, "stripInternal": true diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 738f5a4bf938f..cf35f3795f884 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, io::Write as _, iter::once}; use anyhow::{bail, Result}; use indexmap::indexmap; -use indoc::formatdoc; +use indoc::indoc; use serde_json::Value as JsonValue; use turbo_tasks::Vc; use turbopack_binding::{ @@ -65,7 +65,7 @@ use crate::{ fallback::get_fallback_page, loader_tree::{LoaderTreeModule, ServerComponentTransition}, mode::NextMode, - next_app::UnsupportedDynamicMetadataIssue, + next_app::{AppPage, AppPath, PathSegment, UnsupportedDynamicMetadataIssue}, next_client::{ context::{ get_client_assets_path, get_client_module_options_context, @@ -95,31 +95,28 @@ use crate::{ util::{render_data, NextRuntime}, }; -fn pathname_to_segments(pathname: &str) -> Result<(Vec, RouteType)> { +fn app_path_to_segments(path: &AppPath) -> Result<(Vec, RouteType)> { let mut segments = Vec::new(); - let mut split = pathname.split('/'); - while let Some(segment) = split.next() { - if segment.is_empty() - || (segment.starts_with('(') && segment.ends_with(')') || segment.starts_with('@')) - { - // ignore - } else if segment.starts_with("[[...") && segment.ends_with("]]") - || segment.starts_with("[...") && segment.ends_with(']') - { - // (optional) catch all segment - if split.remainder().is_some() { - bail!( - "Invalid route {}, catch all segment must be the last segment", - pathname - ) + let mut iter = path.iter().peekable(); + + while let Some(segment) = iter.next() { + match segment { + PathSegment::Static(s) => { + segments.push(BaseSegment::Static(s.to_string())); + } + PathSegment::Dynamic(_) => { + segments.push(BaseSegment::Dynamic); + } + PathSegment::CatchAll(_) | PathSegment::OptionalCatchAll(_) => { + if iter.peek().is_some() { + bail!( + "Invalid route {}, catch all segment must be the last segment", + path + ) + } + + return Ok((segments, RouteType::CatchAll)); } - return Ok((segments, RouteType::CatchAll)); - } else if segment.starts_with('[') || segment.ends_with(']') { - // dynamic segment - segments.push(BaseSegment::Dynamic); - } else { - // normal segment - segments.push(BaseSegment::Static(segment.to_string())); } } Ok((segments, RouteType::Exact)) @@ -654,12 +651,12 @@ pub async fn create_app_source( let entrypoints = entrypoints.await?; let mut sources: Vec<_> = entrypoints .iter() - .map(|(pathname, entrypoint)| match *entrypoint { + .map(|(_, entrypoint)| match *entrypoint { Entrypoint::AppPage { - original_name: _, + ref page, loader_tree, } => create_app_page_source_for_route( - pathname.clone(), + page.clone(), loader_tree, context_ssr, context, @@ -672,11 +669,8 @@ pub async fn create_app_source( output_path, render_data, ), - Entrypoint::AppRoute { - original_name: _, - path, - } => create_app_route_source_for_route( - pathname.clone(), + Entrypoint::AppRoute { ref page, path } => create_app_route_source_for_route( + page.clone(), path, context_ssr, project_path, @@ -696,7 +690,7 @@ pub async fn create_app_source( .collect(); if let Some(&Entrypoint::AppPage { - original_name: _, + page: _, loader_tree, }) = entrypoints.get("/_not-found") { @@ -769,7 +763,7 @@ async fn create_global_metadata_source( #[turbo_tasks::function] async fn create_app_page_source_for_route( - pathname: String, + page: AppPage, loader_tree: Vc, context_ssr: Vc, context: Vc, @@ -782,11 +776,12 @@ async fn create_app_page_source_for_route( intermediate_output_path_root: Vc, render_data: Vc, ) -> Result>> { - let pathname_vc = Vc::cell(pathname.clone()); + let app_path = AppPath::from(page.clone()); + let pathname_vc = Vc::cell(app_path.to_string()); let params_matcher = NextParamsMatcher::new(pathname_vc); - let (base_segments, route_type) = pathname_to_segments(&pathname)?; + let (base_segments, route_type) = app_path_to_segments(&app_path)?; let source = create_node_rendered_source( project_path, @@ -814,7 +809,7 @@ async fn create_app_page_source_for_route( should_debug("app_source"), ); - Ok(source.issue_file_path(app_dir, format!("Next.js App Page Route {pathname}"))) + Ok(source.issue_file_path(app_dir, format!("Next.js App Page Route {app_path}"))) } #[turbo_tasks::function] @@ -864,7 +859,7 @@ async fn create_app_not_found_page_source( #[turbo_tasks::function] async fn create_app_route_source_for_route( - pathname: String, + page: AppPage, entry_path: Vc, context_ssr: Vc, project_path: Vc, @@ -875,11 +870,12 @@ async fn create_app_route_source_for_route( intermediate_output_path_root: Vc, render_data: Vc, ) -> Result>> { - let pathname_vc = Vc::cell(pathname.to_string()); + let app_path = AppPath::from(page.clone()); + let pathname_vc = Vc::cell(app_path.to_string()); let params_matcher = NextParamsMatcher::new(pathname_vc); - let (base_segments, route_type) = pathname_to_segments(&pathname)?; + let (base_segments, route_type) = app_path_to_segments(&app_path)?; let source = create_node_api_source( project_path, @@ -906,7 +902,7 @@ async fn create_app_route_source_for_route( should_debug("app_source"), ); - Ok(source.issue_file_path(app_dir, format!("Next.js App Route {pathname}"))) + Ok(source.issue_file_path(app_dir, format!("Next.js App Route {app_path}"))) } /// The renderer for pages in app directory @@ -968,18 +964,13 @@ impl AppRenderer { .emit(); } - let mut result = RopeBuilder::from( - formatdoc!( - " - \"TURBOPACK {{ chunking-type: isolatedParallel; transition: {rsc_transition} }}\"; + let mut result = RopeBuilder::from(indoc! {" + \"TURBOPACK { chunking-type: isolatedParallel; transition: next-edge-server-component }\"; import GlobalErrorMod from \"next/dist/client/components/error-boundary\" - const {{ GlobalError }} = GlobalErrorMod; - \"TURBOPACK {{ chunking-type: isolatedParallel; transition: {rsc_transition} }}\"; + const { GlobalError } = GlobalErrorMod; + \"TURBOPACK { chunking-type: isolatedParallel; transition: next-edge-server-component }\"; import base from \"next/dist/server/app-render/entry-base\"\n - " - ) - .into_bytes(), - ); + "}); for import in loader_tree_module.imports { writeln!(result, "{import}")?; diff --git a/packages/next-swc/crates/next-core/src/app_structure.rs b/packages/next-swc/crates/next-core/src/app_structure.rs index c09ccdc644c98..a3597079af6c0 100644 --- a/packages/next-swc/crates/next-core/src/app_structure.rs +++ b/packages/next-swc/crates/next-core/src/app_structure.rs @@ -1,7 +1,11 @@ use std::collections::{BTreeMap, HashMap}; use anyhow::{bail, Result}; -use indexmap::{indexmap, map::Entry, IndexMap}; +use indexmap::{ + indexmap, + map::{Entry, OccupiedEntry}, + IndexMap, +}; use once_cell::sync::Lazy; use regex::Regex; use serde::{Deserialize, Serialize}; @@ -14,7 +18,11 @@ use turbopack_binding::{ turbopack::core::issue::{Issue, IssueExt, IssueSeverity}, }; -use crate::{next_config::NextConfig, next_import_map::get_next_package}; +use crate::{ + next_app::{AppPage, AppPath}, + next_config::NextConfig, + next_import_map::get_next_package, +}; /// A final route in the app directory. #[turbo_tasks::value] @@ -447,11 +455,11 @@ async fn merge_loader_trees( )] pub enum Entrypoint { AppPage { - original_name: String, + page: AppPage, loader_tree: Vc, }, AppRoute { - original_name: String, + page: AppPage, path: Vc, }, } @@ -487,131 +495,119 @@ async fn add_parallel_route( Ok(()) } +fn conflict_issue( + app_dir: Vc, + e: &OccupiedEntry, + a: &str, + b: &str, + value_a: &AppPage, + value_b: &AppPage, +) { + let item_names = if a == b { + format!("{}s", a) + } else { + format!("{} and {}", a, b) + }; + + DirectoryTreeIssue { + app_dir, + message: Vc::cell(format!( + "Conflicting {} at {}: {a} at {value_a} and {b} at {value_b}", + item_names, + e.key(), + )), + severity: IssueSeverity::Error.cell(), + } + .cell() + .emit(); +} + async fn add_app_page( app_dir: Vc, result: &mut IndexMap, - key: String, - original_name: String, + page: AppPage, loader_tree: Vc, ) -> Result<()> { - match result.entry(key) { - Entry::Occupied(mut e) => { - let value = e.get(); - match value { - Entrypoint::AppPage { - original_name: existing_original_name, - .. - } => { - if *existing_original_name != original_name { - DirectoryTreeIssue { - app_dir, - message: Vc::cell(format!( - "Conflicting pages at {}: {existing_original_name} and \ - {original_name}", - e.key() - )), - severity: IssueSeverity::Error.cell(), - } - .cell() - .emit(); - return Ok(()); - } - if let Entrypoint::AppPage { - loader_tree: value, .. - } = e.get_mut() - { - *value = merge_loader_trees(app_dir, *value, loader_tree) - .resolve() - .await?; - } - } - Entrypoint::AppRoute { - original_name: existing_original_name, - .. - } => { - DirectoryTreeIssue { - app_dir, - message: Vc::cell(format!( - "Conflicting page and route at {}: route at {existing_original_name} \ - and page at {original_name}", - e.key() - )), - severity: IssueSeverity::Error.cell(), - } - .cell() - .emit(); - return Ok(()); - } + let pathname = AppPath::from(page.clone()); + + let mut e = match result.entry(format!("{pathname}")) { + Entry::Occupied(e) => e, + Entry::Vacant(e) => { + e.insert(Entrypoint::AppPage { page, loader_tree }); + return Ok(()); + } + }; + + let conflict = |existing_name: &str, existing_page: &AppPage| { + conflict_issue(app_dir, &e, "page", existing_name, &page, existing_page); + }; + + let value = e.get(); + match value { + Entrypoint::AppPage { + page: existing_page, + .. + } => { + if *existing_page != page { + conflict("page", existing_page); + return Ok(()); + } + + if let Entrypoint::AppPage { + loader_tree: value, .. + } = e.get_mut() + { + *value = merge_loader_trees(app_dir, *value, loader_tree) + .resolve() + .await?; } } - Entry::Vacant(e) => { - e.insert(Entrypoint::AppPage { - original_name, - loader_tree, - }); + Entrypoint::AppRoute { + page: existing_page, + .. + } => { + conflict("route", existing_page); } } + Ok(()) } -async fn add_app_route( +fn add_app_route( app_dir: Vc, result: &mut IndexMap, - key: String, - original_name: String, + page: AppPage, path: Vc, -) -> Result<()> { - match result.entry(key) { - Entry::Occupied(mut e) => { - let value = e.get(); - match value { - Entrypoint::AppPage { - original_name: existing_original_name, - .. - } => { - DirectoryTreeIssue { - app_dir, - message: Vc::cell(format!( - "Conflicting route and page at {}: route at {original_name} and page \ - at {existing_original_name}", - e.key() - )), - severity: IssueSeverity::Error.cell(), - } - .cell() - .emit(); - } - Entrypoint::AppRoute { - original_name: existing_original_name, - .. - } => { - DirectoryTreeIssue { - app_dir, - message: Vc::cell(format!( - "Conflicting routes at {}: {existing_original_name} and \ - {original_name}", - e.key() - )), - severity: IssueSeverity::Error.cell(), - } - .cell() - .emit(); - return Ok(()); - } - } - *e.get_mut() = Entrypoint::AppRoute { - original_name, - path, - }; - } +) { + let pathname = AppPath::from(page.clone()); + + let e = match result.entry(format!("{pathname}")) { + Entry::Occupied(e) => e, Entry::Vacant(e) => { - e.insert(Entrypoint::AppRoute { - original_name, - path, - }); + e.insert(Entrypoint::AppRoute { page, path }); + return; + } + }; + + let conflict = |existing_name: &str, existing_page: &AppPage| { + conflict_issue(app_dir, &e, "route", existing_name, &page, existing_page); + }; + + let value = e.get(); + match value { + Entrypoint::AppPage { + page: existing_page, + .. + } => { + conflict("page", existing_page); + } + Entrypoint::AppRoute { + page: existing_page, + .. + } => { + conflict("route", existing_page); } } - Ok(()) } #[turbo_tasks::function] @@ -627,13 +623,7 @@ fn directory_tree_to_entrypoints( app_dir: Vc, directory_tree: Vc, ) -> Vc { - directory_tree_to_entrypoints_internal( - app_dir, - "".to_string(), - directory_tree, - "/".to_string(), - "/".to_string(), - ) + directory_tree_to_entrypoints_internal(app_dir, "".to_string(), directory_tree, AppPage::new()) } #[turbo_tasks::function] @@ -641,8 +631,7 @@ async fn directory_tree_to_entrypoints_internal( app_dir: Vc, directory_name: String, directory_tree: Vc, - path_prefix: String, - original_name_prefix: String, + app_page: AppPage, ) -> Result> { let mut result = IndexMap::new(); @@ -657,8 +646,7 @@ async fn directory_tree_to_entrypoints_internal( add_app_page( app_dir, &mut result, - path_prefix.to_string(), - original_name_prefix.to_string(), + app_page.clone(), if current_level_is_parallel_route { LoaderTree { segment: "__PAGE__".to_string(), @@ -697,8 +685,7 @@ async fn directory_tree_to_entrypoints_internal( add_app_page( app_dir, &mut result, - path_prefix.to_string(), - original_name_prefix.to_string(), + app_page.clone(), if current_level_is_parallel_route { LoaderTree { segment: "__DEFAULT__".to_string(), @@ -734,17 +721,11 @@ async fn directory_tree_to_entrypoints_internal( } if let Some(route) = components.route { - add_app_route( - app_dir, - &mut result, - path_prefix.to_string(), - original_name_prefix.to_string(), - route, - ) - .await?; + add_app_route(app_dir, &mut result, app_page.clone(), route); } - if path_prefix == "/" { + // root path: / + if app_page.len() == 0 { // Next.js has this logic in "collect-app-paths", where the root not-found page // is considered as its own entry point. if let Some(_not_found) = components.not_found { @@ -766,22 +747,14 @@ async fn directory_tree_to_entrypoints_internal( } .cell(); - add_app_page( - app_dir, - &mut result, - "/not-found".to_string(), - "/not-found".to_string(), - dev_not_found_tree, - ) - .await?; - add_app_page( - app_dir, - &mut result, - "/_not-found".to_string(), - "/_not-found".to_string(), - dev_not_found_tree, - ) - .await?; + { + let app_page = app_page.clone_push_str("not-found")?; + add_app_page(app_dir, &mut result, app_page, dev_not_found_tree).await?; + } + { + let app_page = app_page.clone_push_str("_not-found")?; + add_app_page(app_dir, &mut result, app_page, dev_not_found_tree).await?; + } } else { // Create default not-found page for production if there's no customized // not-found @@ -803,55 +776,35 @@ async fn directory_tree_to_entrypoints_internal( } .cell(); - add_app_page( - app_dir, - &mut result, - "/_not-found".to_string(), - "/_not-found".to_string(), - prod_not_found_tree, - ) - .await?; + let app_page = app_page.clone_push_str("_not-found")?; + add_app_page(app_dir, &mut result, app_page, prod_not_found_tree).await?; } } for (subdir_name, &subdirectory) in subdirectories.iter() { - let is_route_group = subdir_name.starts_with('(') && subdir_name.ends_with(')'); let parallel_route_key = match_parallel_route(subdir_name); + + let mut app_page = app_page.clone(); + if parallel_route_key.is_none() { + app_page.push_str(subdir_name)?; + } + let map = directory_tree_to_entrypoints_internal( app_dir, subdir_name.to_string(), subdirectory, - if is_route_group || parallel_route_key.is_some() { - path_prefix.clone() - } else if path_prefix == "/" { - format!("/{subdir_name}") - } else { - format!("{path_prefix}/{subdir_name}") - }, - if parallel_route_key.is_some() { - original_name_prefix.clone() - } else if original_name_prefix == "/" { - format!("/{subdir_name}") - } else { - format!("{original_name_prefix}/{subdir_name}") - }, + app_page, ) .await?; - for (full_path, entrypoint) in map.iter() { + + for (_, entrypoint) in map.iter() { match *entrypoint { Entrypoint::AppPage { - ref original_name, + ref page, loader_tree, } => { if current_level_is_parallel_route { - add_app_page( - app_dir, - &mut result, - full_path.clone(), - original_name.clone(), - loader_tree, - ) - .await?; + add_app_page(app_dir, &mut result, page.clone(), loader_tree).await?; } else { let key = parallel_route_key.unwrap_or("children").to_string(); let child_loader_tree = LoaderTree { @@ -862,28 +815,11 @@ async fn directory_tree_to_entrypoints_internal( components: components.without_leafs().cell(), } .cell(); - add_app_page( - app_dir, - &mut result, - full_path.clone(), - original_name.clone(), - child_loader_tree, - ) - .await?; + add_app_page(app_dir, &mut result, page.clone(), child_loader_tree).await?; } } - Entrypoint::AppRoute { - ref original_name, - path, - } => { - add_app_route( - app_dir, - &mut result, - full_path.clone(), - original_name.clone(), - path, - ) - .await?; + Entrypoint::AppRoute { ref page, path } => { + add_app_route(app_dir, &mut result, page.clone(), path); } } } diff --git a/packages/next-swc/crates/next-core/src/next_app/app_favicon_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_favicon_entry.rs index 0f4df5eb01f39..b72fc9af399ab 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_favicon_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_favicon_entry.rs @@ -14,7 +14,10 @@ use turbopack_binding::{ }; use super::app_route_entry::get_app_route_entry; -use crate::{app_structure::MetadataItem, next_app::AppEntry}; +use crate::{ + app_structure::MetadataItem, + next_app::{AppEntry, AppPage, PageSegment}, +}; /// Computes the entry for a Next.js favicon file. #[turbo_tasks::function] @@ -57,7 +60,7 @@ pub async fn get_app_route_favicon_entry( const contentType = {content_type} const cacheControl = {cache_control} const buffer = Buffer.from({original_file_content_b64}, 'base64') - + export function GET() {{ return new NextResponse(buffer, {{ headers: {{ @@ -66,7 +69,7 @@ pub async fn get_app_route_favicon_entry( }}, }}) }} - + export const dynamic = 'force-static' "#, content_type = StringifyJs(&content_type), @@ -84,8 +87,7 @@ pub async fn get_app_route_favicon_entry( edge_context, Vc::upcast(source), // TODO(alexkirsz) Get this from the metadata? - "/favicon.ico".to_string(), - "/favicon.ico".to_string(), + AppPage(vec![PageSegment::Static("/favicon.ico".to_string())]), project_root, )) } diff --git a/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs index bde79e2c38b4d..fd99d25664678 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_page_entry.rs @@ -19,7 +19,7 @@ use crate::{ app_structure::LoaderTree, loader_tree::{LoaderTreeModule, ServerComponentTransition}, mode::NextMode, - next_app::UnsupportedDynamicMetadataIssue, + next_app::{AppPage, AppPath, UnsupportedDynamicMetadataIssue}, next_server_component::NextServerComponentTransition, parse_segment_config_from_loader_tree, util::{load_next_js_template, virtual_next_js_template_path, NextRuntime}, @@ -32,8 +32,7 @@ pub async fn get_app_page_entry( edge_context: Vc, loader_tree: Vc, app_dir: Vc, - pathname: String, - original_name: String, + page: AppPage, project_root: Vc, ) -> Result> { let config = parse_segment_config_from_loader_tree(loader_tree, Vc::upcast(nodejs_context)); @@ -79,6 +78,9 @@ pub async fn get_app_page_entry( let pages = pages.iter().map(|page| page.to_string()).try_join().await?; + let original_name = page.to_string(); + let pathname = AppPath::from(page.clone()).to_string(); + let original_page_name = get_original_page_name(&original_name); let template_file = "build/templates/app-page.js"; @@ -90,7 +92,7 @@ pub async fn get_app_page_entry( .to_str()? .replace( "\"VAR_DEFINITION_PAGE\"", - &StringifyJs(&original_name).to_string(), + &StringifyJs(&page.to_string()).to_string(), ) .replace( "\"VAR_DEFINITION_PATHNAME\"", diff --git a/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs b/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs index 45cf5470f40e1..e60c963e0ece0 100644 --- a/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_app/app_route_entry.rs @@ -21,7 +21,7 @@ use turbopack_binding::{ }; use crate::{ - next_app::AppEntry, + next_app::{AppEntry, AppPage, AppPath}, parse_segment_config_from_source, util::{load_next_js_template, virtual_next_js_template_path, NextRuntime}, }; @@ -32,8 +32,7 @@ pub async fn get_app_route_entry( nodejs_context: Vc, edge_context: Vc, source: Vc>, - pathname: String, - original_name: String, + page: AppPage, project_root: Vc, ) -> Result> { let config = parse_segment_config_from_source( @@ -52,6 +51,9 @@ pub async fn get_app_route_entry( let mut result = RopeBuilder::default(); + let original_name = page.to_string(); + let pathname = AppPath::from(page.clone()).to_string(); + let original_page_name = get_original_route_name(&original_name); let path = source.ident().path(); diff --git a/packages/next-swc/crates/next-core/src/next_app/mod.rs b/packages/next-swc/crates/next-core/src/next_app/mod.rs index 7f40ca34fb94c..885ecdf4cd715 100644 --- a/packages/next-swc/crates/next-core/src/next_app/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_app/mod.rs @@ -6,12 +6,283 @@ pub(crate) mod app_page_entry; pub(crate) mod app_route_entry; pub(crate) mod unsupported_dynamic_metadata_issue; -pub use app_client_references_chunks::{ - get_app_client_references_chunks, ClientReferenceChunks, ClientReferencesChunks, +use std::{ + fmt::{Display, Formatter, Write}, + ops::Deref, }; -pub use app_client_shared_chunks::get_app_client_shared_chunks; -pub use app_entry::AppEntry; -pub use app_favicon_entry::get_app_route_favicon_entry; -pub use app_page_entry::get_app_page_entry; -pub use app_route_entry::get_app_route_entry; -pub use unsupported_dynamic_metadata_issue::UnsupportedDynamicMetadataIssue; + +use anyhow::{bail, Result}; +use serde::{Deserialize, Serialize}; +use turbo_tasks::{trace::TraceRawVcs, TaskInput}; + +pub use crate::next_app::{ + app_client_references_chunks::{ + get_app_client_references_chunks, ClientReferenceChunks, ClientReferencesChunks, + }, + app_client_shared_chunks::get_app_client_shared_chunks, + app_entry::AppEntry, + app_favicon_entry::get_app_route_favicon_entry, + app_page_entry::get_app_page_entry, + app_route_entry::get_app_route_entry, + unsupported_dynamic_metadata_issue::UnsupportedDynamicMetadataIssue, +}; + +#[derive(Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, TaskInput, TraceRawVcs)] +pub enum PageSegment { + Static(String), + Dynamic(String), + CatchAll(String), + OptionalCatchAll(String), + Group(String), + Parallel(String), + PageType(PageType), +} + +impl PageSegment { + pub fn parse(segment: &str) -> Result { + if segment.is_empty() { + bail!("empty segments are not allowed"); + } + + if segment.contains('/') { + bail!("slashes are not allowed in segments"); + } + + if let Some(s) = segment.strip_prefix('(').and_then(|s| s.strip_suffix(')')) { + return Ok(PageSegment::Group(s.to_string())); + } + + if let Some(s) = segment.strip_prefix('@') { + return Ok(PageSegment::Parallel(s.to_string())); + } + + if let Some(s) = segment + .strip_prefix("[[...") + .and_then(|s| s.strip_suffix("]]")) + { + return Ok(PageSegment::OptionalCatchAll(s.to_string())); + } + + if let Some(s) = segment + .strip_prefix("[...") + .and_then(|s| s.strip_suffix(']')) + { + return Ok(PageSegment::CatchAll(s.to_string())); + } + + if let Some(s) = segment.strip_prefix('[').and_then(|s| s.strip_suffix(']')) { + return Ok(PageSegment::Dynamic(s.to_string())); + } + + Ok(PageSegment::Static(segment.to_string())) + } +} + +impl Display for PageSegment { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + PageSegment::Static(s) => f.write_str(s), + PageSegment::Dynamic(s) => { + f.write_char('[')?; + f.write_str(s)?; + f.write_char(']') + } + PageSegment::CatchAll(s) => { + f.write_str("[...")?; + f.write_str(s)?; + f.write_char(']') + } + PageSegment::OptionalCatchAll(s) => { + f.write_str("[[...")?; + f.write_str(s)?; + f.write_str("]]") + } + PageSegment::Group(s) => { + f.write_char('(')?; + f.write_str(s)?; + f.write_char(')') + } + PageSegment::Parallel(s) => { + f.write_char('@')?; + f.write_str(s) + } + PageSegment::PageType(s) => Display::fmt(s, f), + } + } +} + +#[derive(Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, TaskInput, TraceRawVcs)] +pub enum PageType { + Page, + Route, +} + +impl Display for PageType { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(match self { + PageType::Page => "page", + PageType::Route => "route", + }) + } +} + +/// Describes the pathname including all internal modifiers such as +/// intercepting routes, parallel routes and route/page suffixes that are not +/// part of the pathname. +#[derive( + Clone, Debug, Hash, PartialEq, Eq, Default, Serialize, Deserialize, TaskInput, TraceRawVcs, +)] +pub struct AppPage(pub Vec); + +impl AppPage { + pub fn new() -> Self { + Self::default() + } + + pub fn push(&mut self, segment: PageSegment) -> Result<()> { + if matches!( + self.0.last(), + Some(PageSegment::CatchAll(..) | PageSegment::OptionalCatchAll(..)) + ) && !matches!(segment, PageSegment::PageType(..)) + { + bail!( + "Invalid segment {}, catch all segment must be the last segment", + segment + ) + } + + self.0.push(segment); + Ok(()) + } + + pub fn push_str(&mut self, segment: &str) -> Result<()> { + if segment.is_empty() { + return Ok(()); + } + + self.push(PageSegment::parse(segment)?) + } + + pub fn clone_push(&self, segment: PageSegment) -> Result { + let mut cloned = self.clone(); + cloned.push(segment)?; + Ok(cloned) + } + + pub fn clone_push_str(&self, segment: &str) -> Result { + let mut cloned = self.clone(); + cloned.push_str(segment)?; + Ok(cloned) + } + + pub fn parse(page: &str) -> Result { + let mut app_page = Self::new(); + + for segment in page.split('/') { + app_page.push_str(segment)?; + } + + Ok(app_page) + } +} + +impl Display for AppPage { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if self.0.is_empty() { + return f.write_char('/'); + } + + for segment in &self.0 { + f.write_char('/')?; + Display::fmt(segment, f)?; + } + + Ok(()) + } +} + +impl Deref for AppPage { + type Target = [PageSegment]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[derive(Clone, Debug, Hash, Serialize, Deserialize, PartialEq, Eq, TaskInput, TraceRawVcs)] +pub enum PathSegment { + Static(String), + Dynamic(String), + CatchAll(String), + OptionalCatchAll(String), +} + +impl Display for PathSegment { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + PathSegment::Static(s) => f.write_str(s), + PathSegment::Dynamic(s) => { + f.write_char('[')?; + f.write_str(s)?; + f.write_char(']') + } + PathSegment::CatchAll(s) => { + f.write_str("[...")?; + f.write_str(s)?; + f.write_char(']') + } + PathSegment::OptionalCatchAll(s) => { + f.write_str("[[...")?; + f.write_str(s)?; + f.write_str("]]") + } + } + } +} + +/// The pathname (including dynamic placeholders) for a route to resolve. +#[derive( + Clone, Debug, Hash, PartialEq, Eq, Default, Serialize, Deserialize, TaskInput, TraceRawVcs, +)] +pub struct AppPath(pub Vec); + +impl Deref for AppPath { + type Target = [PathSegment]; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Display for AppPath { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + if self.0.is_empty() { + return f.write_char('/'); + } + + for segment in &self.0 { + f.write_char('/')?; + Display::fmt(segment, f)?; + } + + Ok(()) + } +} + +impl From for AppPath { + fn from(value: AppPage) -> Self { + AppPath( + value + .0 + .into_iter() + .filter_map(|segment| match segment { + PageSegment::Static(s) => Some(PathSegment::Static(s)), + PageSegment::Dynamic(s) => Some(PathSegment::Dynamic(s)), + PageSegment::CatchAll(s) => Some(PathSegment::CatchAll(s)), + PageSegment::OptionalCatchAll(s) => Some(PathSegment::OptionalCatchAll(s)), + _ => None, + }) + .collect(), + ) + } +} diff --git a/packages/next-swc/crates/next-core/src/next_edge/context.rs b/packages/next-swc/crates/next-core/src/next_edge/context.rs index cfe9eebf19f94..54c7dd3331a63 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/context.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/context.rs @@ -96,9 +96,10 @@ pub async fn get_edge_resolve_options_context( ]; match ty { - ServerContextType::AppRSC { .. } => custom_conditions.push("react-server".to_string()), - ServerContextType::AppRoute { .. } - | ServerContextType::Pages { .. } + ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { + custom_conditions.push("react-server".to_string()) + } + ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } | ServerContextType::AppSSR { .. } | ServerContextType::Middleware { .. } => {} diff --git a/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs b/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs index 05326de255203..de0bd2f2e7bf7 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/route_transition.rs @@ -58,26 +58,24 @@ impl Transition for NextEdgeRouteTransition { #[turbo_tasks::function] async fn process_module( - self: Vc, + &self, asset: Vc>, context: Vc, ) -> Result>> { - let new_context = self.process_context(context); - let this = self.await?; let new_asset = route_bootstrap( asset, - Vc::upcast(new_context), - this.base_path, - this.bootstrap_asset, + Vc::upcast(context), + self.base_path, + self.bootstrap_asset, Vc::cell(indexmap! { - "NAME".to_string() => this.entry_name.clone(), + "NAME".to_string() => self.entry_name.clone(), }), ); let asset = ChunkGroupFilesAsset { module: Vc::upcast(new_asset), - client_root: this.output_path, - chunking_context: this.edge_chunking_context, + client_root: self.output_path, + chunking_context: self.edge_chunking_context, runtime_entries: None, }; diff --git a/packages/next-swc/crates/next-core/src/next_import_map.rs b/packages/next-swc/crates/next-core/src/next_import_map.rs index c530f3bcb9290..e05ac926c139f 100644 --- a/packages/next-swc/crates/next-core/src/next_import_map.rs +++ b/packages/next-swc/crates/next-core/src/next_import_map.rs @@ -216,26 +216,25 @@ pub async fn get_next_server_import_map( let ty = ty.into_value(); insert_next_server_special_aliases(&mut import_map, ty, mode, NextRuntime::NodeJs).await?; - let external: Vc = ImportMapping::External(None).cell(); + let external = ImportMapping::External(None).cell(); - import_map.insert_exact_alias("next/dist/server/require-hook", external); match ty { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { + import_map.insert_exact_alias("next", external); + import_map.insert_wildcard_alias("next/", external); import_map.insert_exact_alias("react", external); import_map.insert_wildcard_alias("react/", external); import_map.insert_exact_alias("react-dom", external); import_map.insert_wildcard_alias("react-dom/", external); import_map.insert_exact_alias("styled-jsx", external); import_map.insert_wildcard_alias("styled-jsx/", external); - import_map.insert_wildcard_alias("react-server-dom-webpack/", external); - // TODO: we should not bundle next/dist/build/utils in the pages renderer at all - import_map.insert_wildcard_alias("next/dist/build/utils", external); + import_map.insert_exact_alias("react-server-dom-webpack/", external); } ServerContextType::AppSSR { .. } | ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { match mode { - NextMode::Build => { + NextMode::Development | NextMode::Build => { import_map.insert_wildcard_alias("next/dist/server/", external); import_map.insert_wildcard_alias("next/dist/shared/", external); } @@ -243,7 +242,6 @@ pub async fn get_next_server_import_map( // The sandbox can't be bundled and needs to be external import_map.insert_exact_alias("next/dist/server/web/sandbox", external); } - NextMode::Development => {} } import_map.insert_exact_alias( "next/head", @@ -379,11 +377,6 @@ async fn insert_next_server_special_aliases( NextRuntime::Edge => request_to_import_mapping(context_dir, request), NextRuntime::NodeJs => external_request_to_import_mapping(request), }; - let passthrough_external_if_node = - move |context_dir: Vc, request: &str| match runtime { - NextRuntime::Edge => request_to_import_mapping(context_dir, request), - NextRuntime::NodeJs => ImportMapping::External(None).cell(), - }; match (mode, ty) { (_, ServerContextType::Pages { pages_dir }) => { import_map.insert_exact_alias( @@ -420,7 +413,12 @@ async fn insert_next_server_special_aliases( (_, ServerContextType::PagesData { .. }) => {} // In development, we *always* use the bundled version of React, even in // SSR, since we're bundling Next.js alongside it. - (NextMode::DevServer, ServerContextType::AppSSR { app_dir }) => { + ( + NextMode::DevServer, + ServerContextType::AppSSR { app_dir } + | ServerContextType::AppRSC { app_dir, .. } + | ServerContextType::AppRoute { app_dir }, + ) => { import_map.insert_exact_alias( "@opentelemetry/api", // TODO(WEB-625) this actually need to prefer the local version of @@ -429,40 +427,28 @@ async fn insert_next_server_special_aliases( ); import_map.insert_exact_alias( "react", - passthrough_external_if_node(app_dir, "next/dist/compiled/react"), + request_to_import_mapping(app_dir, "next/dist/compiled/react"), ); import_map.insert_wildcard_alias( "react/", - passthrough_external_if_node(app_dir, "next/dist/compiled/react/*"), + request_to_import_mapping(app_dir, "next/dist/compiled/react/*"), ); import_map.insert_exact_alias( "react-dom", - passthrough_external_if_node( + request_to_import_mapping( app_dir, "next/dist/compiled/react-dom/server-rendering-stub.js", ), ); import_map.insert_wildcard_alias( "react-dom/", - passthrough_external_if_node(app_dir, "next/dist/compiled/react-dom/*"), - ); - import_map.insert_exact_alias( - "styled-jsx", - passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx"), - ); - import_map.insert_wildcard_alias( - "styled-jsx/", - passthrough_external_if_node(app_dir, "next/dist/compiled/styled-jsx/*"), + request_to_import_mapping(app_dir, "next/dist/compiled/react-dom/*"), ); import_map.insert_wildcard_alias( "react-server-dom-webpack/", - passthrough_external_if_node( - app_dir, - "next/dist/compiled/react-server-dom-webpack/*", - ), + request_to_import_mapping(app_dir, "next/dist/compiled/react-server-dom-webpack/*"), ); } - // NOTE(alexkirsz) This logic maps loosely to // `next.js/packages/next/src/build/webpack-config.ts`, where: // @@ -474,7 +460,7 @@ async fn insert_next_server_special_aliases( // * passes through (react|react-dom|react-server-dom-webpack)/(.*) to // next/dist/compiled/$1/$2 ( - NextMode::Build | NextMode::Development | NextMode::DevServer, + NextMode::Build | NextMode::Development, ServerContextType::AppRSC { app_dir, .. } | ServerContextType::AppRoute { app_dir }, ) => { import_map.insert_exact_alias( @@ -483,20 +469,10 @@ async fn insert_next_server_special_aliases( // @opentelemetry/api request_to_import_mapping(app_dir, "next/dist/compiled/@opentelemetry/api"), ); - if matches!(ty, ServerContextType::AppRSC { .. }) { - import_map.insert_exact_alias( - "react", - request_to_import_mapping( - app_dir, - "next/dist/compiled/react/react.shared-subset", - ), - ); - } else { - import_map.insert_exact_alias( - "react", - request_to_import_mapping(app_dir, "next/dist/compiled/react"), - ); - } + import_map.insert_exact_alias( + "react", + request_to_import_mapping(app_dir, "next/dist/compiled/react/react.shared-subset"), + ); import_map.insert_exact_alias( "react-dom", request_to_import_mapping( diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index 1d242498b36df..e7485ff100ade 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -46,10 +46,7 @@ use crate::{ next_import_map::{get_next_server_import_map, mdx_import_source_file}, next_server::resolve::ExternalPredicate, next_shared::{ - resolve::{ - ModuleFeatureReportResolvePlugin, NextExternalResolvePlugin, - UnsupportedModulesResolvePlugin, - }, + resolve::{ModuleFeatureReportResolvePlugin, UnsupportedModulesResolvePlugin}, transforms::{ emotion::get_emotion_transform_plugin, get_relay_transform_plugin, styled_components::get_styled_components_transform_plugin, @@ -111,9 +108,10 @@ pub async fn get_server_resolve_options_context( let mut custom_conditions = vec![mode.node_env().to_string(), "node".to_string()]; match ty { - ServerContextType::AppRSC { .. } => custom_conditions.push("react-server".to_string()), - ServerContextType::AppRoute { .. } - | ServerContextType::Pages { .. } + ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } => { + custom_conditions.push("react-server".to_string()) + } + ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } | ServerContextType::AppSSR { .. } | ServerContextType::Middleware { .. } => {} @@ -123,15 +121,12 @@ pub async fn get_server_resolve_options_context( ExternalPredicate::AllExcept(next_config.transpile_packages()).cell(), ); - let next_external_plugin = NextExternalResolvePlugin::new(project_path); - let plugins = match ty { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { vec![ Vc::upcast(module_feature_report_resolve_plugin), Vc::upcast(external_cjs_modules_plugin), Vc::upcast(unsupported_modules_resolve_plugin), - Vc::upcast(next_external_plugin), ] } ServerContextType::AppSSR { .. } @@ -142,7 +137,6 @@ pub async fn get_server_resolve_options_context( Vc::upcast(module_feature_report_resolve_plugin), Vc::upcast(server_component_externals_plugin), Vc::upcast(unsupported_modules_resolve_plugin), - Vc::upcast(next_external_plugin), ] } }; diff --git a/packages/next-swc/crates/next-core/src/next_shared/resolve.rs b/packages/next-swc/crates/next-core/src/next_shared/resolve.rs index ea7f044c12cc8..013f87f9fd5b6 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/resolve.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/resolve.rs @@ -13,7 +13,7 @@ use turbopack_binding::{ parse::Request, pattern::Pattern, plugin::{ResolvePlugin, ResolvePluginCondition}, - ResolveResult, ResolveResultItem, ResolveResultOption, + ResolveResultOption, }, }, }; @@ -102,55 +102,6 @@ impl ResolvePlugin for UnsupportedModulesResolvePlugin { } } -#[turbo_tasks::value] -pub(crate) struct NextExternalResolvePlugin { - root: Vc, -} - -#[turbo_tasks::value_impl] -impl NextExternalResolvePlugin { - #[turbo_tasks::function] - pub fn new(root: Vc) -> Vc { - NextExternalResolvePlugin { root }.cell() - } -} - -#[turbo_tasks::value_impl] -impl ResolvePlugin for NextExternalResolvePlugin { - #[turbo_tasks::function] - fn after_resolve_condition(&self) -> Vc { - ResolvePluginCondition::new( - self.root.root(), - Glob::new( - "**/next/dist/**/*.{external,shared-runtime,runtime.dev,runtime.prod}.js" - .to_string(), - ), - ) - } - - #[turbo_tasks::function] - async fn after_resolve( - &self, - fs_path: Vc, - _context: Vc, - _request: Vc, - ) -> Result> { - let raw_fs_path = &*fs_path.await?; - let path = raw_fs_path.path.to_string(); - // Find the starting index of 'next/dist' and slice from that point. It should - // always be found since the glob pattern above is specific enough. - let starting_index = path.find("next/dist").unwrap(); - // Replace '/esm/' with '/' to match the CJS version of the file. - let modified_path = &path[starting_index..].replace("/esm/", "/"); - Ok(Vc::cell(Some( - ResolveResult::primary(ResolveResultItem::OriginalReferenceTypeExternal( - modified_path.to_string(), - )) - .into(), - ))) - } -} - /// A resolver plugin tracks the usage of certain import paths, emit /// telemetry events if there is a match. #[turbo_tasks::value] diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt deleted file mode 100644 index a5ad94c85fb0a..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-3e4dd8.txt +++ /dev/null @@ -1,17 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:64:56 lint TP1004 fs.readFile(???*0*) is very dynamic - 60 | } - 61 | async function loadWasm(wasm) { - 62 | const modules = {}; - 63 | await Promise.all(wasm.map(async (binding)=>{ - + v - 64 + const module1 = await WebAssembly.compile(await _fs.promises.readFile(binding.filePath)); - + ^ - 65 | modules[binding.name] = module1; - 66 | })); - 67 | return modules; - 68 | } - - - *0* ???*1*["filePath"] - ⚠️ unknown object - - *1* binding - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt deleted file mode 100644 index c80db085946c2..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/api/basic/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-e11df4.txt +++ /dev/null @@ -1,15 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:355:28 lint TP1004 fs.readFileSync(???*0*, "utf-8") is very dynamic - 351 | } - 352 | const moduleContext = lazyModuleContext; - 353 | const evaluateInContext = (filepath)=>{ - 354 | if (!moduleContext.paths.has(filepath)) { - + v - 355 + const content = (0, _fs.readFileSync)(filepath, "utf-8"); - + ^ - 356 | try { - 357 | (0, _vm.runInContext)(content, moduleContext.runtime.context, { - 358 | filename: filepath - 359 | }); - - - *0* filepath - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt deleted file mode 100644 index 39e97b4ccc85e..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-8ad1c9.txt +++ /dev/null @@ -1,47 +0,0 @@ -error - [rendering] [root of the server]/invalid Error during SSR Rendering - Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` - - Debug info: - - Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` - See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host - at defaultLoader (packages/next/dist/shared/lib/image-loader.js:41:27) - 37 | process.env.NEXT_RUNTIME !== "edge") { - 38 | // We use dynamic require because this should only error in development - 39 | const { hasMatch } = require("./match-remote-pattern"); - 40 | if (!hasMatch(config.domains, config.remotePatterns, parsedSrc)) { - | v - 41 + throw new Error("Invalid src prop (" + src + ') on `next/image`, hostname "' + parsedSrc.hostname + '" i...xt.config.js`\n' + "See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host"); - | ^ - 42 | } - 43 | } - 44 | } - 45 | } - - at (packages/next/dist/shared/lib/get-img-props.js:101:36) - 97 | const { widths , kind } = getWidths(config, width, sizes); - 98 | const last = widths.length - 1; - 99 | return { - 100 | sizes: !sizes && kind === "w" ? "100vw" : sizes, - | v - 101 + srcSet: widths.map((w, i)=>loader({ - | ^ - 102 | config, - 103 | src, - 104 | quality, - 105 | width: w - - at generateImgAttrs (packages/next/dist/shared/lib/get-img-props.js:101:24) - 97 | const { widths , kind } = getWidths(config, width, sizes); - 98 | const last = widths.length - 1; - 99 | return { - 100 | sizes: !sizes && kind === "w" ? "100vw" : sizes, - | v - 101 + srcSet: widths.map((w, i)=>loader({ - | ^ - 102 | config, - 103 | src, - 104 | quality, - 105 | width: w - - at getImgProps (packages/next/dist/shared/lib/get-img-props.js:392:27) - at (packages/next/dist/client/image-component.js:275:82) \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt new file mode 100644 index 0000000000000..ce775cb8df7e8 --- /dev/null +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/image/remotepattern/issues/Error during SSR Rendering-d9114a.txt @@ -0,0 +1,6 @@ +error - [rendering] [root of the server]/invalid Error during SSR Rendering + Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` + + Debug info: + - Error: Invalid src prop (https://image-optimization-test.vercel.app/test.webp) on `next/image`, hostname "image-optimization-test.vercel.app" is not configured under images in your `next.config.js` + See more info: https://nextjs.org/docs/messages/next-image-unconfigured-host \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js index 108b763da879c..e2c2f40a06dd7 100644 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/input/app/test.js @@ -120,7 +120,7 @@ function runTests() { expect(json).toMatchObject({ edgeThenNode: 'node', nodeThenEdge: 'node', - reactServer: 'default', + reactServer: 'react-server', }) }) @@ -129,7 +129,7 @@ function runTests() { expect(json).toMatchObject({ edgeThenNode: 'edge', nodeThenEdge: 'edge', - reactServer: 'default', + reactServer: 'react-server', }) }) diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt new file mode 100644 index 0000000000000..72c048d7b6481 --- /dev/null +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-b2593b.txt @@ -0,0 +1,13 @@ +error - [resolve] [project]/packages/next/dist/compiled/nanoid/index.cjs /packages/next/dist/compiled/nanoid/index.cjs:1:45 Error resolving commonjs request + + v---------------v + 1 + (()=>{var e={113:e=>{"use strict";e.exports=require("crypto")},660:(e,r,t)=>{let l=t(113);let{urlAlphabet:a}=t(591);const n=128;let _,u;let fillPool=e=>{if(!_||...ndefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(660);module.exports=t})(); + + ^---------------^ + + unable to resolve module "crypto" + + | It was not possible to find the requested file. + | Parsed request as written in source code: module "crypto" + | Path where resolving has started: [project]/packages/next/dist/compiled/nanoid/index.cjs + | Type of request: commonjs request + | Import map: No import map entry + | \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt new file mode 100644 index 0000000000000..72c048d7b6481 --- /dev/null +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/Error resolving commonjs request-dd84e7.txt @@ -0,0 +1,13 @@ +error - [resolve] [project]/packages/next/dist/compiled/nanoid/index.cjs /packages/next/dist/compiled/nanoid/index.cjs:1:45 Error resolving commonjs request + + v---------------v + 1 + (()=>{var e={113:e=>{"use strict";e.exports=require("crypto")},660:(e,r,t)=>{let l=t(113);let{urlAlphabet:a}=t(591);const n=128;let _,u;let fillPool=e=>{if(!_||...ndefined")__nccwpck_require__.ab=__dirname+"/";var t=__nccwpck_require__(660);module.exports=t})(); + + ^---------------^ + + unable to resolve module "crypto" + + | It was not possible to find the requested file. + | Parsed request as written in source code: module "crypto" + | Path where resolving has started: [project]/packages/next/dist/compiled/nanoid/index.cjs + | Type of request: commonjs request + | Import map: No import map entry + | \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt deleted file mode 100644 index a5ad94c85fb0a..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFile(__q____q____q____star__0__-76c34b.txt +++ /dev/null @@ -1,17 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:64:56 lint TP1004 fs.readFile(???*0*) is very dynamic - 60 | } - 61 | async function loadWasm(wasm) { - 62 | const modules = {}; - 63 | await Promise.all(wasm.map(async (binding)=>{ - + v - 64 + const module1 = await WebAssembly.compile(await _fs.promises.readFile(binding.filePath)); - + ^ - 65 | modules[binding.name] = module1; - 66 | })); - 67 | return modules; - 68 | } - - - *0* ???*1*["filePath"] - ⚠️ unknown object - - *1* binding - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt b/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt deleted file mode 100644 index c80db085946c2..0000000000000 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/import/conditions/issues/lint TP1004 fs.readFileSync(__q____q____q____star_-f7e52c.txt +++ /dev/null @@ -1,15 +0,0 @@ -warning - [parse] [project]/packages/next/dist/server/web/sandbox/context.js /packages/next/dist/server/web/sandbox/context.js:355:28 lint TP1004 fs.readFileSync(???*0*, "utf-8") is very dynamic - 351 | } - 352 | const moduleContext = lazyModuleContext; - 353 | const evaluateInContext = (filepath)=>{ - 354 | if (!moduleContext.paths.has(filepath)) { - + v - 355 + const content = (0, _fs.readFileSync)(filepath, "utf-8"); - + ^ - 356 | try { - 357 | (0, _vm.runInContext)(content, moduleContext.runtime.context, { - 358 | filename: filepath - 359 | }); - - - *0* filepath - ⚠️ pattern without value \ No newline at end of file diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 87ac07c84398a..47906ad8c2f6c 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/config.d.ts b/packages/next/config.d.ts index 2da1ee3c4029c..78fe148a8dc9b 100644 --- a/packages/next/config.d.ts +++ b/packages/next/config.d.ts @@ -1,3 +1,3 @@ -import getConfig from './dist/shared/lib/runtime-config.shared-runtime' -export * from './dist/shared/lib/runtime-config.shared-runtime' +import getConfig from './dist/shared/lib/runtime-config' +export * from './dist/shared/lib/runtime-config' export default getConfig diff --git a/packages/next/config.js b/packages/next/config.js index 6510748638097..2da980d8b0065 100644 --- a/packages/next/config.js +++ b/packages/next/config.js @@ -1 +1 @@ -module.exports = require('./dist/shared/lib/runtime-config.shared-runtime') +module.exports = require('./dist/shared/lib/runtime-config') diff --git a/packages/next/package.json b/packages/next/package.json index b80b6eb520902..058280c68b63f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -83,14 +83,13 @@ }, "taskr": { "requires": [ - "./taskfile-webpack.js", "./taskfile-ncc.js", "./taskfile-swc.js", "./taskfile-watch.js" ] }, "dependencies": { - "@next/env": "13.4.20-canary.20", + "@next/env": "13.4.20-canary.21", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -145,11 +144,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "13.4.20-canary.20", - "@next/polyfill-nomodule": "13.4.20-canary.20", - "@next/react-dev-overlay": "13.4.20-canary.20", - "@next/react-refresh-utils": "13.4.20-canary.20", - "@next/swc": "13.4.20-canary.20", + "@next/polyfill-module": "13.4.20-canary.21", + "@next/polyfill-nomodule": "13.4.20-canary.21", + "@next/react-dev-overlay": "13.4.20-canary.21", + "@next/react-refresh-utils": "13.4.20-canary.21", + "@next/swc": "13.4.20-canary.21", "@opentelemetry/api": "1.4.1", "@playwright/test": "^1.35.1", "@segment/ajv-human-errors": "2.1.2", @@ -173,7 +172,7 @@ "@types/fresh": "0.5.0", "@types/glob": "7.1.1", "@types/jsonwebtoken": "9.0.0", - "@types/lodash": "4.14.149", + "@types/lodash": "4.14.198", "@types/lodash.curry": "4.1.6", "@types/lru-cache": "5.1.0", "@types/micromatch": "4.0.2", @@ -254,7 +253,7 @@ "lru-cache": "5.1.1", "micromatch": "4.0.4", "mini-css-extract-plugin": "2.4.3", - "msw": "^1.2.2", + "msw": "1.3.0", "nanoid": "3.1.32", "native-url": "0.3.4", "neo-async": "2.6.1", @@ -300,7 +299,6 @@ "tar": "6.1.15", "taskr": "1.1.0", "terser": "5.14.1", - "terser-webpack-plugin": "5.3.9", "text-table": "0.2.0", "timers-browserify": "2.0.12", "tty-browserify": "0.0.1", diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index b0e0870ca1392..8ad7407b4be45 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -143,13 +143,8 @@ import { createClientRouterFilter } from '../lib/create-client-router-filter' import { createValidFileMatcher } from '../server/lib/find-page-file' import { startTypeChecking } from './type-check' import { generateInterceptionRoutesRewrites } from '../lib/generate-interception-routes-rewrites' - import { buildDataRoute } from '../server/lib/router-utils/build-data-route' -import { - baseOverrides, - defaultOverrides, - experimentalOverrides, -} from '../server/require-hook' +import { baseOverrides, experimentalOverrides } from '../server/require-hook' import { initialize } from '../server/lib/incremental-cache-server' import { nodeFs } from '../server/lib/node-fs-methods' @@ -1248,7 +1243,6 @@ export default async function build( forkOptions: { env: { ...process.env, - __NEXT_PRIVATE_RENDER_RUNTIME: type, __NEXT_INCREMENTAL_CACHE_IPC_PORT: ipcPort + '', __NEXT_INCREMENTAL_CACHE_IPC_KEY: ipcValidationKey, __NEXT_PRIVATE_PREBUNDLED_REACT: @@ -2090,25 +2084,6 @@ export default async function build( ...Object.values(experimentalOverrides).map((override) => require.resolve(override) ), - ...(config.experimental.turbotrace - ? [] - : Object.keys(defaultOverrides).map((value) => - require.resolve(value, { - paths: [require.resolve('next/dist/server/require-hook')], - }) - )), - require.resolve( - 'next/dist/compiled/next-server/app-page.runtime.prod' - ), - require.resolve( - 'next/dist/compiled/next-server/app-route.runtime.prod' - ), - require.resolve( - 'next/dist/compiled/next-server/pages.runtime.prod' - ), - require.resolve( - 'next/dist/compiled/next-server/pages-api.runtime.prod' - ), ] // ensure we trace any dependencies needed for custom @@ -2134,7 +2109,10 @@ export default async function build( const minimalServerEntries = [ ...sharedEntriesSet, require.resolve( - 'next/dist/compiled/next-server/server.runtime.prod' + 'next/dist/compiled/minimal-next-server/next-server-cached.js' + ), + require.resolve( + 'next/dist/compiled/minimal-next-server/next-server.js' ), ].filter(Boolean) diff --git a/packages/next/src/build/templates/app-page.ts b/packages/next/src/build/templates/app-page.ts index f0d2ab692e2aa..c75509904c3a8 100644 --- a/packages/next/src/build/templates/app-page.ts +++ b/packages/next/src/build/templates/app-page.ts @@ -1,7 +1,7 @@ import type { LoaderTree } from '../../server/lib/app-dir-module' // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/app-page/module.compiled' +import * as module from 'next/dist/server/future/route-modules/app-page/module' import { RouteKind } from '../../server/future/route-kind' const AppPageRouteModule = diff --git a/packages/next/src/build/templates/app-route.ts b/packages/next/src/build/templates/app-route.ts index b4b8e5b0fe6cd..50a8b6165a747 100644 --- a/packages/next/src/build/templates/app-route.ts +++ b/packages/next/src/build/templates/app-route.ts @@ -1,8 +1,7 @@ import '../../server/node-polyfill-headers' // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/app-route/module.compiled' - +import * as module from 'next/dist/server/future/route-modules/app-route/module' import type { AppRouteRouteModuleOptions } from '../../server/future/route-modules/app-route/module' import { RouteKind } from '../../server/future/route-kind' diff --git a/packages/next/src/build/templates/pages-api.ts b/packages/next/src/build/templates/pages-api.ts index eaeec836cb61e..a48822f9ed75a 100644 --- a/packages/next/src/build/templates/pages-api.ts +++ b/packages/next/src/build/templates/pages-api.ts @@ -1,6 +1,5 @@ // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/pages-api/module.compiled' - +import * as module from 'next/dist/server/future/route-modules/pages-api/module' import { RouteKind } from '../../server/future/route-kind' import { hoist } from './helpers' diff --git a/packages/next/src/build/templates/pages.ts b/packages/next/src/build/templates/pages.ts index b5def5d13c552..3f3527e6650d6 100644 --- a/packages/next/src/build/templates/pages.ts +++ b/packages/next/src/build/templates/pages.ts @@ -1,5 +1,5 @@ // @ts-ignore this need to be imported from next/dist to be external -import * as module from 'next/dist/server/future/route-modules/pages/module.compiled' +import * as module from 'next/dist/server/future/route-modules/pages/module' import { RouteKind } from '../../server/future/route-kind' import { hoist } from './helpers' diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index 423beb27f6dca..867429c2ba901 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -14,7 +14,7 @@ import type { EdgeFunctionDefinition, MiddlewareManifest, } from './webpack/plugins/middleware-plugin' -import type { StaticGenerationAsyncStorage } from '../client/components/static-generation-async-storage.external' +import type { StaticGenerationAsyncStorage } from '../client/components/static-generation-async-storage' import '../server/require-hook' import '../server/node-polyfill-fetch' @@ -65,9 +65,7 @@ import { nodeFs } from '../server/lib/node-fs-methods' import * as ciEnvironment from '../telemetry/ci-info' import { normalizeAppPath } from '../shared/lib/router/utils/app-paths' import { denormalizeAppPagePath } from '../shared/lib/page-path/denormalize-app-path' -// import { AppRouteRouteModule } from '../server/future/route-modules/app-route/module' -const { AppRouteRouteModule } = - require('../server/future/route-modules/app-route/module.compiled') as typeof import('../server/future/route-modules/app-route/module') +import { AppRouteRouteModule } from '../server/future/route-modules/app-route/module' export type ROUTER_TYPE = 'pages' | 'app' @@ -1391,9 +1389,7 @@ export async function isPageStatic({ const isPageStaticSpan = trace('is-page-static-utils', parentId) return isPageStaticSpan .traceAsyncFn(async () => { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config').setConfig(runtimeEnvConfig) setHttpClientAndAgentOptions({ httpAgentOptions, }) @@ -1677,9 +1673,7 @@ export async function hasCustomGetInitialProps( runtimeEnvConfig: any, checkingApp: boolean ): Promise { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config').setConfig(runtimeEnvConfig) const components = await loadComponents({ distDir, @@ -1702,9 +1696,7 @@ export async function getDefinedNamedExports( distDir: string, runtimeEnvConfig: any ): Promise> { - require('../shared/lib/runtime-config.shared-runtime').setConfig( - runtimeEnvConfig - ) + require('../shared/lib/runtime-config').setConfig(runtimeEnvConfig) const components = await loadComponents({ distDir, pathname: page, diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index d1b7487618fe2..f1f053d05eb9b 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -103,19 +103,6 @@ const reactPackagesRegex = /^(react|react-dom|react-server-dom-webpack)($|\/)/ const asyncStoragesRegex = /next[\\/]dist[\\/](esm[\\/])?client[\\/]components[\\/](static-generation-async-storage|action-async-storage|request-async-storage)/ -const pathSeparators = '[/\\\\]' -const optionalEsmPart = `((${pathSeparators}esm)?${pathSeparators})` -const sharedRuntimeFileEnd = '(\\.shared-runtime(\\.js)?)$' -const externalFileEnd = '(\\.external(\\.js)?)$' -const nextDist = `next${pathSeparators}dist` - -const sharedRuntimePattern = new RegExp( - `${nextDist}${optionalEsmPart}.*${sharedRuntimeFileEnd}` -) -const externalPattern = new RegExp( - `${nextDist}${optionalEsmPart}.*${externalFileEnd}` -) - // exports. const edgeConditionNames = [ 'edge-light', @@ -1024,7 +1011,7 @@ export default async function getBaseWebpackConfig( const customRootAliases: { [key: string]: string[] } = {} if (dev) { - const nextDistPath = 'next/dist/' + (isEdgeServer ? 'esm/' : '') + const nextDist = 'next/dist/' + (isEdgeServer ? 'esm/' : '') customAppAliases[`${PAGES_DIR_ALIAS}/_app`] = [ ...(pagesDir ? pageExtensions.reduce((prev, ext) => { @@ -1032,7 +1019,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `${nextDistPath}pages/_app.js`, + `${nextDist}pages/_app.js`, ] customAppAliases[`${PAGES_DIR_ALIAS}/_error`] = [ ...(pagesDir @@ -1041,7 +1028,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `${nextDistPath}pages/_error.js`, + `${nextDist}pages/_error.js`, ] customDocumentAliases[`${PAGES_DIR_ALIAS}/_document`] = [ ...(pagesDir @@ -1050,7 +1037,7 @@ export default async function getBaseWebpackConfig( return prev }, [] as string[]) : []), - `${nextDistPath}pages/_document.js`, + `${nextDist}pages/_document.js`, ] } @@ -1324,7 +1311,6 @@ export default async function getBaseWebpackConfig( WEBPACK_LAYERS.serverSideRendering, WEBPACK_LAYERS.appPagesBrowser, WEBPACK_LAYERS.actionBrowser, - WEBPACK_LAYERS.appRouteHandler, ].includes(layer!) if ( @@ -1381,7 +1367,7 @@ export default async function getBaseWebpackConfig( } const notExternalModules = - /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers|router)$)|string-hash|private-next-rsc-action-validate|private-next-rsc-action-client-wrapper|private-next-rsc-action-proxy$)/ + /^(?:private-next-pages\/|next\/(?:dist\/pages\/|(?:app|document|link|image|legacy\/image|constants|dynamic|script|navigation|headers)$)|string-hash|private-next-rsc-action-validate|private-next-rsc-action-client-wrapper|private-next-rsc-action-proxy$)/ if (notExternalModules.test(request)) { return } @@ -1404,59 +1390,41 @@ export default async function getBaseWebpackConfig( // Also disable esm request when appDir is enabled const isEsmRequested = dependencyType === 'esm' - /** - * @param localRes the full path to the file - * @returns the externalized path - * @description returns an externalized path if the file is a Next.js file and ends with either `.shared-runtime.js` or `.external.js` - * This is used to ensure that files used across the rendering runtime(s) and the user code are one and the same. The logic in this function - * will rewrite the require to the correct bundle location depending on the layer at which the file is being used. - */ const isLocalCallback = (localRes: string) => { - const isSharedRuntime = sharedRuntimePattern.test(localRes) - const isExternal = externalPattern.test(localRes) - - // if the file ends with .external, we need to make it a commonjs require in all cases - // this is used mainly to share the async local storage across the routing, rendering and user layers. - if (isExternal) { - // it's important we return the path that starts with `next/dist/` here instead of the absolute path - // otherwise NFT will get tripped up - return `commonjs ${localRes.replace(/.*?next[/\\]dist/, 'next/dist')}` - } - // if the file ends with .shared-runtime, we need to make it point to the correct bundle depending on the layer - // this is because each shared-runtime files are unique per bundle, so if you use app-router context in pages, - // it'll be a different instance than the one used in the app-router runtime. - if (isSharedRuntime) { - if (dev) { - return `commonjs ${localRes}` - } + // Makes sure dist/shared and dist/server are not bundled + // we need to process shared `router/router`, `head` and `dynamic`, + // so that the DefinePlugin can inject process.env values. - const name = path.parse(localRes).name.replace('.shared-runtime', '') + // Treat next internals as non-external for server layer + if (isWebpackServerLayer(layer)) { + return + } - const camelCaseName = name.replace(/-([a-z])/g, (_, w) => - w.toUpperCase() + const isNextExternal = + /next[/\\]dist[/\\](esm[\\/])?(shared|server)[/\\](?!lib[/\\](router[/\\]router|dynamic|app-dynamic|image-external|lazy-dynamic|head[^-]))/.test( + localRes + ) || + // There's no need to bundle the dev overlay + (process.env.NODE_ENV === 'development' && + /next[/\\]dist[/\\](esm[/\\])?client[/\\]components[/\\]react-dev-overlay[/\\]/.test( + localRes + )) + + if (isNextExternal) { + // Generate Next.js external import + const externalRequest = path.posix.join( + 'next', + 'dist', + path + .relative( + // Root of Next.js package: + path.join(__dirname, '..'), + localRes + ) + // Windows path normalization + .replace(/\\/g, '/') ) - - // there's no externals for API routes but if need be, they'll need to be added here and have - // their own layer - const runtime = - layer === 'app-route-handler' - ? 'app-route' - : isAppLayer - ? 'app-page' - : 'pages' - return [ - 'commonjs ' + - path.posix.join( - 'next', - 'dist', - 'compiled', - 'next-server', - `${runtime}.runtime.${dev ? 'dev' : 'prod'}` - ), - 'default', - 'sharedModules', - camelCaseName, - ] + return `commonjs ${externalRequest}` } } @@ -1477,10 +1445,6 @@ export default async function getBaseWebpackConfig( return } - if (/^next\/dist\/compiled\/next-server/.test(request)) { - return `commonjs ${request}` - } - if ( /^next\/dist\/shared\/(?!lib\/router\/router)/.test(request) || /^next\/dist\/compiled\/.*\.c?js$/.test(request) @@ -2067,14 +2031,6 @@ export default async function getBaseWebpackConfig( }, ...(hasAppDir ? [ - { - layer: WEBPACK_LAYERS.appRouteHandler, - test: new RegExp( - `private-next-app-dir\\/.*\\/route\\.(${pageExtensions.join( - '|' - )})$` - ), - }, { // Make sure that AsyncLocalStorage module instance is shared between server and client // layers. @@ -2283,7 +2239,7 @@ export default async function getBaseWebpackConfig( WEBPACK_LAYERS.appPagesBrowser, ], }, - exclude: [codeCondition.exclude], + exclude: [asyncStoragesRegex, codeCondition.exclude], use: [ ...(dev && isClient ? [ diff --git a/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts b/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts index c2b1089df5b3f..2be12daecdbc6 100644 --- a/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts +++ b/packages/next/src/build/webpack/plugins/next-types-plugin/index.ts @@ -442,7 +442,7 @@ declare module 'next/link' { declare module 'next/navigation' { export * from 'next/dist/client/components/navigation.js' - import type { NavigateOptions, AppRouterInstance as OriginalAppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime.js' + import type { NavigateOptions, AppRouterInstance as OriginalAppRouterInstance } from 'next/dist/shared/lib/app-router-context.js' interface AppRouterInstance extends OriginalAppRouterInstance { /** * Navigate to the provided href. @@ -575,11 +575,8 @@ export class NextTypesPlugin { } return } - if ( - mod.layer !== WEBPACK_LAYERS.reactServerComponents && - mod.layer !== WEBPACK_LAYERS.appRouteHandler - ) - return + + if (mod.layer !== WEBPACK_LAYERS.reactServerComponents) return const IS_LAYOUT = /[/\\]layout\.[^./\\]+$/.test(mod.resource) const IS_PAGE = !IS_LAYOUT && /[/\\]page\.[^.]+$/.test(mod.resource) diff --git a/packages/next/src/client/app-index.tsx b/packages/next/src/client/app-index.tsx index 47c0bd13f369e..8f82d244837e6 100644 --- a/packages/next/src/client/app-index.tsx +++ b/packages/next/src/client/app-index.tsx @@ -7,8 +7,8 @@ import React, { use } from 'react' // eslint-disable-next-line import/no-extraneous-dependencies import { createFromReadableStream } from 'react-server-dom-webpack/client' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' -import { GlobalLayoutRouterContext } from '../shared/lib/app-router-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' +import { GlobalLayoutRouterContext } from '../shared/lib/app-router-context' import onRecoverableError from './on-recoverable-error' import { callServer } from './app-call-server' import { isNextRouterError } from './components/is-next-router-error' diff --git a/packages/next/src/client/compat/router.ts b/packages/next/src/client/compat/router.ts index e9143c4117bd7..58b1b9f02ed05 100644 --- a/packages/next/src/client/compat/router.ts +++ b/packages/next/src/client/compat/router.ts @@ -1,5 +1,5 @@ import { useContext } from 'react' -import { RouterContext } from '../../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../../shared/lib/router-context' import { NextRouter } from '../router' /** diff --git a/packages/next/src/client/components/action-async-storage.external.ts b/packages/next/src/client/components/action-async-storage.ts similarity index 100% rename from packages/next/src/client/components/action-async-storage.external.ts rename to packages/next/src/client/components/action-async-storage.ts diff --git a/packages/next/src/client/components/app-router.tsx b/packages/next/src/client/components/app-router.tsx index 2c3c541e02b8e..db181118a674a 100644 --- a/packages/next/src/client/components/app-router.tsx +++ b/packages/next/src/client/components/app-router.tsx @@ -14,11 +14,11 @@ import { LayoutRouterContext, GlobalLayoutRouterContext, CacheStates, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import type { CacheNode, AppRouterInstance, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import type { FlightRouterState, FlightData, @@ -33,18 +33,18 @@ import { ACTION_RESTORE, ACTION_SERVER_ACTION, ACTION_SERVER_PATCH, + Mutable, PrefetchKind, ReducerActions, RouterChangeByServerResponse, RouterNavigate, ServerActionDispatcher, - ServerActionMutable, } from './router-reducer/router-reducer-types' import { createHrefFromUrl } from './router-reducer/create-href-from-url' import { SearchParamsContext, PathnameContext, -} from '../../shared/lib/hooks-client-context.shared-runtime' +} from '../../shared/lib/hooks-client-context' import { useReducerWithReduxDevtools } from './use-reducer-with-devtools' import { ErrorBoundary } from './error-boundary' import { @@ -73,7 +73,7 @@ export function getServerActionDispatcher() { return globalServerActionDispatcher } -let globalServerActionMutable: ServerActionMutable['globalMutable'] = { +let globalMutable: Mutable['globalMutable'] = { refresh: () => {}, // noop until the router is initialized } @@ -145,7 +145,7 @@ function useServerActionDispatcher(dispatch: React.Dispatch) { dispatch({ ...actionPayload, type: ACTION_SERVER_ACTION, - mutable: { globalMutable: globalServerActionMutable }, + mutable: { globalMutable }, cache: createEmptyCacheNode(), }) }) @@ -174,7 +174,7 @@ function useChangeByServerResponse( previousTree, overrideCanonicalUrl, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, }) }) }, @@ -186,7 +186,7 @@ function useNavigate(dispatch: React.Dispatch): RouterNavigate { return useCallback( (href, navigateType, forceOptimisticNavigation, shouldScroll) => { const url = new URL(addBasePath(href), location.href) - globalServerActionMutable.pendingNavigatePath = href + globalMutable.pendingNavigatePath = href return dispatch({ type: ACTION_NAVIGATE, @@ -197,7 +197,7 @@ function useNavigate(dispatch: React.Dispatch): RouterNavigate { shouldScroll: shouldScroll ?? true, navigateType, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, }) }, [dispatch] @@ -322,7 +322,7 @@ function Router({ dispatch({ type: ACTION_REFRESH, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, origin: window.location.origin, }) }) @@ -338,7 +338,7 @@ function Router({ dispatch({ type: ACTION_FAST_REFRESH, cache: createEmptyCacheNode(), - mutable: {}, + mutable: { globalMutable }, origin: window.location.origin, }) }) @@ -357,7 +357,7 @@ function Router({ }, [appRouter]) useEffect(() => { - globalServerActionMutable.refresh = appRouter.refresh + globalMutable.refresh = appRouter.refresh }, [appRouter.refresh]) if (process.env.NODE_ENV !== 'production') { @@ -409,11 +409,16 @@ function Router({ // in . At least I hope so. (It will run twice in dev strict mode, // but that's... fine?) if (pushRef.mpaNavigation) { - const location = window.location - if (pushRef.pendingPush) { - location.assign(canonicalUrl) - } else { - location.replace(canonicalUrl) + // if there's a re-render, we don't want to trigger another redirect if one is already in flight to the same URL + if (globalMutable.pendingMpaPath !== canonicalUrl) { + const location = window.location + if (pushRef.pendingPush) { + location.assign(canonicalUrl) + } else { + location.replace(canonicalUrl) + } + + globalMutable.pendingMpaPath = canonicalUrl } // TODO-APP: Should we listen to navigateerror here to catch failed // navigations somehow? And should we call window.stop() if a SPA navigation diff --git a/packages/next/src/client/components/bailout-to-client-rendering.ts b/packages/next/src/client/components/bailout-to-client-rendering.ts index 799398b5f300c..76356e05304a8 100644 --- a/packages/next/src/client/components/bailout-to-client-rendering.ts +++ b/packages/next/src/client/components/bailout-to-client-rendering.ts @@ -1,5 +1,5 @@ import { suspense } from '../../shared/lib/lazy-dynamic/dynamic-no-ssr' -import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' +import { staticGenerationAsyncStorage } from './static-generation-async-storage' export function bailoutToClientRendering(): boolean | never { const staticGenerationStore = staticGenerationAsyncStorage.getStore() diff --git a/packages/next/src/client/components/headers.ts b/packages/next/src/client/components/headers.ts index a0a27a184cbfe..d090264391e7c 100644 --- a/packages/next/src/client/components/headers.ts +++ b/packages/next/src/client/components/headers.ts @@ -4,8 +4,8 @@ import { } from '../../server/web/spec-extension/adapters/request-cookies' import { HeadersAdapter } from '../../server/web/spec-extension/adapters/headers' import { RequestCookies } from '../../server/web/spec-extension/cookies' -import { requestAsyncStorage } from './request-async-storage.external' -import { actionAsyncStorage } from './action-async-storage.external' +import { requestAsyncStorage } from './request-async-storage' +import { actionAsyncStorage } from './action-async-storage' import { staticGenerationBailout } from './static-generation-bailout' import { DraftMode } from './draft-mode' @@ -17,6 +17,7 @@ export function headers() { ) { return HeadersAdapter.seal(new Headers({})) } + const requestStore = requestAsyncStorage.getStore() if (!requestStore) { throw new Error( diff --git a/packages/next/src/client/components/layout-router.tsx b/packages/next/src/client/components/layout-router.tsx index 1f0ffff7e2de8..3e410a93fb0ca 100644 --- a/packages/next/src/client/components/layout-router.tsx +++ b/packages/next/src/client/components/layout-router.tsx @@ -1,6 +1,6 @@ 'use client' -import type { ChildSegmentMap } from '../../shared/lib/app-router-context.shared-runtime' +import type { ChildSegmentMap } from '../../shared/lib/app-router-context' import type { FlightRouterState, FlightSegmentPath, @@ -17,7 +17,7 @@ import { LayoutRouterContext, GlobalLayoutRouterContext, TemplateContext, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import { fetchServerResponse } from './router-reducer/fetch-server-response' import { createInfinitePromise } from './infinite-promise' import { ErrorBoundary } from './error-boundary' diff --git a/packages/next/src/client/components/navigation.ts b/packages/next/src/client/components/navigation.ts index b3d69dcb065e8..bf6a56100080d 100644 --- a/packages/next/src/client/components/navigation.ts +++ b/packages/next/src/client/components/navigation.ts @@ -4,11 +4,11 @@ import { AppRouterContext, GlobalLayoutRouterContext, LayoutRouterContext, -} from '../../shared/lib/app-router-context.shared-runtime' +} from '../../shared/lib/app-router-context' import { SearchParamsContext, PathnameContext, -} from '../../shared/lib/hooks-client-context.shared-runtime' +} from '../../shared/lib/hooks-client-context' import { clientHookInServerComponentError } from './client-hook-in-server-component-error' import { getSegmentValue } from './router-reducer/reducers/get-segment-value' @@ -111,12 +111,12 @@ export function usePathname(): string { export { ServerInsertedHTMLContext, useServerInsertedHTML, -} from '../../shared/lib/server-inserted-html.shared-runtime' +} from '../../shared/lib/server-inserted-html' /** * Get the router methods. For example router.push('/dashboard') */ -export function useRouter(): import('../../shared/lib/app-router-context.shared-runtime').AppRouterInstance { +export function useRouter(): import('../../shared/lib/app-router-context').AppRouterInstance { clientHookInServerComponentError('useRouter') const router = useContext(AppRouterContext) if (router === null) { diff --git a/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts b/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts index d37fce9851e91..4d92a279c3ed5 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts +++ b/packages/next/src/client/components/react-dev-overlay/internal/helpers/use-websocket.ts @@ -1,5 +1,5 @@ import { useCallback, useContext, useEffect, useRef } from 'react' -import { GlobalLayoutRouterContext } from '../../../../../shared/lib/app-router-context.shared-runtime' +import { GlobalLayoutRouterContext } from '../../../../../shared/lib/app-router-context' import { getSocketUrl } from './get-socket-url' export function useWebsocket(assetPrefix: string) { diff --git a/packages/next/src/client/components/redirect-boundary.tsx b/packages/next/src/client/components/redirect-boundary.tsx index 8d407fd6e9d6e..23e5493ae83fb 100644 --- a/packages/next/src/client/components/redirect-boundary.tsx +++ b/packages/next/src/client/components/redirect-boundary.tsx @@ -1,6 +1,6 @@ 'use client' import React, { useEffect } from 'react' -import { AppRouterInstance } from '../../shared/lib/app-router-context.shared-runtime' +import { AppRouterInstance } from '../../shared/lib/app-router-context' import { useRouter } from './navigation' import { RedirectType, diff --git a/packages/next/src/client/components/redirect.ts b/packages/next/src/client/components/redirect.ts index b9a2cfebd883f..10e72bc1ccbef 100644 --- a/packages/next/src/client/components/redirect.ts +++ b/packages/next/src/client/components/redirect.ts @@ -1,4 +1,4 @@ -import { requestAsyncStorage } from './request-async-storage.external' +import { requestAsyncStorage } from './request-async-storage' import type { ResponseCookies } from '../../server/web/spec-extension/cookies' const REDIRECT_ERROR_CODE = 'NEXT_REDIRECT' diff --git a/packages/next/src/client/components/render-from-template-context.tsx b/packages/next/src/client/components/render-from-template-context.tsx index c1755cc5056bf..be486842c4f33 100644 --- a/packages/next/src/client/components/render-from-template-context.tsx +++ b/packages/next/src/client/components/render-from-template-context.tsx @@ -1,7 +1,7 @@ 'use client' import React, { useContext } from 'react' -import { TemplateContext } from '../../shared/lib/app-router-context.shared-runtime' +import { TemplateContext } from '../../shared/lib/app-router-context' export default function RenderFromTemplateContext(): JSX.Element { const children = useContext(TemplateContext) diff --git a/packages/next/src/client/components/request-async-storage.external.ts b/packages/next/src/client/components/request-async-storage.ts similarity index 100% rename from packages/next/src/client/components/request-async-storage.external.ts rename to packages/next/src/client/components/request-async-storage.ts diff --git a/packages/next/src/client/components/router-reducer/apply-flight-data.ts b/packages/next/src/client/components/router-reducer/apply-flight-data.ts index 003d0a5cde9e4..e7a2f11a84f48 100644 --- a/packages/next/src/client/components/router-reducer/apply-flight-data.ts +++ b/packages/next/src/client/components/router-reducer/apply-flight-data.ts @@ -1,7 +1,4 @@ -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import { FlightDataPath } from '../../../server/app-render/types' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' import { fillCacheWithNewSubTreeData } from './fill-cache-with-new-subtree-data' diff --git a/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx b/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx index 414b553c63249..a6052636ef256 100644 --- a/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx +++ b/packages/next/src/client/components/router-reducer/create-initial-router-state.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import type { FlightRouterState } from '../../../server/app-render/types' -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import { createInitialRouterState } from './create-initial-router-state' const buildId = 'development' diff --git a/packages/next/src/client/components/router-reducer/create-initial-router-state.ts b/packages/next/src/client/components/router-reducer/create-initial-router-state.ts index 94fdabb9b577a..7f7cca2003b0b 100644 --- a/packages/next/src/client/components/router-reducer/create-initial-router-state.ts +++ b/packages/next/src/client/components/router-reducer/create-initial-router-state.ts @@ -1,8 +1,8 @@ import type { ReactNode } from 'react' -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' -import { CacheStates } from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates } from '../../../shared/lib/app-router-context' import { createHrefFromUrl } from './create-href-from-url' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' import { extractPathFromFlightRouterState } from './compute-changed-path' diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx index 648069ea76986..28f8c3412ab3a 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.test.tsx @@ -1,10 +1,7 @@ import React from 'react' import { fetchServerResponse } from './fetch-server-response' import { fillCacheWithDataProperty } from './fill-cache-with-data-property' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' describe('fillCacheWithDataProperty', () => { it('should add data property', () => { const fetchServerResponseMock: jest.Mock< diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts index 42df61a952af5..81df295dba302 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-data-property.ts @@ -1,8 +1,5 @@ import { FlightSegmentPath } from '../../../server/app-render/types' -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import { createRouterCacheKey } from './create-router-cache-key' import { fetchServerResponse } from './fetch-server-response' diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx index ac888a3ede0ff..187f86a478751 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import { fillCacheWithNewSubTreeData } from './fill-cache-with-new-subtree-data' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import type { FlightData } from '../../../server/app-render/types' const getFlightData = (): FlightData => { diff --git a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts index 7e9a93699fb65..5d48eaee9ef9f 100644 --- a/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts +++ b/packages/next/src/client/components/router-reducer/fill-cache-with-new-subtree-data.ts @@ -1,7 +1,4 @@ -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import type { FlightDataPath } from '../../../server/app-render/types' import { invalidateCacheByRouterState } from './invalidate-cache-by-router-state' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' diff --git a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx index 1edbeffd7b3e9..606440a96f9c9 100644 --- a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx +++ b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import { fillLazyItemsTillLeafWithHead } from './fill-lazy-items-till-leaf-with-head' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import type { FlightData } from '../../../server/app-render/types' const getFlightData = (): FlightData => { diff --git a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts index f558edfab2f1e..c5ddedd52351e 100644 --- a/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts +++ b/packages/next/src/client/components/router-reducer/fill-lazy-items-till-leaf-with-head.ts @@ -1,7 +1,4 @@ -import { - CacheNode, - CacheStates, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheNode, CacheStates } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' import { createRouterCacheKey } from './create-router-cache-key' diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx index 8c23c47d42d74..915f09cae0cae 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.test.tsx @@ -1,10 +1,7 @@ import React from 'react' import type { FlightData } from '../../../server/app-render/types' import { invalidateCacheBelowFlightSegmentPath } from './invalidate-cache-below-flight-segmentpath' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import { fillCacheWithNewSubTreeData } from './fill-cache-with-new-subtree-data' const getFlightData = (): FlightData => { diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts index d637d850b145a..ac343f8d79679 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-below-flight-segmentpath.ts @@ -1,4 +1,4 @@ -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightSegmentPath } from '../../../server/app-render/types' import { createRouterCacheKey } from './create-router-cache-key' diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx index bdd819b0614d9..65ce9e42c05ee 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.test.tsx @@ -1,9 +1,6 @@ import React from 'react' import { invalidateCacheByRouterState } from './invalidate-cache-by-router-state' -import { - CacheStates, - CacheNode, -} from '../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates, CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' describe('invalidateCacheByRouterState', () => { diff --git a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts index 1ec39ae9e35fd..820e5909bf031 100644 --- a/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts +++ b/packages/next/src/client/components/router-reducer/invalidate-cache-by-router-state.ts @@ -1,4 +1,4 @@ -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState } from '../../../server/app-render/types' import { createRouterCacheKey } from './create-router-cache-key' diff --git a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx index 2d4cdef348b1e..807374c855577 100644 --- a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.test.tsx @@ -3,7 +3,7 @@ import type { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { findHeadInCache } from './find-head-in-cache' describe('findHeadInCache', () => { diff --git a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts index 08dcefc65f2ce..f4d5e768b9808 100644 --- a/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts +++ b/packages/next/src/client/components/router-reducer/reducers/find-head-in-cache.ts @@ -1,5 +1,5 @@ import type { FlightRouterState } from '../../../../server/app-render/types' -import type { CacheNode } from '../../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../../shared/lib/app-router-context' import { createRouterCacheKey } from '../create-router-cache-key' export function findHeadInCache( diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx index 4ed01fed08c83..db40adfa3c5b1 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.test.tsx @@ -79,7 +79,7 @@ import { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { NavigateAction, @@ -106,6 +106,10 @@ const getInitialRouterStateTree = (): FlightRouterState => [ true, ] +const globalMutable = { + refresh: () => {}, +} + async function runPromiseThrowChain(fn: any): Promise { try { return await fn() @@ -194,7 +198,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => @@ -438,7 +442,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -633,7 +637,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -792,7 +796,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -948,7 +952,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1147,7 +1151,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1317,7 +1321,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1630,7 +1634,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => navigateReducer(state, action)) @@ -1841,6 +1845,7 @@ describe('navigateReducer', () => { hashFragment: '#hash', pendingPush: true, shouldScroll: true, + globalMutable, }, } @@ -1983,7 +1988,7 @@ describe('navigateReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => diff --git a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts index e47c42b2aa60a..fe8a4a24c4b8b 100644 --- a/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/navigate-reducer.ts @@ -1,7 +1,7 @@ import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import type { FlightRouterState, FlightSegmentPath, diff --git a/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx index bbbee6ff5f2a4..8055123367a94 100644 --- a/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/prefetch-reducer.test.tsx @@ -36,7 +36,7 @@ import { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { PrefetchAction, diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx index 9ed54e8994d2e..90ce7dc9423a3 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.test.tsx @@ -46,7 +46,7 @@ import { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { RefreshAction, ACTION_REFRESH } from '../router-reducer-types' import { refreshReducer } from './refresh-reducer' @@ -66,6 +66,10 @@ const getInitialRouterStateTree = (): FlightRouterState => [ true, ] +const globalMutable = { + refresh: () => {}, +} + async function runPromiseThrowChain(fn: any): Promise { try { return await fn() @@ -139,7 +143,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } @@ -300,7 +304,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } @@ -487,7 +491,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } @@ -723,7 +727,7 @@ describe('refreshReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, origin: new URL('/linking', 'https://localhost').origin, } diff --git a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts index bd6dfc4ef9047..cd87ef3802b00 100644 --- a/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/refresh-reducer.ts @@ -11,7 +11,7 @@ import { } from '../router-reducer-types' import { handleExternalUrl } from './navigate-reducer' import { handleMutable } from '../handle-mutable' -import { CacheStates } from '../../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates } from '../../../../shared/lib/app-router-context' import { fillLazyItemsTillLeafWithHead } from '../fill-lazy-items-till-leaf-with-head' export function refreshReducer( diff --git a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx index 36c978926517f..b11f39b141ccf 100644 --- a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.test.tsx @@ -3,7 +3,7 @@ import type { FlightRouterState } from '../../../../server/app-render/types' import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { RestoreAction, ACTION_RESTORE } from '../router-reducer-types' import { restoreReducer } from './restore-reducer' diff --git a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts index 0c6caaba746ca..3b8fa6acb4013 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts @@ -27,7 +27,7 @@ import { createHrefFromUrl } from '../create-href-from-url' import { handleExternalUrl } from './navigate-reducer' import { applyRouterStatePatchToTree } from '../apply-router-state-patch-to-tree' import { isNavigatingToNewRootLayout } from '../is-navigating-to-new-root-layout' -import { CacheStates } from '../../../../shared/lib/app-router-context.shared-runtime' +import { CacheStates } from '../../../../shared/lib/app-router-context' import { handleMutable } from '../handle-mutable' import { fillLazyItemsTillLeafWithHead } from '../fill-lazy-items-till-leaf-with-head' diff --git a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx index 0540c02079cb1..db72a92fce743 100644 --- a/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx +++ b/packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx @@ -7,6 +7,10 @@ import type { const buildId = 'development' +const globalMutable = { + refresh: () => {}, +} + jest.mock('../fetch-server-response', () => { const flightData: FlightData = [ [ @@ -41,7 +45,7 @@ jest.mock('../fetch-server-response', () => { import { CacheNode, CacheStates, -} from '../../../../shared/lib/app-router-context.shared-runtime' +} from '../../../../shared/lib/app-router-context' import { createInitialRouterState } from '../create-initial-router-state' import { ServerPatchAction, @@ -184,7 +188,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => @@ -375,7 +379,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } await runPromiseThrowChain(() => serverPatchReducer(state, action)) @@ -514,7 +518,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const state = createInitialRouterState({ @@ -556,7 +560,7 @@ describe('serverPatchReducer', () => { subTreeData: null, parallelRoutes: new Map(), }, - mutable: {}, + mutable: { globalMutable }, } const newState = await runPromiseThrowChain(() => diff --git a/packages/next/src/client/components/router-reducer/router-reducer-types.ts b/packages/next/src/client/components/router-reducer/router-reducer-types.ts index defbb657c7c42..284628dbf9098 100644 --- a/packages/next/src/client/components/router-reducer/router-reducer-types.ts +++ b/packages/next/src/client/components/router-reducer/router-reducer-types.ts @@ -1,4 +1,4 @@ -import type { CacheNode } from '../../../shared/lib/app-router-context.shared-runtime' +import type { CacheNode } from '../../../shared/lib/app-router-context' import type { FlightRouterState, FlightData, @@ -38,11 +38,15 @@ export interface Mutable { prefetchCache?: AppRouterState['prefetchCache'] hashFragment?: string shouldScroll?: boolean + globalMutable: { + pendingNavigatePath?: string + pendingMpaPath?: string + refresh: () => void + } } export interface ServerActionMutable extends Mutable { inFlightServerAction?: Promise | null - globalMutable: { pendingNavigatePath?: string; refresh: () => void } actionResultResolved?: boolean } diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.ts similarity index 100% rename from packages/next/src/client/components/static-generation-async-storage.external.ts rename to packages/next/src/client/components/static-generation-async-storage.ts diff --git a/packages/next/src/client/components/static-generation-bailout.ts b/packages/next/src/client/components/static-generation-bailout.ts index 4d35150664251..c5072218f035c 100644 --- a/packages/next/src/client/components/static-generation-bailout.ts +++ b/packages/next/src/client/components/static-generation-bailout.ts @@ -1,5 +1,5 @@ import { DynamicServerError } from './hooks-server-context' -import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' +import { staticGenerationAsyncStorage } from './static-generation-async-storage' class StaticGenBailoutError extends Error { code = 'NEXT_STATIC_GEN_BAILOUT' diff --git a/packages/next/src/client/image-component.tsx b/packages/next/src/client/image-component.tsx index 321b07ecd0a5f..3f2183c004b10 100644 --- a/packages/next/src/client/image-component.tsx +++ b/packages/next/src/client/image-component.tsx @@ -25,9 +25,9 @@ import type { ImageLoaderProps, } from '../shared/lib/image-config' import { imageConfigDefault } from '../shared/lib/image-config' -import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../shared/lib/image-config-context' import { warnOnce } from '../shared/lib/utils/warn-once' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' // @ts-ignore - This is replaced by webpack alias import defaultLoader from 'next/dist/shared/lib/image-loader' diff --git a/packages/next/src/client/index.tsx b/packages/next/src/client/index.tsx index 0f8a95c93746e..f7c163f020d31 100644 --- a/packages/next/src/client/index.tsx +++ b/packages/next/src/client/index.tsx @@ -10,16 +10,16 @@ import type { import React from 'react' import ReactDOM from 'react-dom/client' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' import mitt, { MittEmitter } from '../shared/lib/mitt' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' import { handleSmoothScroll } from '../shared/lib/router/utils/handle-smooth-scroll' import { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic' import { urlQueryToSearchParams, assign, } from '../shared/lib/router/utils/querystring' -import { setConfig } from '../shared/lib/runtime-config.shared-runtime' +import { setConfig } from '../shared/lib/runtime-config' import { getURL, loadGetInitialProps, @@ -34,17 +34,17 @@ import measureWebVitals from './performance-relayer' import { RouteAnnouncer } from './route-announcer' import { createRouter, makePublicRouterInstance } from './router' import { getProperError } from '../lib/is-error' -import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../shared/lib/image-config-context' import { ImageConfigComplete } from '../shared/lib/image-config' import { removeBasePath } from './remove-base-path' import { hasBasePath } from './has-base-path' -import { AppRouterContext } from '../shared/lib/app-router-context.shared-runtime' +import { AppRouterContext } from '../shared/lib/app-router-context' import { adaptForAppRouterInstance, adaptForSearchParams, PathnameContextProviderAdapter, -} from '../shared/lib/router/adapters.shared-runtime' -import { SearchParamsContext } from '../shared/lib/hooks-client-context.shared-runtime' +} from '../shared/lib/router/adapters' +import { SearchParamsContext } from '../shared/lib/hooks-client-context' import onRecoverableError from './on-recoverable-error' import tracer from './tracing/tracer' import reportToSocket from './tracing/report-to-socket' diff --git a/packages/next/src/client/legacy/image.tsx b/packages/next/src/client/legacy/image.tsx index 07ec2e217c200..d1456477bacf6 100644 --- a/packages/next/src/client/legacy/image.tsx +++ b/packages/next/src/client/legacy/image.tsx @@ -16,7 +16,7 @@ import { VALID_LOADERS, } from '../../shared/lib/image-config' import { useIntersection } from '../use-intersection' -import { ImageConfigContext } from '../../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../../shared/lib/image-config-context' import { warnOnce } from '../../shared/lib/utils/warn-once' import { normalizePathTrailingSlash } from '../normalize-trailing-slash' diff --git a/packages/next/src/client/link.tsx b/packages/next/src/client/link.tsx index 7a15dee249e26..94226c8caa5c0 100644 --- a/packages/next/src/client/link.tsx +++ b/packages/next/src/client/link.tsx @@ -12,12 +12,12 @@ import { isLocalURL } from '../shared/lib/router/utils/is-local-url' import { formatUrl } from '../shared/lib/router/utils/format-url' import { isAbsoluteUrl } from '../shared/lib/utils' import { addLocale } from './add-locale' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' import { AppRouterContext, AppRouterInstance, PrefetchOptions as AppRouterPrefetchOptions, -} from '../shared/lib/app-router-context.shared-runtime' +} from '../shared/lib/app-router-context' import { useIntersection } from './use-intersection' import { getDomainLocale } from './get-domain-locale' import { addBasePath } from './add-base-path' diff --git a/packages/next/src/client/router.ts b/packages/next/src/client/router.ts index f43126691e5e5..342ecb623df74 100644 --- a/packages/next/src/client/router.ts +++ b/packages/next/src/client/router.ts @@ -2,7 +2,7 @@ import React from 'react' import Router from '../shared/lib/router/router' import type { NextRouter } from '../shared/lib/router/router' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +import { RouterContext } from '../shared/lib/router-context' import isError from '../lib/is-error' type SingletonRouterBase = { diff --git a/packages/next/src/client/script.tsx b/packages/next/src/client/script.tsx index f695e691c482d..a4b2c6dcd3184 100644 --- a/packages/next/src/client/script.tsx +++ b/packages/next/src/client/script.tsx @@ -3,7 +3,7 @@ import ReactDOM from 'react-dom' import React, { useEffect, useContext, useRef } from 'react' import { ScriptHTMLAttributes } from 'react' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' +import { HeadManagerContext } from '../shared/lib/head-manager-context' import { DOMAttributeNames } from './head-manager' import { requestIdleCallback } from './request-idle-callback' diff --git a/packages/next/src/compiled/debug/index.js b/packages/next/src/compiled/debug/index.js index 0bdf3d36ef5d3..853a1a2db7873 100644 --- a/packages/next/src/compiled/debug/index.js +++ b/packages/next/src/compiled/debug/index.js @@ -1 +1 @@ -(()=>{var e={237:(e,t,r)=>{t.log=log;t.formatArgs=formatArgs;t.save=save;t.load=load;t.useColors=useColors;t.storage=localstorage();t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window!=="undefined"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)){return true}if(typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)){return false}return typeof document!=="undefined"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window!=="undefined"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(t){t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff);if(!this.useColors){return}const r="color: "+this.color;t.splice(1,0,r,"color: inherit");let s=0;let n=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{if(e==="%%"){return}s++;if(e==="%c"){n=s}}));t.splice(n,0,r)}function log(...e){return typeof console==="object"&&console.log&&console.log(...e)}function save(e){try{if(e){t.storage.setItem("debug",e)}else{t.storage.removeItem("debug")}}catch(e){}}function load(){let e;try{e=t.storage.getItem("debug")}catch(e){}if(!e&&typeof process!=="undefined"&&"env"in process){e=process.env.DEBUG}return e}function localstorage(){try{return localStorage}catch(e){}}e.exports=r(573)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},573:(e,t,r)=>{function setup(e){createDebug.debug=createDebug;createDebug.default=createDebug;createDebug.coerce=coerce;createDebug.disable=disable;createDebug.enable=enable;createDebug.enabled=enabled;createDebug.humanize=r(79);Object.keys(e).forEach((t=>{createDebug[t]=e[t]}));createDebug.instances=[];createDebug.names=[];createDebug.skips=[];createDebug.formatters={};function selectColor(e){let t=0;for(let r=0;r{if(t==="%%"){return t}o++;const n=createDebug.formatters[s];if(typeof n==="function"){const s=e[o];t=n.call(r,s);e.splice(o,1);o--}return t}));createDebug.formatArgs.call(r,e);const c=r.log||createDebug.log;c.apply(r,e)}debug.namespace=e;debug.enabled=createDebug.enabled(e);debug.useColors=createDebug.useColors();debug.color=selectColor(e);debug.destroy=destroy;debug.extend=extend;if(typeof createDebug.init==="function"){createDebug.init(debug)}createDebug.instances.push(debug);return debug}function destroy(){const e=createDebug.instances.indexOf(this);if(e!==-1){createDebug.instances.splice(e,1);return true}return false}function extend(e,t){const r=createDebug(this.namespace+(typeof t==="undefined"?":":t)+e);r.log=this.log;return r}function enable(e){createDebug.save(e);createDebug.names=[];createDebug.skips=[];let t;const r=(typeof e==="string"?e:"").split(/[\s,]+/);const s=r.length;for(t=0;t"-"+e))].join(",");createDebug.enable("");return e}function enabled(e){if(e[e.length-1]==="*"){return true}let t;let r;for(t=0,r=createDebug.skips.length;t{if(typeof process==="undefined"||process.type==="renderer"||process.browser===true||process.__nwjs){e.exports=r(237)}else{e.exports=r(354)}},354:(e,t,r)=>{const s=r(224);const n=r(837);t.init=init;t.log=log;t.formatArgs=formatArgs;t.save=save;t.load=load;t.useColors=useColors;t.colors=[6,2,3,4,5,1];try{const e=r(220);if(e&&(e.stderr||e).level>=2){t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221]}}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const r=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let s=process.env[t];if(/^(yes|on|true|enabled)$/i.test(s)){s=true}else if(/^(no|off|false|disabled)$/i.test(s)){s=false}else if(s==="null"){s=null}else{s=Number(s)}e[r]=s;return e}),{});function useColors(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):s.isatty(process.stderr.fd)}function formatArgs(t){const{namespace:r,useColors:s}=this;if(s){const s=this.color;const n="[3"+(s<8?s:"8;5;"+s);const o=` ${n};1m${r} `;t[0]=o+t[0].split("\n").join("\n"+o);t.push(n+"m+"+e.exports.humanize(this.diff)+"")}else{t[0]=getDate()+r+" "+t[0]}}function getDate(){if(t.inspectOpts.hideDate){return""}return(new Date).toISOString()+" "}function log(...e){return process.stderr.write(n.format(...e)+"\n")}function save(e){if(e){process.env.DEBUG=e}else{delete process.env.DEBUG}}function load(){return process.env.DEBUG}function init(e){e.inspectOpts={};const r=Object.keys(t.inspectOpts);for(let s=0;s{"use strict";e.exports=(e,t)=>{t=t||process.argv;const r=e.startsWith("-")?"":e.length===1?"-":"--";const s=t.indexOf(r+e);const n=t.indexOf("--");return s!==-1&&(n===-1?true:s{var t=1e3;var r=t*60;var s=r*60;var n=s*24;var o=n*7;var c=n*365.25;e.exports=function(e,t){t=t||{};var r=typeof e;if(r==="string"&&e.length>0){return parse(e)}else if(r==="number"&&isFinite(e)){return t.long?fmtLong(e):fmtShort(e)}throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function parse(e){e=String(e);if(e.length>100){return}var a=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!a){return}var u=parseFloat(a[1]);var i=(a[2]||"ms").toLowerCase();switch(i){case"years":case"year":case"yrs":case"yr":case"y":return u*c;case"weeks":case"week":case"w":return u*o;case"days":case"day":case"d":return u*n;case"hours":case"hour":case"hrs":case"hr":case"h":return u*s;case"minutes":case"minute":case"mins":case"min":case"m":return u*r;case"seconds":case"second":case"secs":case"sec":case"s":return u*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return u;default:return undefined}}function fmtShort(e){var o=Math.abs(e);if(o>=n){return Math.round(e/n)+"d"}if(o>=s){return Math.round(e/s)+"h"}if(o>=r){return Math.round(e/r)+"m"}if(o>=t){return Math.round(e/t)+"s"}return e+"ms"}function fmtLong(e){var o=Math.abs(e);if(o>=n){return plural(e,o,n,"day")}if(o>=s){return plural(e,o,s,"hour")}if(o>=r){return plural(e,o,r,"minute")}if(o>=t){return plural(e,o,t,"second")}return e+" ms"}function plural(e,t,r,s){var n=t>=r*1.5;return Math.round(e/r)+" "+s+(n?"s":"")}},220:(e,t,r)=>{"use strict";const s=r(37);const n=r(343);const o=process.env;let c;if(n("no-color")||n("no-colors")||n("color=false")){c=false}else if(n("color")||n("colors")||n("color=true")||n("color=always")){c=true}if("FORCE_COLOR"in o){c=o.FORCE_COLOR.length===0||parseInt(o.FORCE_COLOR,10)!==0}function translateLevel(e){if(e===0){return false}return{level:e,hasBasic:true,has256:e>=2,has16m:e>=3}}function supportsColor(e){if(c===false){return 0}if(n("color=16m")||n("color=full")||n("color=truecolor")){return 3}if(n("color=256")){return 2}if(e&&!e.isTTY&&c!==true){return 0}const t=c?1:0;if(process.platform==="win32"){const e=s.release().split(".");if(Number(process.versions.node.split(".")[0])>=8&&Number(e[0])>=10&&Number(e[2])>=10586){return Number(e[2])>=14931?3:2}return 1}if("CI"in o){if(["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some((e=>e in o))||o.CI_NAME==="codeship"){return 1}return t}if("TEAMCITY_VERSION"in o){return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(o.TEAMCITY_VERSION)?1:0}if(o.COLORTERM==="truecolor"){return 3}if("TERM_PROGRAM"in o){const e=parseInt((o.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(o.TERM_PROGRAM){case"iTerm.app":return e>=3?3:2;case"Apple_Terminal":return 2}}if(/-256(color)?$/i.test(o.TERM)){return 2}if(/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(o.TERM)){return 1}if("COLORTERM"in o){return 1}if(o.TERM==="dumb"){return t}return t}function getSupportLevel(e){const t=supportsColor(e);return translateLevel(t)}e.exports={supportsColor:getSupportLevel,stdout:getSupportLevel(process.stdout),stderr:getSupportLevel(process.stderr)}},37:e=>{"use strict";e.exports=require("os")},224:e=>{"use strict";e.exports=require("tty")},837:e=>{"use strict";e.exports=require("util")}};var t={};function __nccwpck_require__(r){var s=t[r];if(s!==undefined){return s.exports}var n=t[r]={exports:{}};var o=true;try{e[r](n,n.exports,__nccwpck_require__);o=false}finally{if(o)delete t[r]}return n.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(792);module.exports=r})(); \ No newline at end of file +(()=>{var e={237:(e,t,r)=>{t.log=log;t.formatArgs=formatArgs;t.save=save;t.load=load;t.useColors=useColors;t.storage=localstorage();t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"];function useColors(){if(typeof window!=="undefined"&&window.process&&(window.process.type==="renderer"||window.process.__nwjs)){return true}if(typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)){return false}return typeof document!=="undefined"&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||typeof window!=="undefined"&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||typeof navigator!=="undefined"&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/)}function formatArgs(t){t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff);if(!this.useColors){return}const r="color: "+this.color;t.splice(1,0,r,"color: inherit");let s=0;let n=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{if(e==="%%"){return}s++;if(e==="%c"){n=s}}));t.splice(n,0,r)}function log(...e){return typeof console==="object"&&console.log&&console.log(...e)}function save(e){try{if(e){t.storage.setItem("debug",e)}else{t.storage.removeItem("debug")}}catch(e){}}function load(){let e;try{e=t.storage.getItem("debug")}catch(e){}if(!e&&typeof process!=="undefined"&&"env"in process){e=process.env.DEBUG}return e}function localstorage(){try{return localStorage}catch(e){}}e.exports=r(573)(t);const{formatters:s}=e.exports;s.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},573:(e,t,r)=>{function setup(e){createDebug.debug=createDebug;createDebug.default=createDebug;createDebug.coerce=coerce;createDebug.disable=disable;createDebug.enable=enable;createDebug.enabled=enabled;createDebug.humanize=r(958);Object.keys(e).forEach((t=>{createDebug[t]=e[t]}));createDebug.instances=[];createDebug.names=[];createDebug.skips=[];createDebug.formatters={};function selectColor(e){let t=0;for(let r=0;r{if(t==="%%"){return t}o++;const n=createDebug.formatters[s];if(typeof n==="function"){const s=e[o];t=n.call(r,s);e.splice(o,1);o--}return t}));createDebug.formatArgs.call(r,e);const c=r.log||createDebug.log;c.apply(r,e)}debug.namespace=e;debug.enabled=createDebug.enabled(e);debug.useColors=createDebug.useColors();debug.color=selectColor(e);debug.destroy=destroy;debug.extend=extend;if(typeof createDebug.init==="function"){createDebug.init(debug)}createDebug.instances.push(debug);return debug}function destroy(){const e=createDebug.instances.indexOf(this);if(e!==-1){createDebug.instances.splice(e,1);return true}return false}function extend(e,t){const r=createDebug(this.namespace+(typeof t==="undefined"?":":t)+e);r.log=this.log;return r}function enable(e){createDebug.save(e);createDebug.names=[];createDebug.skips=[];let t;const r=(typeof e==="string"?e:"").split(/[\s,]+/);const s=r.length;for(t=0;t"-"+e))].join(",");createDebug.enable("");return e}function enabled(e){if(e[e.length-1]==="*"){return true}let t;let r;for(t=0,r=createDebug.skips.length;t{if(typeof process==="undefined"||process.type==="renderer"||process.browser===true||process.__nwjs){e.exports=r(237)}else{e.exports=r(354)}},354:(e,t,r)=>{const s=r(224);const n=r(837);t.init=init;t.log=log;t.formatArgs=formatArgs;t.save=save;t.load=load;t.useColors=useColors;t.colors=[6,2,3,4,5,1];try{const e=r(220);if(e&&(e.stderr||e).level>=2){t.colors=[20,21,26,27,32,33,38,39,40,41,42,43,44,45,56,57,62,63,68,69,74,75,76,77,78,79,80,81,92,93,98,99,112,113,128,129,134,135,148,149,160,161,162,163,164,165,166,167,168,169,170,171,172,173,178,179,184,185,196,197,198,199,200,201,202,203,204,205,206,207,208,209,214,215,220,221]}}catch(e){}t.inspectOpts=Object.keys(process.env).filter((e=>/^debug_/i.test(e))).reduce(((e,t)=>{const r=t.substring(6).toLowerCase().replace(/_([a-z])/g,((e,t)=>t.toUpperCase()));let s=process.env[t];if(/^(yes|on|true|enabled)$/i.test(s)){s=true}else if(/^(no|off|false|disabled)$/i.test(s)){s=false}else if(s==="null"){s=null}else{s=Number(s)}e[r]=s;return e}),{});function useColors(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):s.isatty(process.stderr.fd)}function formatArgs(t){const{namespace:r,useColors:s}=this;if(s){const s=this.color;const n="[3"+(s<8?s:"8;5;"+s);const o=` ${n};1m${r} `;t[0]=o+t[0].split("\n").join("\n"+o);t.push(n+"m+"+e.exports.humanize(this.diff)+"")}else{t[0]=getDate()+r+" "+t[0]}}function getDate(){if(t.inspectOpts.hideDate){return""}return(new Date).toISOString()+" "}function log(...e){return process.stderr.write(n.format(...e)+"\n")}function save(e){if(e){process.env.DEBUG=e}else{delete process.env.DEBUG}}function load(){return process.env.DEBUG}function init(e){e.inspectOpts={};const r=Object.keys(t.inspectOpts);for(let s=0;s{"use strict";e.exports=(e,t)=>{t=t||process.argv;const r=e.startsWith("-")?"":e.length===1?"-":"--";const s=t.indexOf(r+e);const n=t.indexOf("--");return s!==-1&&(n===-1?true:s{var t=1e3;var r=t*60;var s=r*60;var n=s*24;var o=n*7;var c=n*365.25;e.exports=function(e,t){t=t||{};var r=typeof e;if(r==="string"&&e.length>0){return parse(e)}else if(r==="number"&&isFinite(e)){return t.long?fmtLong(e):fmtShort(e)}throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))};function parse(e){e=String(e);if(e.length>100){return}var a=/^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec(e);if(!a){return}var u=parseFloat(a[1]);var i=(a[2]||"ms").toLowerCase();switch(i){case"years":case"year":case"yrs":case"yr":case"y":return u*c;case"weeks":case"week":case"w":return u*o;case"days":case"day":case"d":return u*n;case"hours":case"hour":case"hrs":case"hr":case"h":return u*s;case"minutes":case"minute":case"mins":case"min":case"m":return u*r;case"seconds":case"second":case"secs":case"sec":case"s":return u*t;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return u;default:return undefined}}function fmtShort(e){var o=Math.abs(e);if(o>=n){return Math.round(e/n)+"d"}if(o>=s){return Math.round(e/s)+"h"}if(o>=r){return Math.round(e/r)+"m"}if(o>=t){return Math.round(e/t)+"s"}return e+"ms"}function fmtLong(e){var o=Math.abs(e);if(o>=n){return plural(e,o,n,"day")}if(o>=s){return plural(e,o,s,"hour")}if(o>=r){return plural(e,o,r,"minute")}if(o>=t){return plural(e,o,t,"second")}return e+" ms"}function plural(e,t,r,s){var n=t>=r*1.5;return Math.round(e/r)+" "+s+(n?"s":"")}},220:(e,t,r)=>{"use strict";const s=r(37);const n=r(343);const o=process.env;let c;if(n("no-color")||n("no-colors")||n("color=false")){c=false}else if(n("color")||n("colors")||n("color=true")||n("color=always")){c=true}if("FORCE_COLOR"in o){c=o.FORCE_COLOR.length===0||parseInt(o.FORCE_COLOR,10)!==0}function translateLevel(e){if(e===0){return false}return{level:e,hasBasic:true,has256:e>=2,has16m:e>=3}}function supportsColor(e){if(c===false){return 0}if(n("color=16m")||n("color=full")||n("color=truecolor")){return 3}if(n("color=256")){return 2}if(e&&!e.isTTY&&c!==true){return 0}const t=c?1:0;if(process.platform==="win32"){const e=s.release().split(".");if(Number(process.versions.node.split(".")[0])>=8&&Number(e[0])>=10&&Number(e[2])>=10586){return Number(e[2])>=14931?3:2}return 1}if("CI"in o){if(["TRAVIS","CIRCLECI","APPVEYOR","GITLAB_CI"].some((e=>e in o))||o.CI_NAME==="codeship"){return 1}return t}if("TEAMCITY_VERSION"in o){return/^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(o.TEAMCITY_VERSION)?1:0}if(o.COLORTERM==="truecolor"){return 3}if("TERM_PROGRAM"in o){const e=parseInt((o.TERM_PROGRAM_VERSION||"").split(".")[0],10);switch(o.TERM_PROGRAM){case"iTerm.app":return e>=3?3:2;case"Apple_Terminal":return 2}}if(/-256(color)?$/i.test(o.TERM)){return 2}if(/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(o.TERM)){return 1}if("COLORTERM"in o){return 1}if(o.TERM==="dumb"){return t}return t}function getSupportLevel(e){const t=supportsColor(e);return translateLevel(t)}e.exports={supportsColor:getSupportLevel,stdout:getSupportLevel(process.stdout),stderr:getSupportLevel(process.stderr)}},37:e=>{"use strict";e.exports=require("os")},224:e=>{"use strict";e.exports=require("tty")},837:e=>{"use strict";e.exports=require("util")}};var t={};function __nccwpck_require__(r){var s=t[r];if(s!==undefined){return s.exports}var n=t[r]={exports:{}};var o=true;try{e[r](n,n.exports,__nccwpck_require__);o=false}finally{if(o)delete t[r]}return n.exports}if(typeof __nccwpck_require__!=="undefined")__nccwpck_require__.ab=__dirname+"/";var r=__nccwpck_require__(792);module.exports=r})(); \ No newline at end of file diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index b9fb7b9afd60a..31f58755996a4 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -59,7 +59,7 @@ import { RSC, } from '../client/components/app-router-headers' -const envConfig = require('../shared/lib/runtime-config.shared-runtime') +const envConfig = require('../shared/lib/runtime-config') ;(globalThis as any).__NEXT_DATA__ = { nextExport: true, @@ -307,10 +307,8 @@ export default async function exportPage({ await promises.mkdir(baseDir, { recursive: true }) let renderResult: RenderResult | undefined let curRenderOpts: RenderOpts = {} - const renderToHTML = - require('../server/future/route-modules/pages/module.compiled') - .renderToHTML as typeof import('../server/render').renderToHTML - + const { renderToHTML } = + require('../server/render') as typeof import('../server/render') let renderMethod = renderToHTML let inAmpMode = false, hybridAmp = false @@ -481,6 +479,7 @@ export default async function exportPage({ const module = await RouteModuleLoader.load( filename ) + // Call the handler with the request and context from the module. const response = await module.handle(request, context) @@ -536,9 +535,8 @@ export default async function exportPage({ results.fromBuildExportRevalidate = 0 } } else { - const renderToHTMLOrFlight = - require('../server/future/route-modules/app-page/module.compiled') - .renderToHTMLOrFlight as typeof import('../server/app-render/app-render').renderToHTMLOrFlight + const { renderToHTMLOrFlight } = + require('../server/app-render/app-render') as typeof import('../server/app-render/app-render') try { curRenderOpts.params ||= {} diff --git a/packages/next/src/lib/chalk.ts b/packages/next/src/lib/chalk.ts index d0939d9148b97..8e40472953f8f 100644 --- a/packages/next/src/lib/chalk.ts +++ b/packages/next/src/lib/chalk.ts @@ -1,6 +1,6 @@ let chalk: typeof import('next/dist/compiled/chalk') -if (process.env.NEXT_RUNTIME === 'edge' || process.env.NEXT_MINIMAL) { +if (process.env.NEXT_RUNTIME === 'edge') { chalk = require('./web/chalk').default } else { chalk = require('next/dist/compiled/chalk') diff --git a/packages/next/src/lib/constants.ts b/packages/next/src/lib/constants.ts index 46f85311a9f0a..fc94397c6aca7 100644 --- a/packages/next/src/lib/constants.ts +++ b/packages/next/src/lib/constants.ts @@ -132,10 +132,6 @@ const WEBPACK_LAYERS_NAMES = { * The server bundle layer for metadata routes. */ appMetadataRoute: 'app-metadata-route', - /** - * The layer for the server bundle for App Route handlers. - */ - appRouteHandler: 'app-route-handler', } export const WEBPACK_LAYERS = { @@ -145,7 +141,6 @@ export const WEBPACK_LAYERS = { WEBPACK_LAYERS_NAMES.reactServerComponents, WEBPACK_LAYERS_NAMES.actionBrowser, WEBPACK_LAYERS_NAMES.appMetadataRoute, - WEBPACK_LAYERS_NAMES.appRouteHandler, ], }, } diff --git a/packages/next/src/pages/_document.tsx b/packages/next/src/pages/_document.tsx index f0a29cb15d1fc..a8526011c5d33 100644 --- a/packages/next/src/pages/_document.tsx +++ b/packages/next/src/pages/_document.tsx @@ -17,11 +17,8 @@ import { BuildManifest, getPageFiles } from '../server/get-page-files' import { htmlEscapeJsonString } from '../server/htmlescape' import isError from '../lib/is-error' -import { - HtmlContext, - useHtmlContext, -} from '../shared/lib/html-context.shared-runtime' -import type { HtmlProps } from '../shared/lib/html-context.shared-runtime' +import { HtmlContext, useHtmlContext } from '../shared/lib/html-context' +import type { HtmlProps } from '../shared/lib/html-context' export { DocumentContext, DocumentInitialProps, DocumentProps } diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 9f6059ec48f5a..6b8bc3228a005 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -19,10 +19,10 @@ import { isRedirectError, } from '../../client/components/redirect' import RenderResult from '../render-result' -import { StaticGenerationStore } from '../../client/components/static-generation-async-storage.external' +import { StaticGenerationStore } from '../../client/components/static-generation-async-storage' import { FlightRenderResult } from './flight-render-result' import { ActionResult } from './types' -import { ActionAsyncStorage } from '../../client/components/action-async-storage.external' +import { ActionAsyncStorage } from '../../client/components/action-async-storage' import { filterReqHeaders, actionsForbiddenHeaders, @@ -31,8 +31,7 @@ import { appendMutableCookies, getModifiedCookieValues, } from '../web/spec-extension/adapters/request-cookies' - -import { RequestStore } from '../../client/components/request-async-storage.external' +import { RequestStore } from '../../client/components/request-async-storage' import { NEXT_CACHE_REVALIDATED_TAGS_HEADER, NEXT_CACHE_REVALIDATE_TAG_TOKEN_HEADER, diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 1dd2eb8f7c639..30749ac66a83d 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -11,9 +11,9 @@ import type { Segment, } from './types' -import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' +import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' import type { StaticGenerationBailout } from '../../client/components/static-generation-bailout' -import type { RequestAsyncStorage } from '../../client/components/request-async-storage.external' +import type { RequestAsyncStorage } from '../../client/components/request-async-storage' import React from 'react' import { createServerComponentRenderer } from './create-server-components-renderer' @@ -286,13 +286,10 @@ export async function renderToHTMLOrFlight( * that we need to resolve the final metadata. */ - let requestId: string - - if (process.env.NEXT_RUNTIME === 'edge') { - requestId = crypto.randomUUID() - } else { - requestId = require('next/dist/compiled/nanoid').nanoid() - } + const requestId = + process.env.NEXT_RUNTIME === 'edge' + ? crypto.randomUUID() + : require('next/dist/compiled/nanoid').nanoid() const LayoutRouter = ComponentMod.LayoutRouter as typeof import('../../client/components/layout-router').default @@ -1395,7 +1392,7 @@ export async function renderToHTMLOrFlight( ) const { HeadManagerContext } = - require('../../shared/lib/head-manager-context.shared-runtime') as typeof import('../../shared/lib/head-manager-context.shared-runtime') + require('../../shared/lib/head-manager-context') as typeof import('../../shared/lib/head-manager-context') // On each render, create a new `ServerInsertedHTML` context to capture // injected nodes from user code (`useServerInsertedHTML`). diff --git a/packages/next/src/server/app-render/entry-base.ts b/packages/next/src/server/app-render/entry-base.ts index 0cc53e0214d86..6bc5fd7e7ace1 100644 --- a/packages/next/src/server/app-render/entry-base.ts +++ b/packages/next/src/server/app-render/entry-base.ts @@ -1,26 +1,36 @@ +const { default: AppRouter } = + require('next/dist/client/components/app-router') as typeof import('../../client/components/app-router') +const { default: LayoutRouter } = + require('next/dist/client/components/layout-router') as typeof import('../../client/components/layout-router') +const { default: RenderFromTemplateContext } = + require('next/dist/client/components/render-from-template-context') as typeof import('../../client/components/render-from-template-context') + +const { staticGenerationAsyncStorage } = + require('next/dist/client/components/static-generation-async-storage') as typeof import('../../client/components/static-generation-async-storage') + +const { requestAsyncStorage } = + require('next/dist/client/components/request-async-storage') as typeof import('../../client/components/request-async-storage') +const { actionAsyncStorage } = + require('next/dist/client/components/action-async-storage') as typeof import('../../client/components/action-async-storage') + +const { staticGenerationBailout } = + require('next/dist/client/components/static-generation-bailout') as typeof import('../../client/components/static-generation-bailout') +const { default: StaticGenerationSearchParamsBailoutProvider } = + require('next/dist/client/components/static-generation-searchparams-bailout-provider') as typeof import('../../client/components/static-generation-searchparams-bailout-provider') +const { createSearchParamsBailoutProxy } = + require('next/dist/client/components/searchparams-bailout-proxy') as typeof import('../../client/components/searchparams-bailout-proxy') + +const serverHooks = + require('next/dist/client/components/hooks-server-context') as typeof import('../../client/components/hooks-server-context') + const { renderToReadableStream, decodeReply, decodeAction, // eslint-disable-next-line import/no-extraneous-dependencies } = require('react-server-dom-webpack/server.edge') - -import AppRouter from '../../client/components/app-router' -import LayoutRouter from '../../client/components/layout-router' -import RenderFromTemplateContext from '../../client/components/render-from-template-context' -import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' -import { requestAsyncStorage } from '../../client/components/request-async-storage.external' -import { actionAsyncStorage } from '../../client/components/action-async-storage.external' -import { staticGenerationBailout } from '../../client/components/static-generation-bailout' -import StaticGenerationSearchParamsBailoutProvider from '../../client/components/static-generation-searchparams-bailout-provider' -import { createSearchParamsBailoutProxy } from '../../client/components/searchparams-bailout-proxy' -import * as serverHooks from '../../client/components/hooks-server-context' - -import { - preloadStyle, - preloadFont, - preconnect, -} from '../../server/app-render/rsc/preloads' +const { preloadStyle, preloadFont, preconnect } = + require('next/dist/server/app-render/rsc/preloads') as typeof import('../../server/app-render/rsc/preloads') const { NotFoundBoundary } = require('next/dist/client/components/not-found-boundary') as typeof import('../../client/components/not-found-boundary') diff --git a/packages/next/src/server/app-render/server-inserted-html.tsx b/packages/next/src/server/app-render/server-inserted-html.tsx index 764dc62792077..f044c24feaba3 100644 --- a/packages/next/src/server/app-render/server-inserted-html.tsx +++ b/packages/next/src/server/app-render/server-inserted-html.tsx @@ -2,7 +2,7 @@ // elements into the HTML stream. import React from 'react' -import { ServerInsertedHTMLContext } from '../../shared/lib/server-inserted-html.shared-runtime' +import { ServerInsertedHTMLContext } from '../../shared/lib/server-inserted-html' export function createServerInsertedHTML() { const serverInsertedHTMLCallbacks: (() => React.ReactNode)[] = [] diff --git a/packages/next/src/server/async-storage/request-async-storage-wrapper.ts b/packages/next/src/server/async-storage/request-async-storage-wrapper.ts index 1376ecfb197cd..50795855c53d4 100644 --- a/packages/next/src/server/async-storage/request-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/request-async-storage-wrapper.ts @@ -1,7 +1,7 @@ import type { BaseNextRequest, BaseNextResponse } from '../base-http' import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'http' import type { AsyncLocalStorage } from 'async_hooks' -import type { RequestStore } from '../../client/components/request-async-storage.external' +import type { RequestStore } from '../../client/components/request-async-storage' import type { RenderOpts } from '../app-render/types' import type { AsyncStorageWrapper } from './async-storage-wrapper' import type { NextRequest } from '../web/spec-extension/request' diff --git a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts index d5adfc9de38b4..a28ac0e8ecb2a 100644 --- a/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts +++ b/packages/next/src/server/async-storage/static-generation-async-storage-wrapper.ts @@ -1,5 +1,5 @@ import type { AsyncStorageWrapper } from './async-storage-wrapper' -import type { StaticGenerationStore } from '../../client/components/static-generation-async-storage.external' +import type { StaticGenerationStore } from '../../client/components/static-generation-async-storage' import type { AsyncLocalStorage } from 'async_hooks' import type { IncrementalCache } from '../lib/incremental-cache' diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index fab999db35ddc..bacb1cc38e4ff 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -55,7 +55,7 @@ import { getCookieParser, checkIsOnDemandRevalidate, } from './api-utils' -import { setConfig } from '../shared/lib/runtime-config.shared-runtime' +import { setConfig } from '../shared/lib/runtime-config' import { setRevalidateHeaders } from './send-payload/revalidate-headers' import { execOnce } from '../shared/lib/utils' @@ -124,6 +124,7 @@ import { } from './web/spec-extension/adapters/next-request' import { matchNextDataPathname } from './lib/match-next-data-pathname' import getRouteFromAssetPath from '../shared/lib/router/utils/get-route-from-asset-path' +import { stripInternalHeaders } from './internal-utils' export type FindComponentsResult = { components: LoadComponentsReturnType @@ -427,11 +428,7 @@ export default abstract class Server { } = this.nextConfig this.buildId = this.getBuildId() - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - const minimalModeKey = 'minimalMode' - this[minimalModeKey] = - minimalMode || !!process.env.NEXT_PRIVATE_MINIMAL_MODE + this.minimalMode = minimalMode || !!process.env.NEXT_PRIVATE_MINIMAL_MODE this.hasAppDir = this.getHasAppDir(dev) const serverComponents = this.hasAppDir @@ -1542,6 +1539,28 @@ export default abstract class Server { ) } + protected stripInternalHeaders(req: BaseNextRequest): void { + // Skip stripping internal headers in test mode while the header stripping + // has been explicitly disabled. This allows tests to verify internal + // routing behavior. + if ( + process.env.__NEXT_TEST_MODE && + process.env.__NEXT_NO_STRIP_INTERNAL_HEADERS === '1' + ) { + return + } + + // Strip the internal headers from both the request and the original + // request. + stripInternalHeaders(req.headers) + if ( + 'originalRequest' in req && + 'headers' in (req as NodeNextRequest).originalRequest + ) { + stripInternalHeaders((req as NodeNextRequest).originalRequest.headers) + } + } + private async renderToResponseWithComponentsImpl( { req, res, pathname, renderOpts: opts }: RequestContext, { components, query }: FindComponentsResult @@ -1550,6 +1569,10 @@ export default abstract class Server { // For edge runtime 404 page, /_not-found needs to be treated as 404 page (process.env.NEXT_RUNTIME === 'edge' && pathname === '/_not-found') || pathname === '/404' + + // Strip the internal headers. + this.stripInternalHeaders(req) + const is500Page = pathname === '/500' const isAppPath = components.isAppPath const hasServerProps = !!components.getServerSideProps diff --git a/packages/next/src/server/dev/next-dev-server.ts b/packages/next/src/server/dev/next-dev-server.ts index 839fa1b13c0e4..1eca11b7358cb 100644 --- a/packages/next/src/server/dev/next-dev-server.ts +++ b/packages/next/src/server/dev/next-dev-server.ts @@ -41,7 +41,7 @@ import { UnwrapPromise, withCoalescedInvoke, } from '../../lib/coalesced-function' -import { loadDefaultErrorComponents } from '../load-default-error-components' +import { loadDefaultErrorComponents } from '../load-components' import { DecodeError, MiddlewareNotFoundError } from '../../shared/lib/utils' import * as Log from '../../build/output/log' import isError, { getProperError } from '../../lib/is-error' diff --git a/packages/next/src/server/dev/static-paths-worker.ts b/packages/next/src/server/dev/static-paths-worker.ts index ddd6526e52f23..68932df7a36b0 100644 --- a/packages/next/src/server/dev/static-paths-worker.ts +++ b/packages/next/src/server/dev/static-paths-worker.ts @@ -14,10 +14,8 @@ import { loadComponents } from '../load-components' import { setHttpClientAndAgentOptions } from '../setup-http-agent-env' import { IncrementalCache } from '../lib/incremental-cache' import * as serverHooks from '../../client/components/hooks-server-context' -import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' - -const { AppRouteRouteModule } = - require('../future/route-modules/app-route/module.compiled') as typeof import('../future/route-modules/app-route/module') +import { staticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' +import { AppRouteRouteModule } from '../future/route-modules/app-route/module' type RuntimeConfig = any @@ -58,7 +56,7 @@ export async function loadStaticPaths({ fallback?: boolean | 'blocking' }> { // update work memory runtime-config - require('../../shared/lib/runtime-config.shared-runtime').setConfig(config) + require('../../shared/lib/runtime-config').setConfig(config) setHttpClientAndAgentOptions({ httpAgentOptions, }) diff --git a/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts b/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts index 6f70685df7e75..3283eb00a53f5 100644 --- a/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts +++ b/packages/next/src/server/future/helpers/module-loader/node-module-loader.ts @@ -7,10 +7,7 @@ export class NodeModuleLoader implements ModuleLoader { public async load(id: string): Promise { if (process.env.NEXT_RUNTIME !== 'edge') { // Need to `await` to cover the case that route is marked ESM modules by ESM escalation. - return await (process.env.NEXT_MINIMAL - ? // @ts-ignore - __non_webpack_require__(id) - : require(id)) + return await require(id) } throw new Error('NodeModuleLoader is not supported in edge runtime.') diff --git a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts b/packages/next/src/server/future/route-modules/app-page/module.compiled.ts deleted file mode 100644 index 78601739acbe5..0000000000000 --- a/packages/next/src/server/future/route-modules/app-page/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/app-page/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/app-page.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/app-page-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/app-page.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/app-page/module.ts b/packages/next/src/server/future/route-modules/app-page/module.ts index daa0291a1c8b4..418e37420d7e9 100644 --- a/packages/next/src/server/future/route-modules/app-page/module.ts +++ b/packages/next/src/server/future/route-modules/app-page/module.ts @@ -11,7 +11,6 @@ import { type RouteModuleOptions, type RouteModuleHandleContext, } from '../route-module' -import * as sharedModules from './shared-modules' type AppPageUserlandModule = { /** @@ -35,8 +34,6 @@ export class AppPageRouteModule extends RouteModule< AppPageRouteDefinition, AppPageUserlandModule > { - static readonly sharedModules = sharedModules - public render( req: IncomingMessage, res: ServerResponse, @@ -52,6 +49,4 @@ export class AppPageRouteModule extends RouteModule< } } -export { renderToHTMLOrFlight } - export default AppPageRouteModule diff --git a/packages/next/src/server/future/route-modules/app-page/shared-modules.ts b/packages/next/src/server/future/route-modules/app-page/shared-modules.ts deleted file mode 100644 index e986c1bad3894..0000000000000 --- a/packages/next/src/server/future/route-modules/app-page/shared-modules.ts +++ /dev/null @@ -1,13 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -export * as headManagerContext from '../../../../shared/lib/head-manager-context.shared-runtime' -export * as serverInsertedHtml from '../../../../shared/lib/server-inserted-html.shared-runtime' -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' -export * as hooksClientContext from '../../../../shared/lib/hooks-client-context.shared-runtime' -export * as routerContext from '../../../../shared/lib/router-context.shared-runtime' -export * as htmlContext from '../../../../shared/lib/html-context.shared-runtime' -export * as ampContext from '../../../../shared/lib/amp-context.shared-runtime' -export * as adapters from '../../../../shared/lib/router/adapters.shared-runtime' -export * as loadableContext from '../../../../shared/lib/loadable-context.shared-runtime' -export * as imageConfigContext from '../../../../shared/lib/image-config-context.shared-runtime' -export * as runtimeConfig from '../../../../shared/lib/runtime-config.shared-runtime' -export * as loadable from '../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/app-route/module.compiled.ts b/packages/next/src/server/future/route-modules/app-route/module.compiled.ts deleted file mode 100644 index f5909104bc772..0000000000000 --- a/packages/next/src/server/future/route-modules/app-route/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/app-route/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/app-route.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/app-route-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/app-route.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/app-route/module.ts b/packages/next/src/server/future/route-modules/app-route/module.ts index d1d36d31501e4..bf47738d35fea 100644 --- a/packages/next/src/server/future/route-modules/app-route/module.ts +++ b/packages/next/src/server/future/route-modules/app-route/module.ts @@ -35,14 +35,22 @@ import { appendMutableCookies } from '../../../web/spec-extension/adapters/reque import { RouteKind } from '../../route-kind' import { parsedUrlQueryToParams } from './helpers/parsed-url-query-to-params' -import * as serverHooks from '../../../../client/components/hooks-server-context' -import * as headerHooks from '../../../../client/components/headers' -import { staticGenerationBailout } from '../../../../client/components/static-generation-bailout' - -import { requestAsyncStorage } from '../../../../client/components/request-async-storage.external' -import { staticGenerationAsyncStorage } from '../../../../client/components/static-generation-async-storage.external' -import { actionAsyncStorage } from '../../../../client/components/action-async-storage.external' -import * as sharedModules from './shared-modules' +// These are imported weirdly like this because of the way that the bundling +// works. We need to import the built files from the dist directory, but we +// can't do that directly because we need types from the source files. So we +// import the types from the source files and then import the built files. +const { requestAsyncStorage } = + require('next/dist/client/components/request-async-storage') as typeof import('../../../../client/components/request-async-storage') +const { staticGenerationAsyncStorage } = + require('next/dist/client/components/static-generation-async-storage') as typeof import('../../../../client/components/static-generation-async-storage') +const serverHooks = + require('next/dist/client/components/hooks-server-context') as typeof import('../../../../client/components/hooks-server-context') +const headerHooks = + require('next/dist/client/components/headers') as typeof import('../../../../client/components/headers') +const { staticGenerationBailout } = + require('next/dist/client/components/static-generation-bailout') as typeof import('../../../../client/components/static-generation-bailout') +const { actionAsyncStorage } = + require('next/dist/client/components/action-async-storage') as typeof import('../../../../client/components/action-async-storage') /** * AppRouteRouteHandlerContext is the context that is passed to the route @@ -139,8 +147,6 @@ export class AppRouteRouteModule extends RouteModule< */ public readonly staticGenerationBailout = staticGenerationBailout - public static readonly sharedModules = sharedModules - /** * A reference to the mutation related async storage, such as mutations of * cookies. diff --git a/packages/next/src/server/future/route-modules/app-route/shared-modules.ts b/packages/next/src/server/future/route-modules/app-route/shared-modules.ts deleted file mode 100644 index e6139d5a69404..0000000000000 --- a/packages/next/src/server/future/route-modules/app-route/shared-modules.ts +++ /dev/null @@ -1,3 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -// TODO: remove this. We need it because using notFound from next/navigation imports this file :( -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts b/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts deleted file mode 100644 index ed74c41adb918..0000000000000 --- a/packages/next/src/server/future/route-modules/pages-api/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/pages-api/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/pages-api.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/pages-api-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/pages-api.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/pages-api/module.ts b/packages/next/src/server/future/route-modules/pages-api/module.ts index 976daeeec4a87..88dbda73b464c 100644 --- a/packages/next/src/server/future/route-modules/pages-api/module.ts +++ b/packages/next/src/server/future/route-modules/pages-api/module.ts @@ -100,16 +100,6 @@ export class PagesAPIRouteModule extends RouteModule< PagesAPIRouteDefinition, PagesAPIUserlandModule > { - constructor(options: PagesAPIRouteModuleOptions) { - super(options) - - if (typeof options.userland.default !== 'function') { - throw new Error( - `Page ${options.definition.page} does not export a default function.` - ) - } - } - /** * * @param req the incoming server request diff --git a/packages/next/src/server/future/route-modules/pages/module.compiled.ts b/packages/next/src/server/future/route-modules/pages/module.compiled.ts deleted file mode 100644 index a935b62abdcad..0000000000000 --- a/packages/next/src/server/future/route-modules/pages/module.compiled.ts +++ /dev/null @@ -1,11 +0,0 @@ -if (process.env.NEXT_RUNTIME === 'edge') { - module.exports = require('next/dist/server/future/route-modules/pages/module.js') -} else { - if (process.env.NODE_ENV === 'development') { - module.exports = require('next/dist/compiled/next-server/pages.runtime.dev.js') - } else if (process.env.TURBOPACK) { - module.exports = require('next/dist/compiled/next-server/pages-turbo.runtime.prod.js') - } else { - module.exports = require('next/dist/compiled/next-server/pages.runtime.prod.js') - } -} diff --git a/packages/next/src/server/future/route-modules/pages/module.ts b/packages/next/src/server/future/route-modules/pages/module.ts index e2730ef668901..dac8ae5546441 100644 --- a/packages/next/src/server/future/route-modules/pages/module.ts +++ b/packages/next/src/server/future/route-modules/pages/module.ts @@ -17,8 +17,7 @@ import { type RouteModuleHandleContext, type RouteModuleOptions, } from '../route-module' -import { renderToHTMLImpl, renderToHTML } from '../../../render' -import * as sharedModules from './shared-modules' +import { renderToHTMLImpl } from '../../../render' /** * The userland module for a page. This is the module that is exported from the @@ -105,8 +104,6 @@ export class PagesRouteModule extends RouteModule< > { private readonly components: PagesComponents - static readonly sharedModules = sharedModules - constructor(options: PagesRouteModuleOptions) { super(options) @@ -132,7 +129,4 @@ export class PagesRouteModule extends RouteModule< } } -// needed for the static build -export { renderToHTML } - export default PagesRouteModule diff --git a/packages/next/src/server/future/route-modules/pages/shared-modules.ts b/packages/next/src/server/future/route-modules/pages/shared-modules.ts deleted file mode 100644 index 55cdfbdeca37c..0000000000000 --- a/packages/next/src/server/future/route-modules/pages/shared-modules.ts +++ /dev/null @@ -1,12 +0,0 @@ -// the name of the export has to be the camelCase version of the file name (without the extension) -export * as htmlContext from '../../../../shared/lib/html-context.shared-runtime' -export * as routerContext from '../../../../shared/lib/router-context.shared-runtime' -export * as ampContext from '../../../../shared/lib/amp-context.shared-runtime' -export * as headManagerContext from '../../../../shared/lib/head-manager-context.shared-runtime' -export * as adapters from '../../../../shared/lib/router/adapters.shared-runtime' -export * as loadableContext from '../../../../shared/lib/loadable-context.shared-runtime' -export * as appRouterContext from '../../../../shared/lib/app-router-context.shared-runtime' -export * as hooksClientContext from '../../../../shared/lib/hooks-client-context.shared-runtime' -export * as imageConfigContext from '../../../../shared/lib/image-config-context.shared-runtime' -export * as runtimeConfig from '../../../../shared/lib/runtime-config.shared-runtime' -export * as loadable from '../../../../shared/lib/loadable.shared-runtime' diff --git a/packages/next/src/server/future/route-modules/route-module.ts b/packages/next/src/server/future/route-modules/route-module.ts index a8e5dd6c5945a..52188ed506dff 100644 --- a/packages/next/src/server/future/route-modules/route-module.ts +++ b/packages/next/src/server/future/route-modules/route-module.ts @@ -44,11 +44,6 @@ export abstract class RouteModule< */ public readonly definition: Readonly - /** - * The shared modules that are exposed and required for the route module. - */ - public static readonly sharedModules: any - constructor({ userland, definition }: RouteModuleOptions) { this.userland = userland this.definition = definition diff --git a/packages/next/src/server/internal-utils.ts b/packages/next/src/server/internal-utils.ts index 1ae559ea09db8..1e712b16379a4 100644 --- a/packages/next/src/server/internal-utils.ts +++ b/packages/next/src/server/internal-utils.ts @@ -1,6 +1,8 @@ -import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers' +import type { IncomingHttpHeaders } from 'http' import type { NextParsedUrlQuery } from './request-meta' +import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers' + const INTERNAL_QUERY_NAMES = [ '__nextFallback', '__nextLocale', @@ -36,3 +38,27 @@ export function stripInternalSearchParams( return (isStringUrl ? instance.toString() : instance) as T } + +/** + * Headers that are set by the Next.js server and should be stripped from the + * request headers going to the user's application. + */ +const INTERNAL_HEADERS = [ + 'x-invoke-path', + 'x-invoke-status', + 'x-invoke-error', + 'x-invoke-query', + 'x-invoke-output', + 'x-middleware-invoke', +] as const + +/** + * Strip internal headers from the request headers. + * + * @param headers the headers to strip of internal headers + */ +export function stripInternalHeaders(headers: IncomingHttpHeaders) { + for (const key of INTERNAL_HEADERS) { + delete headers[key] + } +} diff --git a/packages/next/src/server/lib/incremental-cache/index.ts b/packages/next/src/server/lib/incremental-cache/index.ts index 3032aa685300b..ae2b11b4dc00f 100644 --- a/packages/next/src/server/lib/incremental-cache/index.ts +++ b/packages/next/src/server/lib/incremental-cache/index.ts @@ -131,10 +131,7 @@ export class IncrementalCache { maxMemoryCacheSize = parseInt(process.env.__NEXT_TEST_MAX_ISR_CACHE, 10) } this.dev = dev - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - const minimalModeKey = 'minimalMode' - this[minimalModeKey] = minimalMode + this.minimalMode = minimalMode this.requestHeaders = requestHeaders this.requestProtocol = requestProtocol this.allowedRevalidateHeaderKeys = allowedRevalidateHeaderKeys diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 080361704b718..fb4d02c97b251 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -1,4 +1,4 @@ -import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage.external' +import type { StaticGenerationAsyncStorage } from '../../client/components/static-generation-async-storage' import type * as ServerHooks from '../../client/components/hooks-server-context' import { AppRenderSpan, NextNodeServerSpan } from './trace/constants' diff --git a/packages/next/src/server/lib/router-utils/filesystem.ts b/packages/next/src/server/lib/router-utils/filesystem.ts index d442b87fff858..270580f1f81a7 100644 --- a/packages/next/src/server/lib/router-utils/filesystem.ts +++ b/packages/next/src/server/lib/router-utils/filesystem.ts @@ -249,7 +249,7 @@ export async function setupFsCheck(opts: { ? new RegExp( route.dataRouteRegex.replace( `/${escapedBuildId}/`, - `/${escapedBuildId}/(?.+?)/` + `/${escapedBuildId}/(?[^/]+?)/` ) ) : new RegExp(route.dataRouteRegex), diff --git a/packages/next/src/server/lib/router-utils/setup-dev.ts b/packages/next/src/server/lib/router-utils/setup-dev.ts index 2faaf385fa393..cf17fb2d7d9e6 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev.ts @@ -1784,7 +1784,7 @@ async function startWatcher(opts: SetupOpts) { ? new RegExp( route.dataRouteRegex.replace( `/development/`, - `/development/(?.+?)/` + `/development/(?[^/]+?)/` ) ) : new RegExp(route.dataRouteRegex), diff --git a/packages/next/src/server/lib/server-ipc/index.ts b/packages/next/src/server/lib/server-ipc/index.ts index 023cbde2d25d8..8e7bd60a8855d 100644 --- a/packages/next/src/server/lib/server-ipc/index.ts +++ b/packages/next/src/server/lib/server-ipc/index.ts @@ -115,7 +115,6 @@ export const createWorker = async ( __NEXT_PRIVATE_STANDALONE_CONFIG: process.env.__NEXT_PRIVATE_STANDALONE_CONFIG, NODE_ENV: process.env.NODE_ENV, - __NEXT_PRIVATE_RENDER_RUNTIME: type, __NEXT_PRIVATE_PREBUNDLED_REACT: type === 'app' ? (useServerActions ? 'experimental' : 'next') : '', ...(process.env.NEXT_CPU_PROF diff --git a/packages/next/src/server/lib/trace/constants.ts b/packages/next/src/server/lib/trace/constants.ts index 1b45358bdf8ed..50eb4528c7dec 100644 --- a/packages/next/src/server/lib/trace/constants.ts +++ b/packages/next/src/server/lib/trace/constants.ts @@ -43,6 +43,7 @@ enum NextNodeServerSpan { generatePublicRoutes = 'NextNodeServer.generatePublicRoutes', generateImageRoutes = 'NextNodeServer.generateImageRoutes.route', sendRenderResult = 'NextNodeServer.sendRenderResult', + sendStatic = 'NextNodeServer.sendStatic', proxyRequest = 'NextNodeServer.proxyRequest', runApi = 'NextNodeServer.runApi', render = 'NextNodeServer.render', diff --git a/packages/next/src/server/load-components.ts b/packages/next/src/server/load-components.ts index 39da802ff39b1..d2b563493ebe6 100644 --- a/packages/next/src/server/load-components.ts +++ b/packages/next/src/server/load-components.ts @@ -55,7 +55,7 @@ export type LoadComponentsReturnType = { /** * Load manifest file with retries, defaults to 3 attempts. */ -export async function loadManifestWithRetries( +async function loadManifestWithRetries( manifestPath: string, attempts = 3 ): Promise { @@ -87,6 +87,34 @@ async function loadJSManifest( } } +async function loadDefaultErrorComponentsImpl( + distDir: string +): Promise { + const Document = interopDefault(require('next/dist/pages/_document')) + const AppMod = require('next/dist/pages/_app') + const App = interopDefault(AppMod) + + // Load the compiled route module for this builtin error. + // TODO: (wyattjoh) replace this with just exporting the route module when the transition is complete + const ComponentMod = + require('./future/route-modules/pages/builtin/_error') as typeof import('./future/route-modules/pages/builtin/_error') + const Component = ComponentMod.routeModule.userland.default + + return { + App, + Document, + Component, + pageConfig: {}, + buildManifest: await loadManifestWithRetries( + join(distDir, `fallback-${BUILD_MANIFEST}`) + ), + reactLoadableManifest: {}, + ComponentMod, + pathname: '/_error', + routeModule: ComponentMod.routeModule, + } +} + async function loadComponentsImpl({ distDir, pathname, @@ -177,3 +205,8 @@ export const loadComponents = getTracer().wrap( LoadComponentsSpan.loadComponents, loadComponentsImpl ) + +export const loadDefaultErrorComponents = getTracer().wrap( + LoadComponentsSpan.loadDefaultErrorComponents, + loadDefaultErrorComponentsImpl +) diff --git a/packages/next/src/server/load-default-error-components.ts b/packages/next/src/server/load-default-error-components.ts deleted file mode 100644 index c390e9180b3d9..0000000000000 --- a/packages/next/src/server/load-default-error-components.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { - AppType, - DocumentType, - NextComponentType, -} from '../shared/lib/utils' -import type { ClientReferenceManifest } from '../build/webpack/plugins/flight-manifest-plugin' -import type { - PageConfig, - GetStaticPaths, - GetServerSideProps, - GetStaticProps, -} from 'next/types' -import type { RouteModule } from './future/route-modules/route-module' - -import { BUILD_MANIFEST } from '../shared/lib/constants' -import { join } from 'path' -import { BuildManifest } from './get-page-files' -import { interopDefault } from '../lib/interop-default' -import { getTracer } from './lib/trace/tracer' -import { LoadComponentsSpan } from './lib/trace/constants' -import { loadManifestWithRetries } from './load-components' -export type ManifestItem = { - id: number | string - files: string[] -} - -export type ReactLoadableManifest = { [moduleId: string]: ManifestItem } - -export type LoadComponentsReturnType = { - Component: NextComponentType - pageConfig: PageConfig - buildManifest: BuildManifest - subresourceIntegrityManifest?: Record - reactLoadableManifest: ReactLoadableManifest - clientReferenceManifest?: ClientReferenceManifest - serverActionsManifest?: any - Document: DocumentType - App: AppType - getStaticProps?: GetStaticProps - getStaticPaths?: GetStaticPaths - getServerSideProps?: GetServerSideProps - ComponentMod: any - routeModule?: RouteModule - isAppPath?: boolean - pathname: string -} - -async function loadDefaultErrorComponentsImpl( - distDir: string -): Promise { - const Document = interopDefault(require('next/dist/pages/_document')) - const AppMod = require('next/dist/pages/_app') - const App = interopDefault(AppMod) - - // Load the compiled route module for this builtin error. - // TODO: (wyattjoh) replace this with just exporting the route module when the transition is complete - const ComponentMod = - require('./future/route-modules/pages/builtin/_error') as typeof import('./future/route-modules/pages/builtin/_error') - const Component = ComponentMod.routeModule.userland.default - - return { - App, - Document, - Component, - pageConfig: {}, - buildManifest: await loadManifestWithRetries( - join(distDir, `fallback-${BUILD_MANIFEST}`) - ), - reactLoadableManifest: {}, - ComponentMod, - pathname: '/_error', - routeModule: ComponentMod.routeModule, - } -} -export const loadDefaultErrorComponents = getTracer().wrap( - LoadComponentsSpan.loadDefaultErrorComponents, - loadDefaultErrorComponentsImpl -) diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index fe13482eb8b76..d6ad6edaea41d 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -15,7 +15,7 @@ import { import type { MiddlewareManifest } from '../build/webpack/plugins/middleware-plugin' import type RenderResult from './render-result' import type { FetchEventResult } from './web/types' -import type { PrerenderManifest } from '../build' +import type { PrerenderManifest, RoutesManifest } from '../build' import { BaseNextRequest, BaseNextResponse } from './base-http' import type { PagesManifest } from '../build/webpack/plugins/pages-manifest-plugin' import type { PayloadOptions } from './send-payload' @@ -26,6 +26,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 { renderToHTML, type RenderOpts } from './render' import fs from 'fs' import { join, resolve, isAbsolute } from 'path' @@ -48,6 +49,7 @@ import { findDir } from '../lib/find-pages-dir' import { UrlWithParsedQuery } from 'url' import { NodeNextRequest, NodeNextResponse } from './base-http/node' import { sendRenderResult } from './send-payload' +import { getExtension, serveStatic } from './serve-static' import { ParsedUrlQuery } from 'querystring' import { ParsedUrl, parseUrl } from '../shared/lib/router/utils/parse-url' import * as Log from '../build/output/log' @@ -94,6 +96,7 @@ import { invokeRequest } from './lib/server-ipc/invoke-request' import { pipeReadable } from './pipe-readable' import { filterReqHeaders, ipcForbiddenHeaders } from './lib/server-ipc/utils' import { createRequestResponseMocks } from './lib/mock-request' +import chalk from 'next/dist/compiled/chalk' import { NEXT_RSC_UNION_QUERY } from '../client/components/app-router-headers' import { signalFromNodeResponse } from './web/spec-extension/adapters/next-request' import { RouteModuleLoader } from './future/helpers/module-loader/route-module-loader' @@ -385,6 +388,14 @@ export default class NextNodeServer extends BaseServer { }) } + protected sendStatic( + req: NodeNextRequest, + res: NodeNextResponse, + path: string + ): Promise { + return serveStatic(req.originalRequest, res.originalResponse, path) + } + protected async runApi( req: BaseNextRequest | NodeNextRequest, res: BaseNextResponse | NodeNextResponse, @@ -447,7 +458,7 @@ export default class NextNodeServer extends BaseServer { res: NodeNextResponse, pathname: string, query: NextParsedUrlQuery, - renderOpts: import('./render').RenderOpts + renderOpts: RenderOpts ): Promise { return getTracer().trace(NextNodeServerSpan.renderHTML, async () => this.renderHTMLImpl(req, res, pathname, query, renderOpts) @@ -459,35 +470,17 @@ export default class NextNodeServer extends BaseServer { res: NodeNextResponse, pathname: string, query: NextParsedUrlQuery, - renderOpts: import('./render').RenderOpts + renderOpts: RenderOpts ): Promise { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'invariant: renderHTML should not be called in minimal mode' - ) - // the `else` branch is needed for tree-shaking - } else { - // Due to the way we pass data by mutating `renderOpts`, we can't extend the - // object here but only updating its `nextFontManifest` field. - // https://github.com/vercel/next.js/blob/df7cbd904c3bd85f399d1ce90680c0ecf92d2752/packages/next/server/render.tsx#L947-L952 - renderOpts.nextFontManifest = this.nextFontManifest - - if (this.hasAppDir && renderOpts.isAppPath) { - const { renderToHTMLOrFlight: appRenderToHTMLOrFlight } = - require('./future/route-modules/app-page/module.compiled') as typeof import('./app-render/app-render') - return appRenderToHTMLOrFlight( - req.originalRequest, - res.originalResponse, - pathname, - query, - renderOpts - ) - } - - // TODO: re-enable this once we've refactored to use implicit matches - // throw new Error('Invariant: render should have used routeModule') - - return require('./future/route-modules/pages/module.compiled').renderToHTML( + // Due to the way we pass data by mutating `renderOpts`, we can't extend the + // object here but only updating its `nextFontManifest` field. + // https://github.com/vercel/next.js/blob/df7cbd904c3bd85f399d1ce90680c0ecf92d2752/packages/next/server/render.tsx#L947-L952 + renderOpts.nextFontManifest = this.nextFontManifest + + if (this.hasAppDir && renderOpts.isAppPath) { + const { renderToHTMLOrFlight: appRenderToHTMLOrFlight } = + require('./app-render/app-render') as typeof import('./app-render/app-render') + return appRenderToHTMLOrFlight( req.originalRequest, res.originalResponse, pathname, @@ -495,6 +488,17 @@ export default class NextNodeServer extends BaseServer { renderOpts ) } + + // 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 + ) } protected async imageOptimizer( @@ -502,63 +506,55 @@ export default class NextNodeServer extends BaseServer { res: NodeNextResponse, paramsResult: import('./image-optimizer').ImageParamsResult ): Promise<{ buffer: Buffer; contentType: string; maxAge: number }> { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'invariant: imageOptimizer should not be called in minimal mode' - ) - } else { - const { imageOptimizer } = - require('./image-optimizer') as typeof import('./image-optimizer') - - return imageOptimizer( - req.originalRequest, - res.originalResponse, - paramsResult, - this.nextConfig, - this.renderOpts.dev, - async (newReq, newRes, newParsedUrl) => { - if (newReq.url === req.url) { - throw new Error( - `Invariant attempted to optimize _next/image itself` - ) - } + const { imageOptimizer } = + require('./image-optimizer') as typeof import('./image-optimizer') + + return imageOptimizer( + req.originalRequest, + res.originalResponse, + paramsResult, + this.nextConfig, + this.renderOpts.dev, + async (newReq, newRes, newParsedUrl) => { + if (newReq.url === req.url) { + throw new Error(`Invariant attempted to optimize _next/image itself`) + } - if (this.isRenderWorker) { - const invokeRes = await invokeRequest( - `http://${this.fetchHostname || 'localhost'}:${this.port}${ - newReq.url || '' - }`, - { - method: newReq.method || 'GET', - headers: newReq.headers, - signal: signalFromNodeResponse(res.originalResponse), - } - ) - const filteredResHeaders = filterReqHeaders( - toNodeOutgoingHttpHeaders(invokeRes.headers), - ipcForbiddenHeaders - ) - - for (const key of Object.keys(filteredResHeaders)) { - newRes.setHeader(key, filteredResHeaders[key] || '') + if (this.isRenderWorker) { + const invokeRes = await invokeRequest( + `http://${this.fetchHostname || 'localhost'}:${this.port}${ + newReq.url || '' + }`, + { + method: newReq.method || 'GET', + headers: newReq.headers, + signal: signalFromNodeResponse(res.originalResponse), } - newRes.statusCode = invokeRes.status || 200 + ) + const filteredResHeaders = filterReqHeaders( + toNodeOutgoingHttpHeaders(invokeRes.headers), + ipcForbiddenHeaders + ) - if (invokeRes.body) { - await pipeReadable(invokeRes.body, newRes) - } else { - res.send() - } - return + for (const key of Object.keys(filteredResHeaders)) { + newRes.setHeader(key, filteredResHeaders[key] || '') } - return this.getRequestHandler()( - new NodeNextRequest(newReq), - new NodeNextResponse(newRes), - newParsedUrl - ) + newRes.statusCode = invokeRes.status || 200 + + if (invokeRes.body) { + await pipeReadable(invokeRes.body, newRes) + } else { + res.send() + } + return } - ) - } + return this.getRequestHandler()( + new NodeNextRequest(newReq), + new NodeNextResponse(newRes), + newParsedUrl + ) + } + ) } protected getPagePath(pathname: string, locales?: string[]): string { @@ -729,109 +725,99 @@ export default class NextNodeServer extends BaseServer { res: BaseNextResponse, parsedUrl: NextUrlWithParsedQuery ) { - if ( - this.minimalMode || - this.nextConfig.output === 'export' || - process.env.NEXT_MINIMAL - ) { + if (this.minimalMode || this.nextConfig.output === 'export') { res.statusCode = 400 res.body('Bad Request').send() return { finished: true, } - // the `else` branch is needed for tree-shaking - } else { - const { ImageOptimizerCache } = - require('./image-optimizer') as typeof import('./image-optimizer') - - const imageOptimizerCache = new ImageOptimizerCache({ - distDir: this.distDir, - nextConfig: this.nextConfig, - }) + } + const { ImageOptimizerCache } = + require('./image-optimizer') as typeof import('./image-optimizer') - const { getHash, sendResponse, ImageError } = - require('./image-optimizer') as typeof import('./image-optimizer') + const imageOptimizerCache = new ImageOptimizerCache({ + distDir: this.distDir, + nextConfig: this.nextConfig, + }) - if (!this.imageResponseCache) { - throw new Error('invariant image optimizer cache was not initialized') - } - const imagesConfig = this.nextConfig.images + const { getHash, sendResponse, ImageError } = + require('./image-optimizer') as typeof import('./image-optimizer') - if (imagesConfig.loader !== 'default' || imagesConfig.unoptimized) { - await this.render404(req, res) - return { finished: true } - } - const paramsResult = ImageOptimizerCache.validateParams( - (req as NodeNextRequest).originalRequest, - parsedUrl.query, - this.nextConfig, - !!this.renderOpts.dev - ) + if (!this.imageResponseCache) { + throw new Error('invariant image optimizer cache was not initialized') + } + const imagesConfig = this.nextConfig.images - if ('errorMessage' in paramsResult) { - res.statusCode = 400 - res.body(paramsResult.errorMessage).send() - return { finished: true } - } - const cacheKey = ImageOptimizerCache.getCacheKey(paramsResult) + if (imagesConfig.loader !== 'default' || imagesConfig.unoptimized) { + await this.render404(req, res) + return { finished: true } + } + const paramsResult = ImageOptimizerCache.validateParams( + (req as NodeNextRequest).originalRequest, + parsedUrl.query, + this.nextConfig, + !!this.renderOpts.dev + ) - try { - const { getExtension } = - require('./serve-static') as typeof import('./serve-static') - const cacheEntry = await this.imageResponseCache.get( - cacheKey, - async () => { - const { buffer, contentType, maxAge } = await this.imageOptimizer( - req as NodeNextRequest, - res as NodeNextResponse, - paramsResult - ) - const etag = getHash([buffer]) - - return { - value: { - kind: 'IMAGE', - buffer, - etag, - extension: getExtension(contentType) as string, - }, - revalidate: maxAge, - } - }, - { - incrementalCache: imageOptimizerCache, - } - ) + if ('errorMessage' in paramsResult) { + res.statusCode = 400 + res.body(paramsResult.errorMessage).send() + return { finished: true } + } + const cacheKey = ImageOptimizerCache.getCacheKey(paramsResult) - if (cacheEntry?.value?.kind !== 'IMAGE') { - throw new Error( - 'invariant did not get entry from image response cache' + try { + const cacheEntry = await this.imageResponseCache.get( + cacheKey, + async () => { + const { buffer, contentType, maxAge } = await this.imageOptimizer( + req as NodeNextRequest, + res as NodeNextResponse, + paramsResult ) - } - sendResponse( - (req as NodeNextRequest).originalRequest, - (res as NodeNextResponse).originalResponse, - paramsResult.href, - cacheEntry.value.extension, - cacheEntry.value.buffer, - paramsResult.isStatic, - cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT', - imagesConfig, - cacheEntry.revalidate || 0, - Boolean(this.renderOpts.dev) - ) - } catch (err) { - if (err instanceof ImageError) { - res.statusCode = err.statusCode - res.body(err.message).send() + const etag = getHash([buffer]) + return { - finished: true, + value: { + kind: 'IMAGE', + buffer, + etag, + extension: getExtension(contentType) as string, + }, + revalidate: maxAge, } + }, + { + incrementalCache: imageOptimizerCache, } - throw err + ) + + if (cacheEntry?.value?.kind !== 'IMAGE') { + throw new Error('invariant did not get entry from image response cache') } - return { finished: true } + sendResponse( + (req as NodeNextRequest).originalRequest, + (res as NodeNextResponse).originalResponse, + paramsResult.href, + cacheEntry.value.extension, + cacheEntry.value.buffer, + paramsResult.isStatic, + cacheEntry.isMiss ? 'MISS' : cacheEntry.isStale ? 'STALE' : 'HIT', + imagesConfig, + cacheEntry.revalidate || 0, + Boolean(this.renderOpts.dev) + ) + } catch (err) { + if (err instanceof ImageError) { + res.statusCode = err.statusCode + res.body(err.message).send() + return { + finished: true, + } + } + throw err } + return { finished: true } } protected async handleCatchallRenderRequest( @@ -1034,7 +1020,6 @@ export default class NextNodeServer extends BaseServer { const shouldTruncateUrl = !this.nextConfig.experimental.logging?.fullUrl if (this.renderOpts.dev) { - const chalk = require('next/dist/compiled/chalk') const _req = req as NodeNextRequest | IncomingMessage const _res = res as NodeNextResponse | ServerResponse const origReq = 'originalRequest' in _req ? _req.originalRequest : _req @@ -1453,12 +1438,6 @@ export default class NextNodeServer extends BaseServer { parsed: UrlWithParsedQuery onWarning?: (warning: Error) => void }) { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'invariant: runMiddleware should not be called in minimal mode' - ) - } - // Middleware is skipped for on-demand revalidate requests if ( checkIsOnDemandRevalidate(params.request, this.renderOpts.previewProps) @@ -1612,6 +1591,9 @@ export default class NextNodeServer extends BaseServer { ReturnType > + // Strip the internal headers. + this.stripInternalHeaders(req) + try { await this.ensureMiddleware() @@ -1702,7 +1684,10 @@ export default class NextNodeServer extends BaseServer { protected getRoutesManifest(): NormalizedRouteManifest | undefined { return getTracer().trace(NextNodeServerSpan.getRoutesManifest, () => { - const manifest = loadManifest(join(this.distDir, ROUTES_MANIFEST)) + const manifest: RoutesManifest = require(join( + this.distDir, + ROUTES_MANIFEST + )) let rewrites = manifest.rewrites ?? { beforeFiles: [], @@ -1760,11 +1745,6 @@ export default class NextNodeServer extends BaseServer { match?: RouteMatch onWarning?: (warning: Error) => void }): Promise { - if (process.env.NEXT_MINIMAL) { - throw new Error( - 'Middleware is not supported in minimal mode. Please remove the `NEXT_MINIMAL` environment variable.' - ) - } let edgeInfo: ReturnType | undefined const { query, page, match } = params diff --git a/packages/next/src/server/render-result.ts b/packages/next/src/server/render-result.ts index 2a8252e4fd143..b93dfce5fae21 100644 --- a/packages/next/src/server/render-result.ts +++ b/packages/next/src/server/render-result.ts @@ -1,4 +1,4 @@ -import { StaticGenerationStore } from '../client/components/static-generation-async-storage.external' +import { StaticGenerationStore } from '../client/components/static-generation-async-storage' import { pipeReadable, PipeTarget } from './pipe-readable' type ContentTypeOption = string | undefined diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index fe36e793348e2..ac0989082aa9b 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -1,7 +1,7 @@ import type { IncomingMessage, ServerResponse } from 'http' import type { ParsedUrlQuery } from 'querystring' import type { NextRouter } from '../shared/lib/router/router' -import type { HtmlProps } from '../shared/lib/html-context.shared-runtime' +import type { HtmlProps } from '../shared/lib/html-context' import type { DomainLocale } from './config' import type { AppType, @@ -52,12 +52,12 @@ import { } from '../shared/lib/constants' import { isSerializableProps } from '../lib/is-serializable-props' import { isInAmpMode } from '../shared/lib/amp-mode' -import { AmpStateContext } from '../shared/lib/amp-context.shared-runtime' +import { AmpStateContext } from '../shared/lib/amp-context' import { defaultHead } from '../shared/lib/head' -import { HeadManagerContext } from '../shared/lib/head-manager-context.shared-runtime' -import Loadable from '../shared/lib/loadable.shared-runtime' -import { LoadableContext } from '../shared/lib/loadable-context.shared-runtime' -import { RouterContext } from '../shared/lib/router-context.shared-runtime' +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 { isDynamicRoute } from '../shared/lib/router/utils/is-dynamic' import { ComponentsEnhancer, @@ -65,7 +65,7 @@ import { isResSent, loadGetInitialProps, } from '../shared/lib/utils' -import { HtmlContext } from '../shared/lib/html-context.shared-runtime' +import { HtmlContext } from '../shared/lib/html-context' import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path' import { denormalizePagePath } from '../shared/lib/page-path/denormalize-page-path' import { getRequestMeta, NextParsedUrlQuery } from './request-meta' @@ -79,16 +79,16 @@ import { renderToInitialStream, continueFromInitialStream, } from './stream-utils/node-web-streams-helper' -import { ImageConfigContext } from '../shared/lib/image-config-context.shared-runtime' +import { ImageConfigContext } from '../shared/lib/image-config-context' import stripAnsi from 'next/dist/compiled/strip-ansi' import { stripInternalQueries } from './internal-utils' import { adaptForAppRouterInstance, adaptForSearchParams, PathnameContextProviderAdapter, -} from '../shared/lib/router/adapters.shared-runtime' -import { AppRouterContext } from '../shared/lib/app-router-context.shared-runtime' -import { SearchParamsContext } from '../shared/lib/hooks-client-context.shared-runtime' +} from '../shared/lib/router/adapters' +import { AppRouterContext } from '../shared/lib/app-router-context' +import { SearchParamsContext } from '../shared/lib/hooks-client-context' import { getTracer } from './lib/trace/tracer' import { RenderSpan } from './lib/trace/constants' import { ReflectAdapter } from './web/spec-extension/adapters/reflect' diff --git a/packages/next/src/server/require-hook.ts b/packages/next/src/server/require-hook.ts index 9b2e1526eec0e..1f53b3b479109 100644 --- a/packages/next/src/server/require-hook.ts +++ b/packages/next/src/server/require-hook.ts @@ -2,13 +2,11 @@ // This is needed for userland plugins to attach to the same webpack instance as Next.js'. // Individually compiled modules are as defined for the compilation in bundles/webpack/packages/*. -import path, { dirname } from 'path' - // This module will only be loaded once per process. +const { dirname } = require('path') const mod = require('module') const resolveFilename = mod._resolveFilename -const originalRequire = mod.prototype.require const hookPropertyMap = new Map() let aliasedPrebundledReact = false @@ -21,9 +19,10 @@ const resolve = process.env.NEXT_MINIMAL const toResolveMap = (map: Record): [string, string][] => Object.entries(map).map(([key, value]) => [key, resolve(value)]) +// these must use require.resolve to be statically analyzable export const defaultOverrides = { - 'styled-jsx': dirname(resolve('styled-jsx/package.json')), - 'styled-jsx/style': resolve('styled-jsx/style'), + 'styled-jsx': dirname(require.resolve('styled-jsx/package.json')), + 'styled-jsx/style': require.resolve('styled-jsx/style'), } export const baseOverrides = { @@ -79,6 +78,7 @@ export function addHookAliases(aliases: [string, string][] = []) { } } +// Add default aliases addHookAliases(toResolveMap(defaultOverrides)) // Override built-in React packages if necessary @@ -117,29 +117,3 @@ mod._resolveFilename = function ( // We use `bind` here to avoid referencing outside variables to create potential memory leaks. }.bind(null, resolveFilename, hookPropertyMap) - -// This is a hack to make sure that if a user requires a Next.js module that wasn't bundled -// that needs to point to the rendering runtime version, it will point to the correct one. -// This can happen on `pages` when a user requires a dependency that uses next/image for example. -// This is only needed in production as in development we fallback to the external version. -if ( - process.env.NODE_ENV !== 'development' && - process.env.__NEXT_PRIVATE_RENDER_RUNTIME && - !process.env.TURBOPACK -) { - const currentRuntime = `${ - process.env.__NEXT_PRIVATE_RENDER_RUNTIME === 'pages' - ? 'next/dist/compiled/next-server/pages.runtime' - : 'next/dist/compiled/next-server/app-page.runtime' - }.prod` - - mod.prototype.require = function (request: string) { - if (request.endsWith('.shared-runtime')) { - const base = path.basename(request, '.shared-runtime') - const camelized = base.replace(/-([a-z])/g, (g) => g[1].toUpperCase()) - const instance = originalRequire.call(this, currentRuntime) - return instance.default.sharedModules[camelized] - } - return originalRequire.call(this, request) - } -} diff --git a/packages/next/src/server/response-cache/index.ts b/packages/next/src/server/response-cache/index.ts index 7bd6710cc4a80..6d135da26e939 100644 --- a/packages/next/src/server/response-cache/index.ts +++ b/packages/next/src/server/response-cache/index.ts @@ -20,10 +20,7 @@ export default class ResponseCache { constructor(minimalMode: boolean) { this.pendingResponses = new Map() - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - const minimalModeKey = 'minimalMode' - this[minimalModeKey] = minimalMode + this.minimalMode = minimalMode } public get( diff --git a/packages/next/src/server/response-cache/web.ts b/packages/next/src/server/response-cache/web.ts index f255fdd5412d4..e37ccca314812 100644 --- a/packages/next/src/server/response-cache/web.ts +++ b/packages/next/src/server/response-cache/web.ts @@ -15,9 +15,7 @@ export default class WebResponseCache { constructor(minimalMode: boolean) { this.pendingResponses = new Map() - // this is a hack to avoid Webpack knowing this is equal to this.minimalMode - // because we replace this.minimalMode to true in production bundles. - Object.assign(this, { minimalMode }) + this.minimalMode = minimalMode } public get( diff --git a/packages/next/src/server/web/adapter.ts b/packages/next/src/server/web/adapter.ts index 5c6ad3e7ed5ab..1ea32a75956cd 100644 --- a/packages/next/src/server/web/adapter.ts +++ b/packages/next/src/server/web/adapter.ts @@ -18,7 +18,7 @@ import { import { NEXT_QUERY_PARAM_PREFIX } from '../../lib/constants' import { ensureInstrumentationRegistered } from './globals' import { RequestAsyncStorageWrapper } from '../async-storage/request-async-storage-wrapper' -import { requestAsyncStorage } from '../../client/components/request-async-storage.external' +import { requestAsyncStorage } from '../../client/components/request-async-storage' import { PrerenderManifest } from '../../build' class NextRequestHint extends NextRequest { diff --git a/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts b/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts index d44ea986cad65..df3c369eef877 100644 --- a/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts +++ b/packages/next/src/server/web/spec-extension/adapters/request-cookies.ts @@ -1,5 +1,5 @@ import type { RequestCookies } from '../cookies' -import { StaticGenerationStore } from '../../../../client/components/static-generation-async-storage.external' +import { StaticGenerationStore } from '../../../../client/components/static-generation-async-storage' import { ResponseCookies } from '../cookies' import { ReflectAdapter } from './reflect' diff --git a/packages/next/src/server/web/spec-extension/response.ts b/packages/next/src/server/web/spec-extension/response.ts index 18fa7158c5adc..86b09e3616a83 100644 --- a/packages/next/src/server/web/spec-extension/response.ts +++ b/packages/next/src/server/web/spec-extension/response.ts @@ -71,7 +71,6 @@ export class NextResponse extends Response { body: JsonBody, init?: ResponseInit ): NextResponse { - // @ts-expect-error This is not in lib/dom right now, and we can't augment it. const response: Response = Response.json(body, init) return new NextResponse(response.body, response) } diff --git a/packages/next/src/server/web/spec-extension/revalidate-tag.ts b/packages/next/src/server/web/spec-extension/revalidate-tag.ts index 7c7bff8c2f784..8d7cd68bd3a9a 100644 --- a/packages/next/src/server/web/spec-extension/revalidate-tag.ts +++ b/packages/next/src/server/web/spec-extension/revalidate-tag.ts @@ -1,7 +1,7 @@ import { StaticGenerationAsyncStorage, StaticGenerationStore, -} from '../../../client/components/static-generation-async-storage.external' +} from '../../../client/components/static-generation-async-storage' export function revalidateTag(tag: string) { const staticGenerationAsyncStorage = ( diff --git a/packages/next/src/server/web/spec-extension/unstable-cache.ts b/packages/next/src/server/web/spec-extension/unstable-cache.ts index 1e85b5c290971..aad3ed2baf20a 100644 --- a/packages/next/src/server/web/spec-extension/unstable-cache.ts +++ b/packages/next/src/server/web/spec-extension/unstable-cache.ts @@ -2,7 +2,7 @@ import { StaticGenerationStore, staticGenerationAsyncStorage as _staticGenerationAsyncStorage, StaticGenerationAsyncStorage, -} from '../../../client/components/static-generation-async-storage.external' +} from '../../../client/components/static-generation-async-storage' import { CACHE_ONE_YEAR } from '../../../lib/constants' import { addImplicitTags } from '../../lib/patch-fetch' diff --git a/packages/next/src/shared/lib/amp-context.shared-runtime.ts b/packages/next/src/shared/lib/amp-context.ts similarity index 100% rename from packages/next/src/shared/lib/amp-context.shared-runtime.ts rename to packages/next/src/shared/lib/amp-context.ts diff --git a/packages/next/src/shared/lib/amp.ts b/packages/next/src/shared/lib/amp.ts index 8edd21db9c299..04518b2389357 100644 --- a/packages/next/src/shared/lib/amp.ts +++ b/packages/next/src/shared/lib/amp.ts @@ -1,5 +1,5 @@ import React from 'react' -import { AmpStateContext } from './amp-context.shared-runtime' +import { AmpStateContext } from './amp-context' import { isInAmpMode } from './amp-mode' export function useAmp(): boolean { diff --git a/packages/next/src/shared/lib/app-router-context.shared-runtime.ts b/packages/next/src/shared/lib/app-router-context.ts similarity index 100% rename from packages/next/src/shared/lib/app-router-context.shared-runtime.ts rename to packages/next/src/shared/lib/app-router-context.ts diff --git a/packages/next/src/shared/lib/dynamic.tsx b/packages/next/src/shared/lib/dynamic.tsx index 390410edda29e..cb497fc587d4f 100644 --- a/packages/next/src/shared/lib/dynamic.tsx +++ b/packages/next/src/shared/lib/dynamic.tsx @@ -1,5 +1,5 @@ import React from 'react' -import Loadable from './loadable.shared-runtime' +import Loadable from './loadable' const isServerSide = typeof window === 'undefined' diff --git a/packages/next/src/shared/lib/head-manager-context.shared-runtime.ts b/packages/next/src/shared/lib/head-manager-context.ts similarity index 100% rename from packages/next/src/shared/lib/head-manager-context.shared-runtime.ts rename to packages/next/src/shared/lib/head-manager-context.ts diff --git a/packages/next/src/shared/lib/head.tsx b/packages/next/src/shared/lib/head.tsx index 42f95767bfa4c..3156e259f656f 100644 --- a/packages/next/src/shared/lib/head.tsx +++ b/packages/next/src/shared/lib/head.tsx @@ -2,8 +2,8 @@ import React, { useContext } from 'react' import Effect from './side-effect' -import { AmpStateContext } from './amp-context.shared-runtime' -import { HeadManagerContext } from './head-manager-context.shared-runtime' +import { AmpStateContext } from './amp-context' +import { HeadManagerContext } from './head-manager-context' import { isInAmpMode } from './amp-mode' import { warnOnce } from './utils/warn-once' diff --git a/packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts b/packages/next/src/shared/lib/hooks-client-context.ts similarity index 100% rename from packages/next/src/shared/lib/hooks-client-context.shared-runtime.ts rename to packages/next/src/shared/lib/hooks-client-context.ts diff --git a/packages/next/src/shared/lib/html-context.shared-runtime.ts b/packages/next/src/shared/lib/html-context.ts similarity index 100% rename from packages/next/src/shared/lib/html-context.shared-runtime.ts rename to packages/next/src/shared/lib/html-context.ts diff --git a/packages/next/src/shared/lib/image-config-context.shared-runtime.ts b/packages/next/src/shared/lib/image-config-context.ts similarity index 100% rename from packages/next/src/shared/lib/image-config-context.shared-runtime.ts rename to packages/next/src/shared/lib/image-config-context.ts diff --git a/packages/next/src/shared/lib/loadable-context.shared-runtime.ts b/packages/next/src/shared/lib/loadable-context.ts similarity index 100% rename from packages/next/src/shared/lib/loadable-context.shared-runtime.ts rename to packages/next/src/shared/lib/loadable-context.ts diff --git a/packages/next/src/shared/lib/loadable.shared-runtime.tsx b/packages/next/src/shared/lib/loadable.tsx similarity index 99% rename from packages/next/src/shared/lib/loadable.shared-runtime.tsx rename to packages/next/src/shared/lib/loadable.tsx index 82ba84182701f..1592d98551093 100644 --- a/packages/next/src/shared/lib/loadable.shared-runtime.tsx +++ b/packages/next/src/shared/lib/loadable.tsx @@ -23,7 +23,7 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE // Modified to be compatible with webpack 4 / Next.js import React from 'react' -import { LoadableContext } from './loadable-context.shared-runtime' +import { LoadableContext } from './loadable-context' function resolve(obj: any) { return obj && obj.default ? obj.default : obj diff --git a/packages/next/src/shared/lib/router-context.shared-runtime.ts b/packages/next/src/shared/lib/router-context.ts similarity index 100% rename from packages/next/src/shared/lib/router-context.shared-runtime.ts rename to packages/next/src/shared/lib/router-context.ts diff --git a/packages/next/src/shared/lib/router/adapters.test.tsx b/packages/next/src/shared/lib/router/adapters.test.tsx index e47ce2174dd35..fa8e48f2fc088 100644 --- a/packages/next/src/shared/lib/router/adapters.test.tsx +++ b/packages/next/src/shared/lib/router/adapters.test.tsx @@ -1,4 +1,4 @@ -import { adaptForAppRouterInstance } from './adapters.shared-runtime' +import { adaptForAppRouterInstance } from './adapters' import { NextRouter } from './router' describe('adaptForAppRouterInstance', () => { diff --git a/packages/next/src/shared/lib/router/adapters.shared-runtime.tsx b/packages/next/src/shared/lib/router/adapters.tsx similarity index 95% rename from packages/next/src/shared/lib/router/adapters.shared-runtime.tsx rename to packages/next/src/shared/lib/router/adapters.tsx index 29f92dda8dc08..ce68a8bec1e8b 100644 --- a/packages/next/src/shared/lib/router/adapters.shared-runtime.tsx +++ b/packages/next/src/shared/lib/router/adapters.tsx @@ -1,10 +1,7 @@ import type { ParsedUrlQuery } from 'node:querystring' import React, { useMemo, useRef } from 'react' -import type { - AppRouterInstance, - NavigateOptions, -} from '../app-router-context.shared-runtime' -import { PathnameContext } from '../hooks-client-context.shared-runtime' +import type { AppRouterInstance, NavigateOptions } from '../app-router-context' +import { PathnameContext } from '../hooks-client-context' import type { NextRouter } from './router' import { isDynamicRoute } from './utils' diff --git a/packages/next/src/shared/lib/runtime-config.shared-runtime.ts b/packages/next/src/shared/lib/runtime-config.ts similarity index 100% rename from packages/next/src/shared/lib/runtime-config.shared-runtime.ts rename to packages/next/src/shared/lib/runtime-config.ts diff --git a/packages/next/src/shared/lib/server-inserted-html.shared-runtime.tsx b/packages/next/src/shared/lib/server-inserted-html.tsx similarity index 100% rename from packages/next/src/shared/lib/server-inserted-html.shared-runtime.tsx rename to packages/next/src/shared/lib/server-inserted-html.tsx diff --git a/packages/next/src/shared/lib/utils.ts b/packages/next/src/shared/lib/utils.ts index 4e8036a6894a2..f967be459022b 100644 --- a/packages/next/src/shared/lib/utils.ts +++ b/packages/next/src/shared/lib/utils.ts @@ -1,4 +1,4 @@ -import type { HtmlProps } from './html-context.shared-runtime' +import type { HtmlProps } from './html-context' import type { ComponentType } from 'react' import type { DomainLocale } from '../../server/config' import type { Env } from '@next/env' diff --git a/packages/next/src/trace/index.ts b/packages/next/src/trace/index.ts index e3928f775f613..e242e19c9041f 100644 --- a/packages/next/src/trace/index.ts +++ b/packages/next/src/trace/index.ts @@ -1,5 +1,4 @@ import { trace, flushAllTraces, Span, SpanStatus } from './trace' import { SpanId, setGlobal } from './shared' -export { trace, flushAllTraces, Span, setGlobal, SpanStatus } -export type { SpanId } +export { trace, flushAllTraces, SpanId, Span, SpanStatus, setGlobal } diff --git a/packages/next/taskfile-webpack.js b/packages/next/taskfile-webpack.js deleted file mode 100644 index 04495d7b3621c..0000000000000 --- a/packages/next/taskfile-webpack.js +++ /dev/null @@ -1,35 +0,0 @@ -const webpack = require('webpack') - -module.exports = function (task) { - task.plugin('webpack', {}, function* (_, options) { - options = options || {} - - const compiler = webpack(options.config) - - if (options.watch) { - compiler.watch({}, (err, stats) => { - if (err || stats.hasErrors()) { - console.error(err || stats.toString()) - } else { - console.log(`${options.name} compiled successfully.`) - } - }) - } else { - yield new Promise((resolve, reject) => { - compiler.run((err, stats) => { - if (err || stats.hasErrors()) { - console.error(err || stats.toString()) - reject(err || stats.toString()) - } - if (process.env.ANALYZE) { - require('fs').writeFileSync( - require('path').join(__dirname, options.name + '-stats.json'), - JSON.stringify(stats.toJson()) - ) - } - resolve() - }) - }) - } - }) -} diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 321490234153b..f38289c3d4984 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2357,7 +2357,7 @@ export async function ncc(task, opts) { ) } -export async function next_compile(task, opts) { +export async function compile(task, opts) { await task.parallel( [ 'cli', @@ -2388,16 +2388,12 @@ export async function next_compile(task, opts) { ], opts ) -} - -export async function compile(task, opts) { - await task.serial(['next_compile', 'next_bundle'], opts) - await task.serial([ 'ncc_react_refresh_utils', 'ncc_next__react_dev_overlay', 'ncc_next_font', 'capsize_metrics', + 'minimal_next_server', ]) } @@ -2662,38 +2658,157 @@ export async function release(task) { await task.clear('dist').start('build') } -export async function next_bundle_prod(task, opts) { - await task.source('dist').webpack({ - watch: opts.dev, - config: require('./webpack.config')({ - dev: false, - }), - name: 'next-bundle-prod', +export async function minimal_next_server(task) { + const outputName = 'next-server.js' + const cachedOutputName = `${outputName}.cache` + + const minimalExternals = [ + 'react', + 'react/package.json', + 'react/jsx-runtime', + 'react/jsx-dev-runtime', + 'react-dom', + 'react-dom/package.json', + 'react-dom/client', + 'react-dom/server', + 'react-dom/server.browser', + 'react-dom/server.edge', + 'react-server-dom-webpack/client', + 'react-server-dom-webpack/client.edge', + 'react-server-dom-webpack/server.edge', + 'react-server-dom-webpack/server.node', + 'styled-jsx', + 'styled-jsx/style', + '@opentelemetry/api', + 'next/dist/compiled/@next/react-dev-overlay/dist/middleware', + 'next/dist/compiled/@ampproject/toolbox-optimizer', + 'next/dist/compiled/edge-runtime', + 'next/dist/compiled/@edge-runtime/ponyfill', + 'next/dist/compiled/undici', + 'next/dist/compiled/raw-body', + 'next/dist/server/capsize-font-metrics.json', + 'critters', + 'next/dist/compiled/node-html-parser', + 'next/dist/compiled/compression', + 'next/dist/compiled/jsonwebtoken', + 'next/dist/compiled/@mswjs/interceptors/ClientRequest', + ].reduce((acc, pkg) => { + acc[pkg] = pkg + return acc + }, {}) + + Object.assign(minimalExternals, { + '/(.*)config$/': 'next/dist/server/config', + './web/sandbox': 'next/dist/server/web/sandbox', }) -} -export async function next_bundle_dev(task, opts) { - await task.source('dist').webpack({ - watch: opts.dev, - config: require('./webpack.config')({ - dev: true, - }), - name: 'next-bundle-dev', + const webpack = require('webpack') + const TerserPlugin = require('terser-webpack-plugin') + // const BundleAnalyzerPlugin = + // require('webpack-bundle-analyzer').BundleAnalyzerPlugin + /** @type {webpack.Configuration} */ + const config = { + entry: join(__dirname, 'dist/server/next-server.js'), + target: 'node', + mode: 'production', + output: { + path: join(__dirname, 'dist/compiled/minimal-next-server'), + filename: outputName, + libraryTarget: 'commonjs2', + }, + // left in for debugging + optimization: { + moduleIds: 'named', + // minimize: false, + minimize: true, + minimizer: [ + new TerserPlugin({ + extractComments: false, + terserOptions: { + format: { + comments: false, + }, + compress: { + passes: 2, + }, + }, + }), + ], + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production'), + 'process.env.NEXT_MINIMAL': JSON.stringify('true'), + 'process.env.NEXT_RUNTIME': JSON.stringify('nodejs'), + }), + // new BundleAnalyzerPlugin({}), + ], + externals: [minimalExternals], + } + + await new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err) return reject(err) + if (stats.hasErrors()) { + return reject(new Error(stats.toString('errors-only'))) + } + resolve() + }) }) -} -export async function next_bundle_turbo_prod(task, opts) { - await task.source('dist').webpack({ - watch: opts.dev, - config: require('./webpack.config')({ - turbo: true, - }), - name: 'next-bundle-prod-turbo', + const wrappedTemplate = ` +const filename = ${JSON.stringify(outputName)} +const { readFileSync } = require('fs'), + { Script } = require('vm'), + { wrap } = require('module'), + { join } = require('path'); +const basename = join(__dirname, filename) + +const source = readFileSync(basename, 'utf-8') + +const cachedData = + !process.pkg && + require('process').platform !== 'win32' && + readFileSync(join(__dirname, '${cachedOutputName}')) + +const scriptOpts = { filename: basename, columnOffset: 0 } + +const script = new Script( + wrap(source), + cachedData ? Object.assign({ cachedData }, scriptOpts) : scriptOpts +) + +script.runInThisContext()(exports, require, module, __filename, __dirname) +` + + await fs.writeFile( + join(__dirname, `dist/compiled/minimal-next-server/next-server-cached.js`), + wrappedTemplate + ) + + const Module = require('module') + const vm = require('vm') + const filename = resolve( + __dirname, + 'dist/compiled/minimal-next-server', + outputName + ) + + const content = require('fs').readFileSync(filename, 'utf8') + + const wrapper = Module.wrap(content) + var script = new vm.Script(wrapper, { + filename: filename, + lineOffset: 0, + displayErrors: true, }) -} -export async function next_bundle(task, opts) { - await task.parallel( - ['next_bundle_prod', 'next_bundle_dev', 'next_bundle_turbo_prod'], - opts + + script.runInThisContext()(exports, require, module, __filename, __dirname) + + const buffer = script.createCachedData() + + await fs.writeFile( + join(__dirname, `dist/compiled/minimal-next-server/${cachedOutputName}`), + buffer ) } diff --git a/packages/next/webpack.config.js b/packages/next/webpack.config.js deleted file mode 100644 index 8e7c3063fa5ed..0000000000000 --- a/packages/next/webpack.config.js +++ /dev/null @@ -1,145 +0,0 @@ -const webpack = require('webpack') -const path = require('path') -const TerserPlugin = require('terser-webpack-plugin') -const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer') - -const minimalExternals = [ - 'react', - 'react/package.json', - 'react/jsx-runtime', - 'react/jsx-dev-runtime', - 'react-dom', - 'react-dom/package.json', - 'react-dom/client', - 'react-dom/server', - 'react-dom/server.browser', - 'react-dom/server.edge', - 'react-server-dom-webpack/client', - 'react-server-dom-webpack/client.edge', - 'react-server-dom-webpack/server.edge', - 'react-server-dom-webpack/server.node', - 'styled-jsx', - 'styled-jsx/style', - '@opentelemetry/api', - 'next/dist/compiled/@next/react-dev-overlay/dist/middleware', - 'next/dist/compiled/@ampproject/toolbox-optimizer', - 'next/dist/compiled/edge-runtime', - 'next/dist/compiled/@edge-runtime/ponyfill', - 'next/dist/compiled/undici', - 'next/dist/compiled/raw-body', - 'next/dist/server/capsize-font-metrics.json', - 'critters', - 'next/dist/compiled/node-html-parser', - 'next/dist/compiled/compression', - 'next/dist/compiled/jsonwebtoken', - 'next/dist/compiled/@opentelemetry/api', - 'next/dist/compiled/@mswjs/interceptors/ClientRequest', -] - -const externalsMap = { - './web/sandbox': 'next/dist/server/web/sandbox', -} - -const externalsRegexMap = { - '(.*)trace/tracer$': 'next/dist/server/lib/trace/tracer', -} - -module.exports = ({ dev, turbo }) => { - const externalHandler = ({ context, request, getResolve }, callback) => { - ;(async () => { - if ( - ((dev || turbo) && request.endsWith('.shared-runtime')) || - request.endsWith('.external') - ) { - const resolve = getResolve() - const resolved = await resolve(context, request) - const relative = path.relative( - path.join(__dirname, '..'), - resolved.replace('esm' + path.sep, '') - ) - callback(null, `commonjs ${relative}`) - } else { - const regexMatch = Object.keys(externalsRegexMap).find((regex) => - new RegExp(regex).test(request) - ) - if (regexMatch) { - return callback(null, 'commonjs ' + externalsRegexMap[regexMatch]) - } - callback() - } - })() - } - - /** @type {webpack.Configuration} */ - return { - entry: { - server: path.join(__dirname, 'dist/esm/server/next-server.js'), - 'app-page': path.join( - __dirname, - 'dist/esm/server/future/route-modules/app-page/module.js' - ), - 'app-route': path.join( - __dirname, - 'dist/esm/server/future/route-modules/app-route/module.js' - ), - pages: path.join( - __dirname, - 'dist/esm/server/future/route-modules/pages/module.js' - ), - 'pages-api': path.join( - __dirname, - 'dist/esm/server/future/route-modules/pages-api/module.js' - ), - }, - target: 'node', - mode: 'production', - output: { - path: path.join(__dirname, 'dist/compiled/next-server'), - filename: `[name]${turbo ? '-turbo' : ''}.runtime.${ - dev ? 'dev' : 'prod' - }.js`, - libraryTarget: 'commonjs2', - }, - optimization: { - moduleIds: 'named', - minimize: true, - // splitChunks: { - // chunks: 'all', - // }, - concatenateModules: true, - minimizer: [ - new TerserPlugin({ - extractComments: false, - terserOptions: { - format: { - comments: false, - }, - compress: { - passes: 2, - }, - }, - }), - ], - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env.NEXT_MINIMAL': JSON.stringify('true'), - 'this.serverOptions.experimentalTestProxy': JSON.stringify(false), - 'this.minimalMode': JSON.stringify(true), - 'this.renderOpts.dev': JSON.stringify(dev), - 'process.env.NODE_ENV': JSON.stringify( - dev ? 'development' : 'production' - ), - 'process.env.NEXT_RUNTIME': JSON.stringify('nodejs'), - }), - !!process.env.ANALYZE && - new BundleAnalyzerPlugin({ - analyzerPort: 8888 + (dev ? 0 : 1) + (turbo ? 1 : 0), - }), - ].filter(Boolean), - stats: { - optimizationBailout: true, - }, - externals: [...minimalExternals, externalsMap, externalHandler], - } -} diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index cc6d2a5b422a3..d760b0ff82191 100644 --- a/packages/react-dev-overlay/package.json +++ b/packages/react-dev-overlay/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-dev-overlay", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-dev-overlay/tsconfig.json b/packages/react-dev-overlay/tsconfig.json index 59e05adbe1d27..01235b6a1bf8f 100644 --- a/packages/react-dev-overlay/tsconfig.json +++ b/packages/react-dev-overlay/tsconfig.json @@ -12,6 +12,7 @@ "jsx": "react", "noFallthroughCasesInSwitch": true, "skipLibCheck": true, + "module": "Node16", "moduleResolution": "Node16" }, "include": ["src/**/*.ts", "src/**/*.tsx", "types/local.d.ts"], diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 20e4acbdcca74..2db27f44e1e96 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": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "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 7677d8733511c..4e69590dcd618 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "13.4.20-canary.20", + "version": "13.4.20-canary.21", "private": true, "repository": { "url": "vercel/next.js", @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "13.4.20-canary.20", + "next": "13.4.20-canary.21", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8478bb10eb18c..ecefb2db79ec1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -150,8 +150,8 @@ importers: specifier: 18.2.4 version: 18.2.4 '@types/relay-runtime': - specifier: 13.0.0 - version: 13.0.0 + specifier: 14.1.13 + version: 14.1.13 '@types/selenium-webdriver': specifier: 4.0.15 version: 4.0.15 @@ -166,10 +166,10 @@ importers: version: 2.0.3 '@typescript-eslint/eslint-plugin': specifier: 6.1.0 - version: 6.1.0(@typescript-eslint/parser@6.1.0)(eslint@7.24.0)(typescript@5.1.3) + version: 6.1.0(@typescript-eslint/parser@6.1.0)(eslint@7.24.0)(typescript@5.2.2) '@typescript-eslint/parser': specifier: 6.1.0 - version: 6.1.0(eslint@7.24.0)(typescript@5.1.3) + version: 6.1.0(eslint@7.24.0)(typescript@5.2.2) '@vercel/fetch': specifier: 6.1.1 version: 6.1.1(@types/node-fetch@2.6.1)(node-fetch@2.6.7) @@ -250,7 +250,7 @@ importers: version: 2.22.1(@typescript-eslint/parser@6.1.0)(eslint@7.24.0) eslint-plugin-jest: specifier: 24.3.5 - version: 24.3.5(@typescript-eslint/eslint-plugin@6.1.0)(eslint@7.24.0)(typescript@5.1.3) + version: 24.3.5(@typescript-eslint/eslint-plugin@6.1.0)(eslint@7.24.0)(typescript@5.2.2) eslint-plugin-jsdoc: specifier: 39.6.4 version: 39.6.4(eslint@7.24.0) @@ -520,13 +520,13 @@ importers: version: 1.2.2 tsec: specifier: 0.2.1 - version: 0.2.1(@bazel/bazelisk@1.12.1)(typescript@5.1.3) + version: 0.2.1(@bazel/bazelisk@1.12.1)(typescript@5.2.2) turbo: specifier: 1.10.9 version: 1.10.9 typescript: - specifier: 5.1.3 - version: 5.1.3 + specifier: 5.2.2 + version: 5.2.2 unfetch: specifier: 4.2.0 version: 4.2.0 @@ -729,7 +729,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -790,7 +790,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-env '@swc/helpers': specifier: 0.5.1 @@ -917,19 +917,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../react-refresh-utils '@next/swc': - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next-swc '@opentelemetry/api': specifier: 1.4.1 @@ -1001,8 +1001,8 @@ importers: specifier: 9.0.0 version: 9.0.0 '@types/lodash': - specifier: 4.14.149 - version: 4.14.149 + specifier: 4.14.198 + version: 4.14.198 '@types/lodash.curry': specifier: 4.1.6 version: 4.1.6 @@ -1244,8 +1244,8 @@ importers: specifier: 2.4.3 version: 2.4.3(webpack@5.86.0) msw: - specifier: ^1.2.2 - version: 1.2.2(typescript@5.1.3) + specifier: 1.3.0 + version: 1.3.0(typescript@5.2.2) nanoid: specifier: 3.1.32 version: 3.1.32 @@ -1381,9 +1381,6 @@ importers: terser: specifier: 5.14.1 version: 5.14.1 - terser-webpack-plugin: - specifier: 5.3.9 - version: 5.3.9(@swc/core@1.3.55)(webpack@5.86.0) text-table: specifier: 0.2.0 version: 0.2.0 @@ -1688,7 +1685,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 13.4.20-canary.20 + specifier: 13.4.20-canary.21 version: link:../next outdent: specifier: 0.8.0 @@ -6848,7 +6845,7 @@ packages: '@types/debug': 4.1.8 '@xmldom/xmldom': 0.8.10 debug: 4.3.4 - headers-polyfill: 3.1.2 + headers-polyfill: 3.2.3 outvariant: 1.4.0 strict-event-emitter: 0.2.8 web-encoding: 1.1.5 @@ -8336,11 +8333,11 @@ packages: /@types/lodash.curry@4.1.6: resolution: {integrity: sha512-x3ctCcmOYqRrihNNnQJW6fe/yZFCgnrIa6p80AiPQRO8Jis29bBdy1dEw1FwngoF/mCZa3Bx+33fUZvOEE635Q==} dependencies: - '@types/lodash': 4.14.149 + '@types/lodash': 4.14.198 dev: true - /@types/lodash@4.14.149: - resolution: {integrity: sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ==} + /@types/lodash@4.14.198: + resolution: {integrity: sha512-trNJ/vtMZYMLhfN45uLq4ShQSw0/S7xCTLLVM+WM1rmFpba/VS42jVUgaO3w/NOLiWR/09lnYk0yMaA/atdIsg==} dev: true /@types/long@4.0.1: @@ -8463,8 +8460,8 @@ packages: '@types/scheduler': 0.16.2 csstype: 3.0.10 - /@types/relay-runtime@13.0.0: - resolution: {integrity: sha512-yzv6F8EZPWA2rtfFP2qMluS8tsz1q4lfdYxLegCshdAjX5uqxTR2pAliATj9wrzD6OMZF4fl9aU+Y+zmSfm2EA==} + /@types/relay-runtime@14.1.13: + resolution: {integrity: sha512-NODqEnGjERJr02M0YQclUnXWCldmerNUkpFfuO317h/od1uXuwAW5131vpeiROE11BizPC/Qhup5VrwKsENazw==} dev: true /@types/resolve@1.17.1: @@ -8621,7 +8618,7 @@ packages: '@types/yargs-parser': 21.0.0 dev: true - /@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.1.0)(eslint@7.24.0)(typescript@5.1.3): + /@typescript-eslint/eslint-plugin@6.1.0(@typescript-eslint/parser@6.1.0)(eslint@7.24.0)(typescript@5.2.2): resolution: {integrity: sha512-qg7Bm5TyP/I7iilGyp6DRqqkt8na00lI6HbjWZObgk3FFSzH5ypRwAHXJhJkwiRtTcfn+xYQIMOR5kJgpo6upw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8633,10 +8630,10 @@ packages: optional: true dependencies: '@eslint-community/regexpp': 4.5.1 - '@typescript-eslint/parser': 6.1.0(eslint@7.24.0)(typescript@5.1.3) + '@typescript-eslint/parser': 6.1.0(eslint@7.24.0)(typescript@5.2.2) '@typescript-eslint/scope-manager': 6.1.0 - '@typescript-eslint/type-utils': 6.1.0(eslint@7.24.0)(typescript@5.1.3) - '@typescript-eslint/utils': 6.1.0(eslint@7.24.0)(typescript@5.1.3) + '@typescript-eslint/type-utils': 6.1.0(eslint@7.24.0)(typescript@5.2.2) + '@typescript-eslint/utils': 6.1.0(eslint@7.24.0)(typescript@5.2.2) '@typescript-eslint/visitor-keys': 6.1.0 debug: 4.3.4 eslint: 7.24.0 @@ -8645,13 +8642,13 @@ packages: natural-compare: 1.4.0 natural-compare-lite: 1.4.0 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.1.3) - typescript: 5.1.3 + ts-api-utils: 1.0.1(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/experimental-utils@4.29.1(eslint@7.24.0)(typescript@5.1.3): + /@typescript-eslint/experimental-utils@4.29.1(eslint@7.24.0)(typescript@5.2.2): resolution: {integrity: sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -8660,7 +8657,7 @@ packages: '@types/json-schema': 7.0.12 '@typescript-eslint/scope-manager': 4.29.1 '@typescript-eslint/types': 4.29.1 - '@typescript-eslint/typescript-estree': 4.29.1(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 4.29.1(typescript@5.2.2) eslint: 7.24.0 eslint-scope: 5.1.1 eslint-utils: 3.0.0(eslint@7.24.0) @@ -8669,7 +8666,7 @@ packages: - typescript dev: true - /@typescript-eslint/parser@6.1.0(eslint@7.24.0)(typescript@5.1.3): + /@typescript-eslint/parser@6.1.0(eslint@7.24.0)(typescript@5.2.2): resolution: {integrity: sha512-hIzCPvX4vDs4qL07SYzyomamcs2/tQYXg5DtdAfj35AyJ5PIUqhsLf4YrEIFzZcND7R2E8tpQIZKayxg8/6Wbw==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8681,11 +8678,11 @@ packages: dependencies: '@typescript-eslint/scope-manager': 6.1.0 '@typescript-eslint/types': 6.1.0 - '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.2.2) '@typescript-eslint/visitor-keys': 6.1.0 debug: 4.3.4 eslint: 7.24.0 - typescript: 5.1.3 + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -8726,7 +8723,7 @@ packages: '@typescript-eslint/types': 6.1.0 '@typescript-eslint/visitor-keys': 6.1.0 - /@typescript-eslint/type-utils@6.1.0(eslint@7.24.0)(typescript@5.1.3): + /@typescript-eslint/type-utils@6.1.0(eslint@7.24.0)(typescript@5.2.2): resolution: {integrity: sha512-kFXBx6QWS1ZZ5Ni89TyT1X9Ag6RXVIVhqDs0vZE/jUeWlBv/ixq2diua6G7ece6+fXw3TvNRxP77/5mOMusx2w==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8736,12 +8733,12 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.1.3) - '@typescript-eslint/utils': 6.1.0(eslint@7.24.0)(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.2.2) + '@typescript-eslint/utils': 6.1.0(eslint@7.24.0)(typescript@5.2.2) debug: 4.3.4 eslint: 7.24.0 - ts-api-utils: 1.0.1(typescript@5.1.3) - typescript: 5.1.3 + ts-api-utils: 1.0.1(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -8755,7 +8752,7 @@ packages: resolution: {integrity: sha512-+Gfd5NHCpDoHDOaU/yIF3WWRI2PcBRKKpP91ZcVbL0t5tQpqYWBs3z/GGhvU+EV1D0262g9XCnyqQh19prU0JQ==} engines: {node: ^16.0.0 || >=18.0.0} - /@typescript-eslint/typescript-estree@4.29.1(typescript@5.1.3): + /@typescript-eslint/typescript-estree@4.29.1(typescript@5.2.2): resolution: {integrity: sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -8770,8 +8767,8 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.7 - tsutils: 3.21.0(typescript@5.1.3) - typescript: 5.1.3 + tsutils: 3.21.0(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true @@ -8797,7 +8794,7 @@ packages: - supports-color dev: false - /@typescript-eslint/typescript-estree@6.1.0(typescript@5.1.3): + /@typescript-eslint/typescript-estree@6.1.0(typescript@5.2.2): resolution: {integrity: sha512-nUKAPWOaP/tQjU1IQw9sOPCDavs/iU5iYLiY/6u7gxS7oKQoi4aUxXS1nrrVGTyBBaGesjkcwwHkbkiD5eBvcg==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8812,13 +8809,13 @@ packages: globby: 11.1.0 is-glob: 4.0.3 semver: 7.5.4 - ts-api-utils: 1.0.1(typescript@5.1.3) - typescript: 5.1.3 + ts-api-utils: 1.0.1(typescript@5.2.2) + typescript: 5.2.2 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/utils@6.1.0(eslint@7.24.0)(typescript@5.1.3): + /@typescript-eslint/utils@6.1.0(eslint@7.24.0)(typescript@5.2.2): resolution: {integrity: sha512-wp652EogZlKmQoMS5hAvWqRKplXvkuOnNzZSE0PVvsKjpexd/XznRVHAtrfHFYmqaJz0DFkjlDsGYC9OXw+OhQ==} engines: {node: ^16.0.0 || >=18.0.0} peerDependencies: @@ -8829,7 +8826,7 @@ packages: '@types/semver': 7.5.0 '@typescript-eslint/scope-manager': 6.1.0 '@typescript-eslint/types': 6.1.0 - '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.1.3) + '@typescript-eslint/typescript-estree': 6.1.0(typescript@5.2.2) eslint: 7.24.0 semver: 7.5.4 transitivePeerDependencies: @@ -10710,14 +10707,6 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 - /chalk@4.1.1: - resolution: {integrity: sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==} - engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - /chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} @@ -12179,7 +12168,7 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} @@ -13132,7 +13121,7 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 6.1.0(eslint@7.24.0)(typescript@5.1.3) + '@typescript-eslint/parser': 6.1.0(eslint@7.24.0)(typescript@5.2.2) debug: 3.2.7 eslint-import-resolver-node: 0.3.6 find-up: 2.1.0 @@ -13191,7 +13180,7 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 6.1.0(eslint@7.24.0)(typescript@5.1.3) + '@typescript-eslint/parser': 6.1.0(eslint@7.24.0)(typescript@5.2.2) array-includes: 3.1.4 array.prototype.flat: 1.2.5 contains-path: 0.1.0 @@ -13247,7 +13236,7 @@ packages: - supports-color dev: false - /eslint-plugin-jest@24.3.5(@typescript-eslint/eslint-plugin@6.1.0)(eslint@7.24.0)(typescript@5.1.3): + /eslint-plugin-jest@24.3.5(@typescript-eslint/eslint-plugin@6.1.0)(eslint@7.24.0)(typescript@5.2.2): resolution: {integrity: sha512-XG4rtxYDuJykuqhsOqokYIR84/C8pRihRtEpVskYLbIIKGwPNW2ySxdctuVzETZE+MbF/e7wmsnbNVpzM0rDug==} engines: {node: '>=10'} peerDependencies: @@ -13257,8 +13246,8 @@ packages: '@typescript-eslint/eslint-plugin': optional: true dependencies: - '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.1.0)(eslint@7.24.0)(typescript@5.1.3) - '@typescript-eslint/experimental-utils': 4.29.1(eslint@7.24.0)(typescript@5.1.3) + '@typescript-eslint/eslint-plugin': 6.1.0(@typescript-eslint/parser@6.1.0)(eslint@7.24.0)(typescript@5.2.2) + '@typescript-eslint/experimental-utils': 4.29.1(eslint@7.24.0)(typescript@5.2.2) eslint: 7.24.0 transitivePeerDependencies: - supports-color @@ -15331,6 +15320,10 @@ packages: resolution: {integrity: sha512-tWCK4biJ6hcLqTviLXVR9DTRfYGQMXEIUj3gwJ2rZ5wO/at3XtkI4g8mCvFdUF9l1KMBNCfmNAdnahm1cgavQA==} dev: true + /headers-polyfill@3.2.3: + resolution: {integrity: sha512-oj6MO8sdFQ9gQQedSVdMGh96suxTNp91vPQu7C4qx/57FqYsA5TiNr92nhIZwVQq8zygn4nu3xS1aEqpakGqdw==} + dev: true + /hex-color-regex@1.1.0: resolution: {integrity: sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ==} dev: true @@ -19487,13 +19480,13 @@ packages: isarray: 1.0.0 dev: true - /msw@1.2.2(typescript@5.1.3): - resolution: {integrity: sha512-GsW3PE/Es/a1tYThXcM8YHOZ1S1MtivcS3He/LQbbTCx3rbWJYCtWD5XXyJ53KlNPT7O1VI9sCW3xMtgFe8XpQ==} + /msw@1.3.0(typescript@5.2.2): + resolution: {integrity: sha512-nnWAZlQyQOKeYRblCpseT1kSPt1aF5e/jHz1hn/18IxbsMFreSVV1cJriT0uV+YG6+wvwFRMHXU3zVuMvuwERQ==} engines: {node: '>=14'} hasBin: true requiresBuild: true peerDependencies: - typescript: '>= 4.4.x <= 5.1.x' + typescript: '>= 4.4.x <= 5.2.x' peerDependenciesMeta: typescript: optional: true @@ -19503,11 +19496,11 @@ packages: '@open-draft/until': 1.0.3 '@types/cookie': 0.4.1 '@types/js-levenshtein': 1.1.1 - chalk: 4.1.1 + chalk: 4.1.2 chokidar: 3.5.3 cookie: 0.4.2 graphql: 16.7.1 - headers-polyfill: 3.1.2 + headers-polyfill: 3.2.3 inquirer: 8.2.0 is-node-process: 1.2.0 js-levenshtein: 1.1.6 @@ -19516,7 +19509,7 @@ packages: path-to-regexp: 6.2.1 strict-event-emitter: 0.4.6 type-fest: 2.19.0 - typescript: 5.1.3 + typescript: 5.2.2 yargs: 17.5.1 transitivePeerDependencies: - encoding @@ -25709,13 +25702,13 @@ packages: typescript: 4.8.2 dev: false - /ts-api-utils@1.0.1(typescript@5.1.3): + /ts-api-utils@1.0.1(typescript@5.2.2): resolution: {integrity: sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==} engines: {node: '>=16.13.0'} peerDependencies: typescript: '>=4.2.0' dependencies: - typescript: 5.1.3 + typescript: 5.2.2 dev: true /tsconfig-paths@3.14.1: @@ -25736,7 +25729,7 @@ packages: strip-bom: 3.0.0 dev: false - /tsec@0.2.1(@bazel/bazelisk@1.12.1)(typescript@5.1.3): + /tsec@0.2.1(@bazel/bazelisk@1.12.1)(typescript@5.2.2): resolution: {integrity: sha512-RP9vhbRbRI9VH4CfOlQvo5W9HdfiPKq0gdiUOWI5oKmLaZKNFN8CsPwBfT5ySmhnKNwmmAS/BtY3WoTfABwwig==} hasBin: true peerDependencies: @@ -25746,7 +25739,7 @@ packages: '@bazel/bazelisk': 1.12.1 glob: 7.2.0 minimatch: 3.1.2 - typescript: 5.1.3 + typescript: 5.2.2 dev: true /tslib@1.11.1: @@ -25766,14 +25759,14 @@ packages: /tslib@2.5.3: resolution: {integrity: sha512-mSxlJJwl3BMEQCUNnxXBU9jP4JBktcEGhURcPR6VQVlnP0FdDEsIaz0C35dXNGLyRfrATNofF0F5p2KPxQgB+w==} - /tsutils@3.21.0(typescript@5.1.3): + /tsutils@3.21.0(typescript@5.2.2): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.11.1 - typescript: 5.1.3 + typescript: 5.2.2 dev: true /tty-browserify@0.0.1: @@ -25976,8 +25969,8 @@ packages: engines: {node: '>=4.2.0'} hasBin: true - /typescript@5.1.3: - resolution: {integrity: sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw==} + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} engines: {node: '>=14.17'} hasBin: true dev: true diff --git a/scripts/minimal-server.js b/scripts/minimal-server.js index 08f9125a4f0cc..f4f30ac97ce25 100644 --- a/scripts/minimal-server.js +++ b/scripts/minimal-server.js @@ -1,4 +1,3 @@ -console.time('next-wall-time') // Usage: node scripts/minimal-server.js // This script is used to run a minimal Next.js server in production mode. @@ -45,13 +44,11 @@ if (process.env.LOG_READFILE) { require('fs').readFile = function (path, options, callback) { readFileCount++ - console.log(`readFile: ${path}`) return originalReadFile.apply(this, arguments) } require('fs').readFileSync = function (path, options) { readFileSyncCount++ - console.log(`readFileSync: ${path}`) return originalReadFileSync.apply(this, arguments) } } @@ -59,9 +56,10 @@ if (process.env.LOG_READFILE) { console.time('next-cold-start') const NextServer = process.env.USE_BUNDLED_NEXT - ? require('next/dist/compiled/next-server/server.runtime.prod').default + ? require('next/dist/compiled/minimal-next-server/next-server-cached').default : require('next/dist/server/next-server').default +console.timeEnd('next-cold-start') if (process.env.LOG_READFILE) { console.log(`readFileCount: ${readFileCount + readFileSyncCount}`) } @@ -103,20 +101,9 @@ require('http') if (process.env.LOG_READFILE) { console.log(`readFileCount: ${readFileCount + readFileSyncCount}`) } + require('process').exit(0) }) }) .listen(3000, () => { console.timeEnd('next-cold-start') - fetch('http://localhost:3000/') - .then((res) => res.text()) - .then((text) => { - console.log(text) - }) - .catch((err) => { - console.error(err) - }) - .finally(() => { - console.timeEnd('next-wall-time') - require('process').exit(0) - }) }) diff --git a/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts b/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts index 3e5e6b82ea050..a61e222c3872e 100644 --- a/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts +++ b/test/e2e/app-dir/actions/app-action-size-limit-invalid.test.ts @@ -113,7 +113,7 @@ createNextDescribe( await check(() => { const fullLog = logs.join('') - return fullLog.includes('[Error]: Body exceeded 1.5mb limit') && + return fullLog.includes('Error: Body exceeded 1.5mb limit') && fullLog.includes( 'To configure the body size limit for Server Actions, see' ) diff --git a/test/e2e/app-dir/navigation/app/mpa-nav-test/page.js b/test/e2e/app-dir/navigation/app/mpa-nav-test/page.js new file mode 100644 index 0000000000000..9a335e2d0995c --- /dev/null +++ b/test/e2e/app-dir/navigation/app/mpa-nav-test/page.js @@ -0,0 +1,38 @@ +'use client' +import Link from 'next/link' +import { useEffect, useRef } from 'react' + +export default function Page() { + const prefetchRef = useRef() + const slowPageRef = useRef() + + useEffect(() => { + function triggerPrefetch() { + const event = new MouseEvent('mouseover', { + view: window, + bubbles: true, + cancelable: true, + }) + + prefetchRef.current.dispatchEvent(event) + console.log('dispatched') + } + + slowPageRef.current.click() + + setInterval(() => { + triggerPrefetch() + }, 1000) + }, []) + + return ( + <> + + To /slow-page + + + Prefetch link + + + ) +} diff --git a/test/e2e/app-dir/navigation/navigation.test.ts b/test/e2e/app-dir/navigation/navigation.test.ts index 67beabf483fe3..b3e1cf19c4261 100644 --- a/test/e2e/app-dir/navigation/navigation.test.ts +++ b/test/e2e/app-dir/navigation/navigation.test.ts @@ -1,5 +1,5 @@ import { createNextDescribe } from 'e2e-utils' -import { check } from 'next-test-utils' +import { check, waitFor } from 'next-test-utils' import type { Request } from 'playwright-chromium' createNextDescribe( @@ -497,6 +497,33 @@ createNextDescribe( .waitForElementByCss('#link-to-app') expect(await browser.url()).toBe(next.url + '/some') }) + + if (!isNextDev) { + // this test is pretty hard to test in playwright, so most of the heavy lifting is in the page component itself + // it triggers a hover on a link to initiate a prefetch request every second, and so we check that + // it doesn't repeatedly initiate the mpa navigation request + it('should not continously initiate a mpa navigation to the same URL when router state changes', async () => { + let requestCount = 0 + const browser = await next.browser('/mpa-nav-test', { + beforePageLoad(page) { + page.on('request', (request) => { + const url = new URL(request.url()) + // skip rsc prefetches + if (url.pathname === '/slow-page' && !url.search) { + requestCount++ + } + }) + }, + }) + + await browser.waitForElementByCss('#link-to-slow-page') + + // wait a few seconds since prefetches are triggered in 1s intervals in the page component + await waitFor(5000) + + expect(requestCount).toBe(1) + }) + } }) describe('nested navigation', () => { @@ -562,7 +589,7 @@ createNextDescribe( ) }) - it('should emit refresh meta tag (peramnent) for redirect page when streaming', async () => { + it('should emit refresh meta tag (permanent) for redirect page when streaming', async () => { const html = await next.render('/redirect/suspense-2') expect(html).toContain( '' diff --git a/test/e2e/app-dir/navigation/pages/slow-page.js b/test/e2e/app-dir/navigation/pages/slow-page.js new file mode 100644 index 0000000000000..ad37357cb6dcf --- /dev/null +++ b/test/e2e/app-dir/navigation/pages/slow-page.js @@ -0,0 +1,13 @@ +export default function Page() { + return 'Hello from slow page' +} + +export async function getServerSideProps({ resolvedUrl }) { + if (!resolvedUrl.includes('?_rsc')) { + // only stall on the navigation, not prefetch + await new Promise((resolve) => setTimeout(resolve, 100000)) + } + return { + props: {}, + } +} diff --git a/test/e2e/getserversideprops/app/pages/index.js b/test/e2e/getserversideprops/app/pages/index.js index da17edc01839d..4433c9c2ee84e 100644 --- a/test/e2e/getserversideprops/app/pages/index.js +++ b/test/e2e/getserversideprops/app/pages/index.js @@ -1,6 +1,6 @@ import Link from 'next/link' import ReactDOM from 'react-dom/server' -import { RouterContext } from 'next/dist/shared/lib/router-context.shared-runtime' +import { RouterContext } from 'next/dist/shared/lib/router-context' import { useRouter } from 'next/router' function RouterComp(props) { diff --git a/test/e2e/i18n-data-route/components/page.tsx b/test/e2e/i18n-data-route/components/page.tsx new file mode 100644 index 0000000000000..60418c58cba43 --- /dev/null +++ b/test/e2e/i18n-data-route/components/page.tsx @@ -0,0 +1,12 @@ +import React from 'react' + +export function Page({ page }) { + return

{page}

+} + +export function createGetServerSideProps(page: string) { + return async function getServerSideProps(ctx) { + const output = ctx.req.headers['x-invoke-output'] ?? null + return { props: { page, output } } + } +} diff --git a/test/e2e/i18n-data-route/i18n-data-route.test.ts b/test/e2e/i18n-data-route/i18n-data-route.test.ts new file mode 100644 index 0000000000000..1231f78f02670 --- /dev/null +++ b/test/e2e/i18n-data-route/i18n-data-route.test.ts @@ -0,0 +1,87 @@ +import { createNextDescribe } from 'e2e-utils' + +const { i18n } = require('./next.config') + +const pages = [ + { url: '/about', page: '/about', params: null }, + { url: '/blog/about', page: '/[slug]/about', params: { slug: 'blog' } }, +] + +function checkDataRoute(data: any, page: string) { + expect(data).toHaveProperty('pageProps') + expect(data.pageProps).toHaveProperty('page', page) + expect(data.pageProps).toHaveProperty('output', page) +} + +createNextDescribe( + 'i18n-data-route', + { + files: __dirname, + env: { + // Disable internal header stripping so we can test the invoke output. + __NEXT_NO_STRIP_INTERNAL_HEADERS: '1', + }, + }, + ({ next }) => { + describe('with locale prefix', () => { + describe.each(i18n.locales)('/%s', (locale) => { + const prefixed = pages.map((page) => ({ + ...page, + url: `/${locale}${page.url}`, + })) + + it.each(prefixed)( + 'should render $page via $url', + async ({ url, page }) => { + const $ = await next.render$(url) + expect($('[data-page]').data('page')).toBe(page) + } + ) + + it.each(prefixed)( + 'should serve data for $page', + async ({ url, page, params }) => { + url = `/_next/data/${next.buildId}${url}.json` + if (params) { + const query = new URLSearchParams(params) + // Ensure the query is sorted so it's deterministic. + query.sort() + url += `?${query.toString()}` + } + + const res = await next.fetch(url) + expect(res.status).toBe(200) + expect(res.headers.get('content-type')).toBe('application/json') + const data = await res.json() + checkDataRoute(data, page) + } + ) + }) + }) + + describe('without locale prefix', () => { + it.each(pages)('should render $page via $url', async ({ url, page }) => { + const $ = await next.render$(url) + expect($('[data-page]').data('page')).toBe(page) + }) + + it.each(pages)( + 'should serve data for $page', + async ({ url, page, params }) => { + url = `/_next/data/${next.buildId}/${i18n.defaultLocale}${url}.json` + if (params) { + const query = new URLSearchParams(params) + // Ensure the query is sorted so it's deterministic. + query.sort() + url += `?${query.toString()}` + } + const res = await next.fetch(url) + expect(res.status).toBe(200) + expect(res.headers.get('content-type')).toBe('application/json') + const data = await res.json() + checkDataRoute(data, page) + } + ) + }) + } +) diff --git a/test/e2e/i18n-data-route/next.config.js b/test/e2e/i18n-data-route/next.config.js new file mode 100644 index 0000000000000..32a015bd37ca9 --- /dev/null +++ b/test/e2e/i18n-data-route/next.config.js @@ -0,0 +1,9 @@ +/** + * @type {import('next').NextConfig} + */ +module.exports = { + i18n: { + locales: ['en-CA', 'fr-CA'], + defaultLocale: 'en-CA', + }, +} diff --git a/test/e2e/i18n-data-route/pages/[slug]/about/index.tsx b/test/e2e/i18n-data-route/pages/[slug]/about/index.tsx new file mode 100644 index 0000000000000..3c8a96c601f40 --- /dev/null +++ b/test/e2e/i18n-data-route/pages/[slug]/about/index.tsx @@ -0,0 +1,5 @@ +import { Page, createGetServerSideProps } from '../../../components/page' + +export default Page + +export const getServerSideProps = createGetServerSideProps('/[slug]/about') diff --git a/test/e2e/i18n-data-route/pages/about/index.tsx b/test/e2e/i18n-data-route/pages/about/index.tsx new file mode 100644 index 0000000000000..83ef2115f5326 --- /dev/null +++ b/test/e2e/i18n-data-route/pages/about/index.tsx @@ -0,0 +1,5 @@ +import { Page, createGetServerSideProps } from '../../components/page' + +export default Page + +export const getServerSideProps = createGetServerSideProps('/about') diff --git a/test/e2e/opentelemetry/opentelemetry.test.ts b/test/e2e/opentelemetry/opentelemetry.test.ts index 13e0fefea2787..ae798ec7c5c2d 100644 --- a/test/e2e/opentelemetry/opentelemetry.test.ts +++ b/test/e2e/opentelemetry/opentelemetry.test.ts @@ -77,80 +77,80 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.url": "https://vercel.com/", - "net.peer.name": "vercel.com", - "next.span_name": "fetch GET https://vercel.com/", - "next.span_type": "AppRender.fetch", - }, - "kind": 2, - "name": "fetch GET https://vercel.com/", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/app/[param]/rsc-fetch", - "next.span_name": "render route (app) /app/[param]/rsc-fetch", - "next.span_type": "AppRender.getBodyResult", - }, - "kind": 0, - "name": "render route (app) /app/[param]/rsc-fetch", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/app/[param]/rsc-fetch", - "http.status_code": 200, - "http.target": "/app/param/rsc-fetch", - "next.route": "/app/[param]/rsc-fetch", - "next.span_name": "GET /app/[param]/rsc-fetch", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /app/[param]/rsc-fetch", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.page": "/app/[param]/layout", - "next.span_name": "generateMetadata /app/[param]/layout", - "next.span_type": "ResolveMetadata.generateMetadata", - }, - "kind": 0, - "name": "generateMetadata /app/[param]/layout", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.page": "/app/[param]/rsc-fetch/page", - "next.span_name": "generateMetadata /app/[param]/rsc-fetch/page", - "next.span_type": "ResolveMetadata.generateMetadata", - }, - "kind": 0, - "name": "generateMetadata /app/[param]/rsc-fetch/page", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.url": "https://vercel.com/", + "net.peer.name": "vercel.com", + "next.span_name": "fetch GET https://vercel.com/", + "next.span_type": "AppRender.fetch", + }, + "kind": 2, + "name": "fetch GET https://vercel.com/", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/app/[param]/rsc-fetch", + "next.span_name": "render route (app) /app/[param]/rsc-fetch", + "next.span_type": "AppRender.getBodyResult", + }, + "kind": 0, + "name": "render route (app) /app/[param]/rsc-fetch", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/app/[param]/rsc-fetch", + "http.status_code": 200, + "http.target": "/app/param/rsc-fetch", + "next.route": "/app/[param]/rsc-fetch", + "next.span_name": "GET /app/[param]/rsc-fetch", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /app/[param]/rsc-fetch", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.page": "/app/[param]/layout", + "next.span_name": "generateMetadata /app/[param]/layout", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "kind": 0, + "name": "generateMetadata /app/[param]/layout", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.page": "/app/[param]/rsc-fetch/page", + "next.span_name": "generateMetadata /app/[param]/rsc-fetch/page", + "next.span_type": "ResolveMetadata.generateMetadata", + }, + "kind": 0, + "name": "generateMetadata /app/[param]/rsc-fetch/page", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -160,39 +160,37 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "next.route": "/api/app/[param]/data/route", - "next.span_name": "executing api route (app) /api/app/[param]/data/route", - "next.span_type": "AppRouteRouteHandlers.runHandler", - }, - "kind": 0, - "name": "executing api route (app) /api/app/[param]/data/route", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, + Array [ + Object { + "attributes": Object { + "next.route": "/api/app/[param]/data/route", + "next.span_name": "executing api route (app) /api/app/[param]/data/route", + "next.span_type": "AppRouteRouteHandlers.runHandler", + }, + "kind": 0, + "name": "executing api route (app) /api/app/[param]/data/route", + "parentId": "[parent-id]", + "status": Object { + "code": 0, }, - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/api/app/[param]/data/route", - "http.status_code": 200, - "http.target": "/api/app/param/data", - "next.route": "/api/app/[param]/data/route", - "next.span_name": "GET /api/app/[param]/data/route", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /api/app/[param]/data/route", - "parentId": undefined, - "status": Object { - "code": 0, - }, + }, + Object { + "attributes": Object { + "http.method": "GET", + "http.status_code": 200, + "http.target": "/api/app/param/data", + "next.span_name": "GET /api/app/param/data", + "next.span_type": "BaseServer.handleRequest", }, - ] - `) + "kind": 1, + "name": "GET /api/app/param/data", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -204,52 +202,52 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/pages/[param]/getServerSideProps", - "http.status_code": 200, - "http.target": "/pages/param/getServerSideProps", - "next.route": "/pages/[param]/getServerSideProps", - "next.span_name": "GET /pages/[param]/getServerSideProps", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /pages/[param]/getServerSideProps", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getServerSideProps", - "next.span_name": "getServerSideProps /pages/[param]/getServerSideProps", - "next.span_type": "Render.getServerSideProps", - }, - "kind": 0, - "name": "getServerSideProps /pages/[param]/getServerSideProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getServerSideProps", - "next.span_name": "render route (pages) /pages/[param]/getServerSideProps", - "next.span_type": "Render.renderDocument", - }, - "kind": 0, - "name": "render route (pages) /pages/[param]/getServerSideProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/pages/[param]/getServerSideProps", + "http.status_code": 200, + "http.target": "/pages/param/getServerSideProps", + "next.route": "/pages/[param]/getServerSideProps", + "next.span_name": "GET /pages/[param]/getServerSideProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/[param]/getServerSideProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getServerSideProps", + "next.span_name": "getServerSideProps /pages/[param]/getServerSideProps", + "next.span_type": "Render.getServerSideProps", + }, + "kind": 0, + "name": "getServerSideProps /pages/[param]/getServerSideProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getServerSideProps", + "next.span_name": "render route (pages) /pages/[param]/getServerSideProps", + "next.span_type": "Render.renderDocument", + }, + "kind": 0, + "name": "render route (pages) /pages/[param]/getServerSideProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -259,52 +257,52 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/pages/[param]/getStaticProps", - "http.status_code": 200, - "http.target": "/pages/param/getStaticProps", - "next.route": "/pages/[param]/getStaticProps", - "next.span_name": "GET /pages/[param]/getStaticProps", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /pages/[param]/getStaticProps", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getStaticProps", - "next.span_name": "getStaticProps /pages/[param]/getStaticProps", - "next.span_type": "Render.getStaticProps", - }, - "kind": 0, - "name": "getStaticProps /pages/[param]/getStaticProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.route": "/pages/[param]/getStaticProps", - "next.span_name": "render route (pages) /pages/[param]/getStaticProps", - "next.span_type": "Render.renderDocument", - }, - "kind": 0, - "name": "render route (pages) /pages/[param]/getStaticProps", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/pages/[param]/getStaticProps", + "http.status_code": 200, + "http.target": "/pages/param/getStaticProps", + "next.route": "/pages/[param]/getStaticProps", + "next.span_name": "GET /pages/[param]/getStaticProps", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /pages/[param]/getStaticProps", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getStaticProps", + "next.span_name": "getStaticProps /pages/[param]/getStaticProps", + "next.span_type": "Render.getStaticProps", + }, + "kind": 0, + "name": "getStaticProps /pages/[param]/getStaticProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.route": "/pages/[param]/getStaticProps", + "next.span_name": "render route (pages) /pages/[param]/getStaticProps", + "next.span_type": "Render.renderDocument", + }, + "kind": 0, + "name": "render route (pages) /pages/[param]/getStaticProps", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) @@ -314,38 +312,38 @@ createNextDescribe( await check(async () => { expect(await getSanitizedTraces(1)).toMatchInlineSnapshot(` - Array [ - Object { - "attributes": Object { - "http.method": "GET", - "http.route": "/api/pages/[param]/basic", - "http.status_code": 200, - "http.target": "/api/pages/param/basic", - "next.route": "/api/pages/[param]/basic", - "next.span_name": "GET /api/pages/[param]/basic", - "next.span_type": "BaseServer.handleRequest", - }, - "kind": 1, - "name": "GET /api/pages/[param]/basic", - "parentId": undefined, - "status": Object { - "code": 0, - }, - }, - Object { - "attributes": Object { - "next.span_name": "executing api route (pages) /api/pages/[param]/basic", - "next.span_type": "Node.runHandler", - }, - "kind": 0, - "name": "executing api route (pages) /api/pages/[param]/basic", - "parentId": "[parent-id]", - "status": Object { - "code": 0, - }, - }, - ] - `) + Array [ + Object { + "attributes": Object { + "http.method": "GET", + "http.route": "/api/pages/[param]/basic", + "http.status_code": 200, + "http.target": "/api/pages/param/basic", + "next.route": "/api/pages/[param]/basic", + "next.span_name": "GET /api/pages/[param]/basic", + "next.span_type": "BaseServer.handleRequest", + }, + "kind": 1, + "name": "GET /api/pages/[param]/basic", + "parentId": undefined, + "status": Object { + "code": 0, + }, + }, + Object { + "attributes": Object { + "next.span_name": "executing api route (pages) /api/pages/[param]/basic", + "next.span_type": "Node.runHandler", + }, + "kind": 0, + "name": "executing api route (pages) /api/pages/[param]/basic", + "parentId": "[parent-id]", + "status": Object { + "code": 0, + }, + }, + ] + `) return 'success' }, 'success') }) diff --git a/test/e2e/prerender-native-module.test.ts b/test/e2e/prerender-native-module.test.ts index 34adb36ce5bd8..c23b1d2d05cd0 100644 --- a/test/e2e/prerender-native-module.test.ts +++ b/test/e2e/prerender-native-module.test.ts @@ -85,6 +85,8 @@ describe('prerender native module', () => { /node_modules\/sqlite3\/.*?\.node/, /node_modules\/sqlite\/.*?\.js/, /node_modules\/next/, + /next\/router\.js/, + /next\/dist\/client\/router\.js/, /\/data\.sqlite/, ], notTests: [], @@ -97,6 +99,7 @@ describe('prerender native module', () => { ) const { version, files } = JSON.parse(contents) expect(version).toBe(1) + expect( check.tests.every((item) => files.some((file) => item.test(file))) ).toBe(true) diff --git a/test/e2e/prerender.test.ts b/test/e2e/prerender.test.ts index 1ff677e583b15..f21b4224fe236 100644 --- a/test/e2e/prerender.test.ts +++ b/test/e2e/prerender.test.ts @@ -2070,6 +2070,7 @@ describe('Prerender', () => { /node_modules\/react\/index\.js/, /node_modules\/react\/package\.json/, /node_modules\/react\/cjs\/react\.production\.min\.js/, + /node_modules\/next/, ], notTests: [], }, @@ -2081,6 +2082,7 @@ describe('Prerender', () => { /node_modules\/react\/index\.js/, /node_modules\/react\/package\.json/, /node_modules\/react\/cjs\/react\.production\.min\.js/, + /node_modules\/next/, /\/world.txt/, ], notTests: [ @@ -2096,6 +2098,9 @@ describe('Prerender', () => { /node_modules\/react\/index\.js/, /node_modules\/react\/package\.json/, /node_modules\/react\/cjs\/react\.production\.min\.js/, + /node_modules\/next/, + /next\/router\.js/, + /next\/dist\/client\/router\.js/, /node_modules\/@firebase\/firestore\/.*?\.js/, ], notTests: [/\/world.txt/], diff --git a/test/integration/externalize-next-server/app/node_modules/comps/index.js b/test/integration/externalize-next-server/app/node_modules/comps/index.js new file mode 100644 index 0000000000000..74c3153f1b835 --- /dev/null +++ b/test/integration/externalize-next-server/app/node_modules/comps/index.js @@ -0,0 +1,5 @@ +const react = require('react') + +module.exports = function() { + return react.createElement('p', null, 'MyComp:', typeof window) +} diff --git a/test/integration/externalize-next-server/app/node_modules/comps/package.json b/test/integration/externalize-next-server/app/node_modules/comps/package.json new file mode 100644 index 0000000000000..6e665b646a6ad --- /dev/null +++ b/test/integration/externalize-next-server/app/node_modules/comps/package.json @@ -0,0 +1,6 @@ +{ + "name": "comps", + "version": "1.0.0", + "main": "index.js", + "license": "MIT" +} diff --git a/test/integration/externalize-next-server/app/package.json b/test/integration/externalize-next-server/app/package.json new file mode 100644 index 0000000000000..c5bd706a3a950 --- /dev/null +++ b/test/integration/externalize-next-server/app/package.json @@ -0,0 +1,6 @@ +{ + "name": "externalize-next-server-app", + "version": "1.0.0", + "main": "index.js", + "license": "MIT" +} diff --git a/test/integration/externalize-next-server/app/pages/index.js b/test/integration/externalize-next-server/app/pages/index.js new file mode 100644 index 0000000000000..9ceb7bee3db17 --- /dev/null +++ b/test/integration/externalize-next-server/app/pages/index.js @@ -0,0 +1,12 @@ +import MyComp from 'comps' + +const Page = () => ( + <> +

Hello {typeof window}

+ + +) + +Page.getInitialProps = () => ({}) + +export default Page diff --git a/test/integration/externalize-next-server/test/index.test.js b/test/integration/externalize-next-server/test/index.test.js new file mode 100644 index 0000000000000..bba968de16585 --- /dev/null +++ b/test/integration/externalize-next-server/test/index.test.js @@ -0,0 +1,19 @@ +/* eslint-env jest */ +import path from 'path' +import { nextBuild, readNextBuildServerPageFile } from 'next-test-utils' + +const appDir = path.join(__dirname, '../app') + +describe('externalize next/dist/shared', () => { + beforeAll(async () => { + await nextBuild(appDir) + }) + + it('Bundle next/dist/shared/lib/head.js but not next/dist/shared/lib/head-manager-context.js in _error', async () => { + const content = readNextBuildServerPageFile(appDir, '/_error') + expect(content).toContain( + `require("next/dist/shared/lib/head-manager-context.js")` + ) + expect(content).not.toContain(`require("next/dist/shared/lib/head.js")`) + }) +}) diff --git a/test/integration/jsconfig-baseurl/test/index.test.js b/test/integration/jsconfig-baseurl/test/index.test.js index 4ad014d0e8f03..91f084ce1d55e 100644 --- a/test/integration/jsconfig-baseurl/test/index.test.js +++ b/test/integration/jsconfig-baseurl/test/index.test.js @@ -72,6 +72,12 @@ describe('TypeScript Features', () => { const helloTrace = await fs.readJSON( join(appDir, '.next/server/pages/hello.js.nft.json') ) + const appTrace = await fs.readJSON( + join(appDir, '.next/server/pages/_app.js.nft.json') + ) + expect( + appTrace.files.some((file) => file.includes('node_modules/next')) + ).toBe(true) expect( helloTrace.files.some((file) => file.includes('components/world.js')) ).toBe(false) diff --git a/test/integration/jsconfig-paths/test/index.test.js b/test/integration/jsconfig-paths/test/index.test.js index bc3c635b9ce96..77c84e7edfbb4 100644 --- a/test/integration/jsconfig-paths/test/index.test.js +++ b/test/integration/jsconfig-paths/test/index.test.js @@ -89,6 +89,9 @@ function runTests() { await nextBuild(appDir) }) it('should trace correctly', async () => { + const appTrace = await fs.readJSON( + join(appDir, '.next/server/pages/_app.js.nft.json') + ) const singleAliasTrace = await fs.readJSON( join(appDir, '.next/server/pages/single-alias.js.nft.json') ) @@ -104,7 +107,9 @@ function runTests() { const basicAliasTrace = await fs.readJSON( join(appDir, '.next/server/pages/basic-alias.js.nft.json') ) - + expect( + appTrace.files.some((file) => file.includes('node_modules/next')) + ).toBe(true) expect( singleAliasTrace.files.some((file) => file.includes('components/hello.js') diff --git a/test/integration/tsconfig-verifier/test/index.test.js b/test/integration/tsconfig-verifier/test/index.test.js index fdb648b46ee10..5102737198a85 100644 --- a/test/integration/tsconfig-verifier/test/index.test.js +++ b/test/integration/tsconfig-verifier/test/index.test.js @@ -298,7 +298,7 @@ describe('tsconfig.json verifier', () => { await writeFile( tsConfig, - `{ "compilerOptions": { "esModuleInterop": false, "moduleResolution": "node16" } }` + `{ "compilerOptions": { "esModuleInterop": false, "moduleResolution": "node16", "module": "node16" } }` ) await new Promise((resolve) => setTimeout(resolve, 500)) const { code, stderr, stdout } = await nextBuild(appDir, undefined, { @@ -313,6 +313,7 @@ describe('tsconfig.json verifier', () => { \\"compilerOptions\\": { \\"esModuleInterop\\": true, \\"moduleResolution\\": \\"node16\\", + \\"module\\": \\"node16\\", \\"lib\\": [ \\"dom\\", \\"dom.iterable\\", @@ -323,7 +324,6 @@ describe('tsconfig.json verifier', () => { \\"strict\\": false, \\"noEmit\\": true, \\"incremental\\": true, - \\"module\\": \\"esnext\\", \\"resolveJsonModule\\": true, \\"isolatedModules\\": true, \\"jsx\\": \\"preserve\\",