From 048ab21f6b033b2865353b236f52de7d48b44754 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Tue, 28 Nov 2023 04:54:46 -0800 Subject: [PATCH 001/189] fix(turbopack): treat .mdx as valid ecma asset (#58985) ### What Pairing with https://github.com/vercel/turbo/pull/6602, enables ecma-related transform support in mdx. notably fixes test cases in https://github.com/vercel/next.js/pull/58968 . With turbopack side fix, still modularize imports are not being applied as we limite it to .js* extension only. PR expands it to include mdx if mdx is enabled. PR is failling until turbopack side fix lands. Closes PACK-2045 --------- Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- Cargo.lock | 68 +++++++++---------- Cargo.toml | 6 +- .../next-core/src/next_client/transforms.rs | 18 +++-- .../next-core/src/next_server/context.rs | 4 +- .../next-core/src/next_server/transforms.rs | 33 ++++++--- .../src/next_shared/transforms/mod.rs | 26 +++++-- .../transforms/modularize_imports.rs | 3 +- .../next_shared/transforms/next_dynamic.rs | 3 +- .../src/next_shared/transforms/next_font.rs | 4 +- .../transforms/next_strip_page_exports.rs | 3 +- .../next_shared/transforms/server_actions.rs | 7 +- packages/next/package.json | 2 +- pnpm-lock.yaml | 10 +-- 13 files changed, 115 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9387dd7d74c70..456f2d6b7660a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "serde", "smallvec", @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "serde", @@ -7678,7 +7678,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-trait", @@ -7710,7 +7710,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "cargo-lock", @@ -7722,7 +7722,7 @@ dependencies = [ [[package]] name = "turbo-tasks-bytes" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "bytes", @@ -7737,7 +7737,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "dotenvs", @@ -7751,7 +7751,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7768,7 +7768,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "auto-hash-map", @@ -7798,7 +7798,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "base16", "hex", @@ -7810,7 +7810,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -7824,7 +7824,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "proc-macro2", "quote", @@ -7834,7 +7834,7 @@ dependencies = [ [[package]] name = "turbo-tasks-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "mimalloc", ] @@ -7842,7 +7842,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "auto-hash-map", @@ -7867,7 +7867,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-recursion", @@ -7898,7 +7898,7 @@ dependencies = [ [[package]] name = "turbopack-binding" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "auto-hash-map", "mdxjs", @@ -7939,7 +7939,7 @@ dependencies = [ [[package]] name = "turbopack-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7962,7 +7962,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "clap 4.4.2", @@ -7980,7 +7980,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-recursion", @@ -8010,7 +8010,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-trait", @@ -8036,7 +8036,7 @@ dependencies = [ [[package]] name = "turbopack-dev" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8060,7 +8060,7 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-compression", @@ -8097,7 +8097,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-trait", @@ -8131,7 +8131,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-hmr-protocol" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "serde", "serde_json", @@ -8142,7 +8142,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-plugins" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-trait", @@ -8165,7 +8165,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-runtime" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "indoc", @@ -8182,7 +8182,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8198,7 +8198,7 @@ dependencies = [ [[package]] name = "turbopack-image" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "base64 0.21.4", @@ -8218,7 +8218,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "serde", @@ -8233,7 +8233,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "mdxjs", @@ -8248,7 +8248,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "async-stream", @@ -8283,7 +8283,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "serde", @@ -8299,7 +8299,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "swc_core", "turbo-tasks", @@ -8310,7 +8310,7 @@ dependencies = [ [[package]] name = "turbopack-trace-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "crossbeam-channel", @@ -8325,7 +8325,7 @@ dependencies = [ [[package]] name = "turbopack-wasm" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.3#cb1496ca9ee93f5270041e4988080c2eb52b0e35" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" dependencies = [ "anyhow", "indexmap 1.9.3", diff --git a/Cargo.toml b/Cargo.toml index 4c7e71f5b53d9..4a27aa315019c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,11 +43,11 @@ swc_core = { version = "0.86.81", features = [ testing = { version = "0.35.11" } # Turbo crates -turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.3" } +turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.4" } # [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros.. -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.3" } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.4" } # [TODO]: need to refactor embed_directory! macro usage in next-core -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.3" } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.4" } # General Deps diff --git a/packages/next-swc/crates/next-core/src/next_client/transforms.rs b/packages/next-swc/crates/next-core/src/next_client/transforms.rs index b387763cf01fb..ef849c32cbcc7 100644 --- a/packages/next-swc/crates/next-core/src/next_client/transforms.rs +++ b/packages/next-swc/crates/next-core/src/next_client/transforms.rs @@ -25,26 +25,34 @@ pub async fn get_next_client_transforms_rules( let modularize_imports_config = &next_config.await?.modularize_imports; if let Some(modularize_imports_config) = modularize_imports_config { - rules.push(get_next_modularize_imports_rule(modularize_imports_config)); + rules.push(get_next_modularize_imports_rule( + modularize_imports_config, + *next_config.mdx_rs().await?, + )); } - rules.push(get_next_font_transform_rule()); + let mdx_rs = *next_config.mdx_rs().await?; + rules.push(get_next_font_transform_rule(mdx_rs)); let pages_dir = match context_ty { ClientContextType::Pages { pages_dir } => { rules.push( - get_next_pages_transforms_rule(pages_dir, ExportFilter::StripDataExports).await?, + get_next_pages_transforms_rule(pages_dir, ExportFilter::StripDataExports, mdx_rs) + .await?, ); Some(pages_dir) } ClientContextType::App { .. } => { - rules.push(get_server_actions_transform_rule(ActionsTransform::Client)); + rules.push(get_server_actions_transform_rule( + ActionsTransform::Client, + mdx_rs, + )); None } ClientContextType::Fallback | ClientContextType::Other => None, }; - rules.push(get_next_dynamic_transform_rule(false, false, pages_dir, mode).await?); + rules.push(get_next_dynamic_transform_rule(false, false, pages_dir, mode, mdx_rs).await?); rules.push(get_next_image_rule()); 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 9bf41b1a9e9ee..02e3adbb12edd 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 @@ -255,7 +255,9 @@ pub async fn get_server_module_options_context( next_config: Vc, ) -> Result> { let custom_rules = get_next_server_transforms_rules(next_config, ty.into_value(), mode).await?; - let internal_custom_rules = get_next_server_internal_transforms_rules(ty.into_value()).await?; + let internal_custom_rules = + get_next_server_internal_transforms_rules(ty.into_value(), *next_config.mdx_rs().await?) + .await?; let foreign_code_context_condition = foreign_code_context_condition(next_config, project_path).await?; diff --git a/packages/next-swc/crates/next-core/src/next_server/transforms.rs b/packages/next-swc/crates/next-core/src/next_server/transforms.rs index c939e0ed5e385..61e48d91c6851 100644 --- a/packages/next-swc/crates/next-core/src/next_server/transforms.rs +++ b/packages/next-swc/crates/next-core/src/next_server/transforms.rs @@ -25,10 +25,14 @@ pub async fn get_next_server_transforms_rules( let mut rules = vec![]; let modularize_imports_config = &next_config.await?.modularize_imports; + let mdx_rs = *next_config.mdx_rs().await?; if let Some(modularize_imports_config) = modularize_imports_config { - rules.push(get_next_modularize_imports_rule(modularize_imports_config)); + rules.push(get_next_modularize_imports_rule( + modularize_imports_config, + mdx_rs, + )); } - rules.push(get_next_font_transform_rule()); + rules.push(get_next_font_transform_rule(mdx_rs)); let (is_server_components, pages_dir) = match context_ty { ServerContextType::Pages { pages_dir } | ServerContextType::PagesApi { pages_dir } => { @@ -36,19 +40,26 @@ pub async fn get_next_server_transforms_rules( } ServerContextType::PagesData { pages_dir } => { rules.push( - get_next_pages_transforms_rule(pages_dir, ExportFilter::StripDefaultExport).await?, + get_next_pages_transforms_rule(pages_dir, ExportFilter::StripDefaultExport, mdx_rs) + .await?, ); (false, Some(pages_dir)) } ServerContextType::AppSSR { .. } => { // Yah, this is SSR, but this is still treated as a Client transform layer. - rules.push(get_server_actions_transform_rule(ActionsTransform::Client)); + rules.push(get_server_actions_transform_rule( + ActionsTransform::Client, + mdx_rs, + )); (false, None) } ServerContextType::AppRSC { client_transition, .. } => { - rules.push(get_server_actions_transform_rule(ActionsTransform::Server)); + rules.push(get_server_actions_transform_rule( + ActionsTransform::Server, + mdx_rs, + )); if let Some(client_transition) = client_transition { rules.push(get_next_css_client_reference_transforms_rule( client_transition, @@ -60,7 +71,10 @@ pub async fn get_next_server_transforms_rules( ServerContextType::Middleware { .. } => (false, None), }; - rules.push(get_next_dynamic_transform_rule(true, is_server_components, pages_dir, mode).await?); + rules.push( + get_next_dynamic_transform_rule(true, is_server_components, pages_dir, mode, mdx_rs) + .await?, + ); rules.push(get_next_image_rule()); @@ -71,23 +85,24 @@ pub async fn get_next_server_transforms_rules( /// transforms, but which are only applied to internal modules. pub async fn get_next_server_internal_transforms_rules( context_ty: ServerContextType, + mdx_rs: bool, ) -> Result> { let mut rules = vec![]; match context_ty { ServerContextType::Pages { .. } => { // Apply next/font transforms to foreign code - rules.push(get_next_font_transform_rule()); + rules.push(get_next_font_transform_rule(mdx_rs)); } ServerContextType::PagesApi { .. } => {} ServerContextType::PagesData { .. } => {} ServerContextType::AppSSR { .. } => { - rules.push(get_next_font_transform_rule()); + rules.push(get_next_font_transform_rule(mdx_rs)); } ServerContextType::AppRSC { client_transition, .. } => { - rules.push(get_next_font_transform_rule()); + rules.push(get_next_font_transform_rule(mdx_rs)); if let Some(client_transition) = client_transition { rules.push(get_next_css_client_reference_transforms_rule( client_transition, diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs index 49c4fe4320894..ca47788165365 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs @@ -56,16 +56,28 @@ pub fn get_next_image_rule() -> ModuleRule { } /// Returns a rule which applies the Next.js dynamic transform. -pub(crate) fn module_rule_match_js_no_url() -> ModuleRuleCondition { +pub(crate) fn module_rule_match_js_no_url(enable_mdx_rs: bool) -> ModuleRuleCondition { + let mut conditions = vec![ + ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), + ]; + + if enable_mdx_rs { + conditions.append( + vec![ + ModuleRuleCondition::ResourcePathEndsWith(".md".to_string()), + ModuleRuleCondition::ResourcePathEndsWith(".mdx".to_string()), + ] + .as_mut(), + ); + } + ModuleRuleCondition::all(vec![ ModuleRuleCondition::not(ModuleRuleCondition::ReferenceType(ReferenceType::Url( UrlReferenceSubType::Undefined, ))), - ModuleRuleCondition::any(vec![ - ModuleRuleCondition::ResourcePathEndsWith(".js".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".jsx".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".ts".to_string()), - ModuleRuleCondition::ResourcePathEndsWith(".tsx".to_string()), - ]), + ModuleRuleCondition::any(conditions), ]) } diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/modularize_imports.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/modularize_imports.rs index ada8add3ef787..33f452726b3d1 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/modularize_imports.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/modularize_imports.rs @@ -44,12 +44,13 @@ pub enum Transform { /// Returns a rule which applies the Next.js modularize imports transform. pub fn get_next_modularize_imports_rule( modularize_imports_config: &IndexMap, + enable_mdx_rs: bool, ) -> ModuleRule { let transformer = EcmascriptInputTransform::Plugin(Vc::cell(Box::new( ModularizeImportsTransformer::new(modularize_imports_config), ) as _)); ModuleRule::new( - module_rule_match_js_no_url(), + module_rule_match_js_no_url(enable_mdx_rs), vec![ModuleRuleEffect::AddEcmascriptTransforms(Vc::cell(vec![ transformer, ]))], diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/next_dynamic.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/next_dynamic.rs index 468f55085114c..e5153d8f63e93 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/next_dynamic.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/next_dynamic.rs @@ -28,6 +28,7 @@ pub async fn get_next_dynamic_transform_rule( is_react_server_layer: bool, pages_dir: Option>, mode: NextMode, + enable_mdx_rs: bool, ) -> Result { let dynamic_transform = EcmascriptInputTransform::Plugin(Vc::cell(Box::new(NextJsDynamic { is_server_compiler, @@ -39,7 +40,7 @@ pub async fn get_next_dynamic_transform_rule( mode, }) as _)); Ok(ModuleRule::new( - module_rule_match_js_no_url(), + module_rule_match_js_no_url(enable_mdx_rs), vec![ModuleRuleEffect::AddEcmascriptTransforms(Vc::cell(vec![ dynamic_transform, ]))], diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/next_font.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/next_font.rs index 098bcbe266945..5285893ae6312 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/next_font.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/next_font.rs @@ -10,7 +10,7 @@ use turbopack_binding::turbopack::{ use super::module_rule_match_js_no_url; /// Returns a rule which applies the Next.js font transform. -pub fn get_next_font_transform_rule() -> ModuleRule { +pub fn get_next_font_transform_rule(enable_mdx_rs: bool) -> ModuleRule { let font_loaders = vec![ "next/font/google".into(), "@next/font/google".into(), @@ -22,7 +22,7 @@ pub fn get_next_font_transform_rule() -> ModuleRule { EcmascriptInputTransform::Plugin(Vc::cell(Box::new(NextJsFont { font_loaders }) as _)); ModuleRule::new( // TODO: Only match in pages (not pages/api), app/, etc. - module_rule_match_js_no_url(), + module_rule_match_js_no_url(enable_mdx_rs), vec![ModuleRuleEffect::AddEcmascriptTransforms(Vc::cell(vec![ transformer, ]))], diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs index bc5be315ed17f..28fb090be92fc 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/next_strip_page_exports.rs @@ -23,6 +23,7 @@ use super::module_rule_match_js_no_url; pub async fn get_next_pages_transforms_rule( pages_dir: Vc, export_filter: ExportFilter, + enable_mdx_rs: bool, ) -> Result { // Apply the Next SSG transform to all pages. let strip_transform = EcmascriptInputTransform::Plugin(Vc::cell(Box::new( @@ -51,7 +52,7 @@ pub async fn get_next_pages_transforms_rule( ), ])), ]), - module_rule_match_js_no_url(), + module_rule_match_js_no_url(enable_mdx_rs), ]), vec![ModuleRuleEffect::AddEcmascriptTransforms(Vc::cell(vec![ strip_transform, diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/server_actions.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/server_actions.rs index a8cbfd14fa7c6..6f9a3f3c5e284 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/server_actions.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/server_actions.rs @@ -20,11 +20,14 @@ pub enum ActionsTransform { } /// Returns a rule which applies the Next.js Server Actions transform. -pub fn get_server_actions_transform_rule(transform: ActionsTransform) -> ModuleRule { +pub fn get_server_actions_transform_rule( + transform: ActionsTransform, + enable_mdx_rs: bool, +) -> ModuleRule { let transformer = EcmascriptInputTransform::Plugin(Vc::cell(Box::new(NextServerActions { transform }) as _)); ModuleRule::new( - module_rule_match_js_no_url(), + module_rule_match_js_no_url(enable_mdx_rs), vec![ModuleRuleEffect::AddEcmascriptTransforms(Vc::cell(vec![ transformer, ]))], diff --git a/packages/next/package.json b/packages/next/package.json index e4a3d8e3ceab9..e731ddb990437 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -195,7 +195,7 @@ "@types/ws": "8.2.0", "@vercel/ncc": "0.34.0", "@vercel/nft": "0.22.6", - "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.3", + "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4", "acorn": "8.5.0", "amphtml-validator": "1.0.35", "anser": "1.4.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b3618a13b5efe..b26b30f633c53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1074,8 +1074,8 @@ importers: specifier: 0.22.6 version: 0.22.6 '@vercel/turbopack-ecmascript-runtime': - specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.3 - version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.3(react-refresh@0.12.0)(webpack@5.86.0)' + specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4 + version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4(react-refresh@0.12.0)(webpack@5.86.0)' acorn: specifier: 8.5.0 version: 8.5.0 @@ -24648,9 +24648,9 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.3(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.3} - id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.3' + '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4(react-refresh@0.12.0)(webpack@5.86.0)': + resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4} + id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 dependencies: From cd66493749a9e76ab32913f839e56b9828b22523 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 28 Nov 2023 06:38:59 -0800 Subject: [PATCH 002/189] dedupe pending revalidation requests (#58990) ### What? We currently dedupe fetch requests, but if those fetch requests contain a `revalidate` time, when that window is expired all of those fetches will be invoked without deduping. ### Why? We track revalidations on the `staticGenerationStore` but we don't have a way to dedupe them, as it's currently just an array. When the (patched) fetch is invoked and catches a stale entry, it'll push each fetch onto the `pendingRevalidates` array which will later be invoked via `Promise.all`. ### How? This updates the shape of `pendingRevalidates` to be a map, that way we can reliably dedupe if we see a key that is already pending revalidation. Closes NEXT-1744 [slack x-ref](https://vercel.slack.com/archives/C03S8ED1DKM/p1700836529460289) --- ...tatic-generation-async-storage.external.ts | 2 +- .../src/server/app-render/action-handler.ts | 12 +++-- .../next/src/server/app-render/app-render.tsx | 2 +- .../future/route-modules/app-route/module.ts | 4 +- packages/next/src/server/lib/patch-fetch.ts | 9 ++-- .../web/spec-extension/revalidate-tag.ts | 8 ++-- .../web/spec-extension/unstable-cache.ts | 7 ++- .../app-fetch-deduping.test.ts | 44 ++++++++++++++++++- 8 files changed, 68 insertions(+), 20 deletions(-) diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.external.ts index 1c30022ce392a..b216ec5dca5d4 100644 --- a/packages/next/src/client/components/static-generation-async-storage.external.ts +++ b/packages/next/src/client/components/static-generation-async-storage.external.ts @@ -26,7 +26,7 @@ export interface StaticGenerationStore { revalidate?: false | number forceStatic?: boolean dynamicShouldError?: boolean - pendingRevalidates?: Promise[] + pendingRevalidates?: Record> postponeWasTriggered?: boolean postpone?: (reason: string) => never diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 787ee62d9d575..0ff64ebb8f360 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -111,7 +111,9 @@ async function addRevalidationHeader( requestStore: RequestStore } ) { - await Promise.all(staticGenerationStore.pendingRevalidates || []) + await Promise.all( + Object.values(staticGenerationStore.pendingRevalidates || []) + ) // If a tag was revalidated, the client router needs to invalidate all the // client router cache as they may be stale. And if a path was revalidated, the @@ -348,7 +350,9 @@ export async function handleAction({ if (isFetchAction) { res.statusCode = 500 - await Promise.all(staticGenerationStore.pendingRevalidates || []) + await Promise.all( + Object.values(staticGenerationStore.pendingRevalidates || []) + ) const promise = Promise.reject(error) try { @@ -640,7 +644,9 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc if (isFetchAction) { res.statusCode = 500 - await Promise.all(staticGenerationStore.pendingRevalidates || []) + await Promise.all( + Object.values(staticGenerationStore.pendingRevalidates || []) + ) const promise = Promise.reject(err) try { // we need to await the promise to trigger the rejection early diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 252bb68d83ab4..9b56b8a13a2ee 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -1037,7 +1037,7 @@ async function renderToHTMLOrFlightImpl( pageData: await stringifiedFlightPayloadPromise, // If we have pending revalidates, wait until they are all resolved. waitUntil: staticGenerationStore.pendingRevalidates - ? Promise.all(staticGenerationStore.pendingRevalidates) + ? Promise.all(Object.values(staticGenerationStore.pendingRevalidates)) : undefined, } ) 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 56abebde7a5d0..0aab61b356361 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 @@ -368,7 +368,9 @@ export class AppRouteRouteModule extends RouteModule< staticGenerationStore.fetchMetrics context.renderOpts.waitUntil = Promise.all( - staticGenerationStore.pendingRevalidates || [] + Object.values( + staticGenerationStore.pendingRevalidates || [] + ) ) addImplicitTags(staticGenerationStore) diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index 4a831e9788151..d90e2ba11640a 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -546,12 +546,11 @@ export function patchFetch({ // so the revalidated entry has the updated data if (!(staticGenerationStore.isRevalidate && entry.isStale)) { if (entry.isStale) { - if (!staticGenerationStore.pendingRevalidates) { - staticGenerationStore.pendingRevalidates = [] + staticGenerationStore.pendingRevalidates ??= {} + if (!staticGenerationStore.pendingRevalidates[cacheKey]) { + staticGenerationStore.pendingRevalidates[cacheKey] = + doOriginalFetch(true).catch(console.error) } - staticGenerationStore.pendingRevalidates.push( - doOriginalFetch(true).catch(console.error) - ) } const resData = entry.value.data 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 fcd3be4fb80c3..2b3a7734561b2 100644 --- a/packages/next/src/server/web/spec-extension/revalidate-tag.ts +++ b/packages/next/src/server/web/spec-extension/revalidate-tag.ts @@ -30,13 +30,13 @@ export function revalidateTag(tag: string) { } if (!store.pendingRevalidates) { - store.pendingRevalidates = [] + store.pendingRevalidates = {} } - store.pendingRevalidates.push( - store.incrementalCache.revalidateTag?.(tag).catch((err) => { + store.pendingRevalidates[tag] = store.incrementalCache + .revalidateTag?.(tag) + .catch((err) => { console.error(`revalidateTag failed for ${tag}`, err) }) - ) // TODO: only revalidate if the path matches store.pathWasRevalidated = true 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 abf9a3d46cbf5..237bdf1688a28 100644 --- a/packages/next/src/server/web/spec-extension/unstable-cache.ts +++ b/packages/next/src/server/web/spec-extension/unstable-cache.ts @@ -166,12 +166,11 @@ export function unstable_cache( return invokeCallback() } else { if (!store.pendingRevalidates) { - store.pendingRevalidates = [] + store.pendingRevalidates = {} } - store.pendingRevalidates.push( - invokeCallback().catch((err) => + store.pendingRevalidates[joinedKey] = invokeCallback().catch( + (err) => console.error(`revalidating cache with key: ${joinedKey}`, err) - ) ) } } diff --git a/test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts b/test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts index a049db1517c30..1657be6e9ee19 100644 --- a/test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts +++ b/test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts @@ -1,4 +1,4 @@ -import { findPort } from 'next-test-utils' +import { findPort, waitFor } from 'next-test-utils' import http from 'http' import { outdent } from 'outdent' import { FileRef, createNext } from 'e2e-utils' @@ -82,6 +82,48 @@ describe('app-fetch-deduping', () => { await next.destroy() }) + + it('should dedupe pending revalidation requests', async () => { + const next = await createNext({ + files: new FileRef(__dirname), + }) + + await next.patchFile( + 'app/test/page.tsx', + outdent` + async function getTime() { + const res = await fetch("http://localhost:${next.appPort}/api/time", { next: { revalidate: 5 } }) + return res.text() + } + + export default async function Home() { + await getTime() + await getTime() + const time = await getTime() + + return

{time}

+ } + ` + ) + + await next.render('/test') + + let count = next.cliOutput.split('Starting...').length - 1 + expect(count).toBe(1) + + const outputIndex = next.cliOutput.length + + // wait for the revalidation to finish + await waitFor(6000) + + await next.render('/test') + + count = + next.cliOutput.slice(outputIndex).split('Starting...').length - 1 + expect(count).toBe(1) + + await next.destroy() + }) }) } else { it('should skip other scenarios', () => {}) From 8d1c619ad650f5d147207f267441caf12acd91d1 Mon Sep 17 00:00:00 2001 From: Jan Amann Date: Tue, 28 Nov 2023 16:14:47 +0100 Subject: [PATCH 003/189] fix: Put back type for `NavigateOptions.scroll` (#59001) It seems like in https://github.com/vercel/next.js/commit/24b2ff16abaa973d695247a9c1ac4e229640d4ca#diff-421107ce62efb02560358d25c5eb086d5d82d2ad1c7c4929ebfb768c2ea1c973 `forceOptimisticNavigation` was removed, but the `@internal` flag that was originally assigned to this option remained in place. Due to this, it seems like `scroll` is missing in the built types (see [`app-router-context.shared-runtime.d.ts` in the latest canary](https://unpkg.com/browse/next@14.0.4-canary.18/dist/shared/lib/app-router-context.shared-runtime.d.ts)). Co-authored-by: Zack Tanner --- .../next/src/shared/lib/app-router-context.shared-runtime.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/next/src/shared/lib/app-router-context.shared-runtime.ts b/packages/next/src/shared/lib/app-router-context.shared-runtime.ts index 250151cbb7a56..6b6ee05e900c8 100644 --- a/packages/next/src/shared/lib/app-router-context.shared-runtime.ts +++ b/packages/next/src/shared/lib/app-router-context.shared-runtime.ts @@ -68,7 +68,6 @@ export type CacheNode = } export interface NavigateOptions { - /** @internal */ scroll?: boolean } From f4c14935aa27b11cc7f2bf3b37b389668eeb4428 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 28 Nov 2023 09:10:38 -0700 Subject: [PATCH 004/189] Cleanup Render Result (#58782) This improves some of the typings around the `RenderResult` returned during renders. Previously it had a single large metadata object that was shared across both the pages and app render pipelines. To add more type safety, this splits the types used by each of the render pipelines into their own types while still allowing the default `RenderResult` to reference metadata from either render pipeline. This also improved the flight data generation for app renders. Previously, the promise was inlined, and errors were swallowed. With the advent of improvements in #58779 the postpone errors are no longer returned by the flight generation and are instead handled correctly inside the render by React so it can emit properly postponed flight data. Besides that there was some whitespace changes, so hiding whitespace differences during review should make it much clearer to review! --- packages/next/src/build/utils.ts | 8 +- ...tatic-generation-async-storage.external.ts | 4 +- .../components/static-generation-bailout.ts | 12 +- packages/next/src/export/routes/app-page.ts | 16 +- .../src/server/app-render/action-handler.ts | 5 +- .../next/src/server/app-render/app-render.tsx | 275 +++++++++++------- .../server/app-render/flight-render-result.ts | 2 +- packages/next/src/server/base-server.ts | 8 +- packages/next/src/server/render-result.ts | 68 +++-- packages/next/src/server/render.tsx | 50 ++-- .../stream-utils/node-web-streams-helper.ts | 12 +- 11 files changed, 271 insertions(+), 189 deletions(-) diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index d99d6e3a28eea..3dfce139d23cb 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -1127,10 +1127,16 @@ export async function buildStaticPaths({ } } +export type AppConfigDynamic = + | 'auto' + | 'error' + | 'force-static' + | 'force-dynamic' + export type AppConfig = { revalidate?: number | false dynamicParams?: true | false - dynamic?: 'auto' | 'error' | 'force-static' | 'force-dynamic' + dynamic?: AppConfigDynamic fetchCache?: 'force-cache' | 'only-cache' preferredRegion?: string } diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.external.ts index b216ec5dca5d4..1119969c6c275 100644 --- a/packages/next/src/client/components/static-generation-async-storage.external.ts +++ b/packages/next/src/client/components/static-generation-async-storage.external.ts @@ -2,6 +2,8 @@ import type { AsyncLocalStorage } from 'async_hooks' import type { IncrementalCache } from '../../server/lib/incremental-cache' import type { DynamicServerError } from './hooks-server-context' import type { FetchMetrics } from '../../server/base-http' +import type { Revalidate } from '../../server/lib/revalidate' + import { createAsyncLocalStorage } from './async-local-storage' export interface StaticGenerationStore { @@ -23,7 +25,7 @@ export interface StaticGenerationStore { | 'default-no-store' | 'only-no-store' - revalidate?: false | number + revalidate?: Revalidate forceStatic?: boolean dynamicShouldError?: boolean pendingRevalidates?: Record> diff --git a/packages/next/src/client/components/static-generation-bailout.ts b/packages/next/src/client/components/static-generation-bailout.ts index 354ee9a162a12..558c2ec763081 100644 --- a/packages/next/src/client/components/static-generation-bailout.ts +++ b/packages/next/src/client/components/static-generation-bailout.ts @@ -1,3 +1,5 @@ +import type { AppConfigDynamic } from '../../build/utils' + import { DynamicServerError } from './hooks-server-context' import { maybePostpone } from './maybe-postpone' import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' @@ -6,7 +8,7 @@ class StaticGenBailoutError extends Error { code = 'NEXT_STATIC_GEN_BAILOUT' } -type BailoutOpts = { dynamic?: string; link?: string } +type BailoutOpts = { dynamic?: AppConfigDynamic; link?: string } export type StaticGenerationBailout = ( reason: string, @@ -23,7 +25,7 @@ function formatErrorMessage(reason: string, opts?: BailoutOpts) { export const staticGenerationBailout: StaticGenerationBailout = ( reason, - opts + { dynamic, link } = {} ) => { const staticGenerationStore = staticGenerationAsyncStorage.getStore() if (!staticGenerationStore) return false @@ -34,12 +36,12 @@ export const staticGenerationBailout: StaticGenerationBailout = ( if (staticGenerationStore.dynamicShouldError) { throw new StaticGenBailoutError( - formatErrorMessage(reason, { ...opts, dynamic: opts?.dynamic ?? 'error' }) + formatErrorMessage(reason, { link, dynamic: dynamic ?? 'error' }) ) } const message = formatErrorMessage(reason, { - ...opts, + dynamic, // this error should be caught by Next to bail out of static generation // in case it's uncaught, this link provides some additional context as to why link: 'https://nextjs.org/docs/messages/dynamic-server-error', @@ -51,7 +53,7 @@ export const staticGenerationBailout: StaticGenerationBailout = ( // to 0. staticGenerationStore.revalidate = 0 - if (!opts?.dynamic) { + if (!dynamic) { // we can statically prefetch pages that opt into dynamic, // but not things like headers/cookies staticGenerationStore.staticPrefetchBailout = true diff --git a/packages/next/src/export/routes/app-page.ts b/packages/next/src/export/routes/app-page.ts index 64b62dfc9405d..cc0c885d87e7f 100644 --- a/packages/next/src/export/routes/app-page.ts +++ b/packages/next/src/export/routes/app-page.ts @@ -25,6 +25,7 @@ import { lazyRenderAppPage } from '../../server/future/route-modules/app-page/mo export const enum ExportedAppPageFiles { HTML = 'HTML', FLIGHT = 'FLIGHT', + PREFETCH_FLIGHT = 'PREFETCH_FLIGHT', META = 'META', POSTPONED = 'POSTPONED', } @@ -128,10 +129,8 @@ export async function exportAppPage( const html = result.toUnchunkedString() - const { - metadata: { pageData, revalidate = false, postponed, fetchTags }, - } = result const { metadata } = result + const { flightData, revalidate = false, postponed, fetchTags } = metadata // Ensure we don't postpone without having PPR enabled. if (postponed && !renderOpts.experimental.ppr) { @@ -169,6 +168,11 @@ export async function exportAppPage( return { revalidate: 0 } } + // If page data isn't available, it means that the page couldn't be rendered + // properly. + else if (!flightData) { + throw new Error(`Invariant: failed to get page data for ${path}`) + } // If PPR is enabled, we want to emit a prefetch rsc file for the page // instead of the standard rsc. This is because the standard rsc will // contain the dynamic data. @@ -176,16 +180,16 @@ export async function exportAppPage( // If PPR is enabled, we should emit the flight data as the prefetch // payload. await fileWriter( - ExportedAppPageFiles.FLIGHT, + ExportedAppPageFiles.PREFETCH_FLIGHT, htmlFilepath.replace(/\.html$/, RSC_PREFETCH_SUFFIX), - pageData + flightData ) } else { // Writing the RSC payload to a file if we don't have PPR enabled. await fileWriter( ExportedAppPageFiles.FLIGHT, htmlFilepath.replace(/\.html$/, RSC_SUFFIX), - pageData + flightData ) } diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 0ff64ebb8f360..d507553404e8a 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -210,7 +210,8 @@ async function createRedirectRenderResult( console.error(`failed to get redirect response`, err) } } - return new RenderResult(JSON.stringify({})) + + return RenderResult.fromStatic('{}') } // Used to compare Host header and Origin header. @@ -607,7 +608,7 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc res.statusCode = 303 return { type: 'done', - result: new RenderResult(''), + result: RenderResult.fromStatic(''), } } else if (isNotFoundError(err)) { res.statusCode = 404 diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 9b56b8a13a2ee..53664456c2119 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -15,6 +15,7 @@ import type { NextParsedUrlQuery } from '../request-meta' import type { LoaderTree } from '../lib/app-dir-module' import type { AppPageModule } from '../future/route-modules/app-page/module' import type { ClientReferenceManifest } from '../../build/webpack/plugins/flight-manifest-plugin' +import type { Revalidate } from '../lib/revalidate' import React from 'react' @@ -22,7 +23,11 @@ import { createServerComponentRenderer, type ServerComponentRendererOptions, } from './create-server-components-renderer' -import RenderResult, { type RenderResultMetadata } from '../render-result' +import RenderResult, { + type AppPageRenderResultMetadata, + type RenderResultOptions, + type RenderResultResponse, +} from '../render-result' import { renderToInitialFizzStream, continueFizzStream, @@ -106,7 +111,7 @@ export type AppRenderContext = AppRenderBaseContext & { appUsingSizeAdjustment: boolean providedFlightRouterState?: FlightRouterState requestId: string - defaultRevalidate: StaticGenerationStore['revalidate'] + defaultRevalidate: Revalidate pagePath: string clientReferenceManifest: ClientReferenceManifest assetPrefix: string @@ -303,6 +308,34 @@ async function generateFlight( return new FlightRenderResult(flightReadableStream) } +/** + * Creates a resolver that eagerly generates a flight payload that is then + * resolved when the resolver is called. + */ +function createFlightDataResolver(ctx: AppRenderContext) { + // Generate the flight data and as soon as it can, convert it into a string. + const promise = generateFlight(ctx) + .then(async (result) => ({ + flightData: await result.toUnchunkedString(true), + })) + // Otherwise if it errored, return the error. + .catch((err) => ({ err })) + + return async () => { + // Resolve the promise to get the flight data or error. + const result = await promise + + // If the flight data failed to render due to an error, re-throw the error + // here. + if ('err' in result) { + throw result.err + } + + // Otherwise, return the flight data. + return result.flightData + } +} + type ServerComponentsRendererOptions = { ctx: AppRenderContext preinitScripts: () => void @@ -430,7 +463,7 @@ async function renderToHTMLOrFlightImpl( globalThis.__next_chunk_load__ = ComponentMod.__next_app__.loadChunk } - const extraRenderResultMeta: RenderResultMetadata = {} + const metadata: AppPageRenderResultMetadata = {} const appUsingSizeAdjustment = !!nextFontManifest?.appUsingSizeAdjust @@ -469,7 +502,7 @@ async function renderToHTMLOrFlightImpl( const allCapturedErrors: Error[] = [] const isNextExport = !!renderOpts.nextExport const { staticGenerationStore, requestStore } = baseCtx - const isStaticGeneration = staticGenerationStore.isStaticGeneration + const { isStaticGeneration } = staticGenerationStore // when static generation fails during PPR, we log the errors separately. We intentionally // silence the error logger in this case to avoid double logging. const silenceStaticGenerationErrors = @@ -537,7 +570,7 @@ async function renderToHTMLOrFlightImpl( const { urlPathname } = staticGenerationStore staticGenerationStore.fetchMetrics = [] - extraRenderResultMeta.fetchMetrics = staticGenerationStore.fetchMetrics + metadata.fetchMetrics = staticGenerationStore.fetchMetrics // don't modify original query object query = { ...query } @@ -615,11 +648,14 @@ async function renderToHTMLOrFlightImpl( const hasPostponed = typeof renderOpts.postponed === 'string' - let stringifiedFlightPayloadPromise = isStaticGeneration - ? generateFlight(ctx) - .then((renderResult) => renderResult.toUnchunkedString(true)) - .catch(() => null) - : Promise.resolve(null) + // Create the resolver that can get the flight payload when it's ready or + // throw the error if it occurred. If we are not generating static HTML, we + // don't need to generate the flight payload because it's a dynamic request + // which means we're either getting the flight payload only or just the + // regular HTML. + const flightDataResolver = isStaticGeneration + ? createFlightDataResolver(ctx) + : null // Get the nonce from the incoming request if it has one. const csp = req.headers['content-security-policy'] @@ -754,8 +790,8 @@ async function renderToHTMLOrFlightImpl( // result. if (isStaticGeneration) { headers.forEach((value, key) => { - extraRenderResultMeta.headers ??= {} - extraRenderResultMeta.headers[key] = value + metadata.headers ??= {} + metadata.headers[key] = value }) // Resolve the promise to continue the stream. @@ -779,7 +815,7 @@ async function renderToHTMLOrFlightImpl( // If the stream was postponed, we need to add the result to the // metadata so that it can be resumed later. if (postponed) { - extraRenderResultMeta.postponed = JSON.stringify(postponed) + metadata.postponed = JSON.stringify(postponed) // We don't need to "continue" this stream now as it's continued when // we resume the stream. @@ -789,8 +825,7 @@ async function renderToHTMLOrFlightImpl( const options: ContinueStreamOptions = { inlinedDataStream: serverComponentsRenderOpts.inlinedDataTransformStream.readable, - generateStaticHTML: - staticGenerationStore.isStaticGeneration || generateStaticHTML, + isStaticGeneration: isStaticGeneration || generateStaticHTML, getServerInsertedHTML: () => getServerInsertedHTML(allCapturedErrors), serverInsertedHTMLToHead: !renderOpts.postponed, // If this render generated a postponed state or this is a resume @@ -968,7 +1003,7 @@ async function renderToHTMLOrFlightImpl( inlinedDataStream: serverErrorComponentsRenderOpts.inlinedDataTransformStream .readable, - generateStaticHTML: staticGenerationStore.isStaticGeneration, + isStaticGeneration, getServerInsertedHTML: () => getServerInsertedHTML([]), serverInsertedHTMLToHead: true, validateRootLayout, @@ -1012,11 +1047,11 @@ async function renderToHTMLOrFlightImpl( tree: notFoundLoaderTree, formState, }), - { ...extraRenderResultMeta } + { metadata } ) } else if (actionRequestResult.type === 'done') { if (actionRequestResult.result) { - actionRequestResult.result.extendMetadata(extraRenderResultMeta) + actionRequestResult.result.assignMetadata(metadata) return actionRequestResult.result } else if (actionRequestResult.formState) { formState = actionRequestResult.formState @@ -1024,114 +1059,130 @@ async function renderToHTMLOrFlightImpl( } } - const renderResult = new RenderResult( - await renderToStream({ - asNotFound: isNotFoundPath, - tree: loaderTree, - formState, - }), - { - ...extraRenderResultMeta, - // Wait for and collect the flight payload data if we don't have it - // already. - pageData: await stringifiedFlightPayloadPromise, - // If we have pending revalidates, wait until they are all resolved. - waitUntil: staticGenerationStore.pendingRevalidates - ? Promise.all(Object.values(staticGenerationStore.pendingRevalidates)) - : undefined, - } - ) + const options: RenderResultOptions = { + metadata, + } - addImplicitTags(staticGenerationStore) - extraRenderResultMeta.fetchTags = staticGenerationStore.tags?.join(',') - renderResult.extendMetadata({ - fetchTags: extraRenderResultMeta.fetchTags, + let response: RenderResultResponse = await renderToStream({ + asNotFound: isNotFoundPath, + tree: loaderTree, + formState, }) - if (staticGenerationStore.isStaticGeneration) { - // Collect the entire render result to a string (by streaming it to a - // string). - const htmlResult = await renderResult.toUnchunkedString(true) - - // Timeout after 1.5 seconds for the headers to write. If it takes - // longer than this it's more likely that the stream has stalled and - // there is a React bug. The headers will then be updated in the render - // result below when the metadata is re-added to the new render result. - const onTimeout = new DetachedPromise() - const timeout = setTimeout(() => { - onTimeout.reject( - new Error( - 'Timeout waiting for headers to be emitted, this is a bug in Next.js' - ) - ) - }, 1500) - - // Race against the timeout and the headers being written. - await Promise.race([onHeadersFinished.promise, onTimeout.promise]) - - // It got here, which means it did not reject, so clear the timeout to avoid - // it from rejecting again (which is a no-op anyways). - clearTimeout(timeout) - - if ( - // if PPR is enabled - renderOpts.experimental.ppr && - // and a call to `maybePostpone` happened - staticGenerationStore.postponeWasTriggered && - // but there's no postpone state - !extraRenderResultMeta.postponed - ) { - // a call to postpone was made but was caught and not detected by Next.js. We should fail the build immediately - // as we won't be able to generate the static part - warn('') - error( - `Prerendering ${urlPathname} needs to partially bail out because something dynamic was used. ` + - `React throws a special object to indicate where we need to bail out but it was caught ` + - `by a try/catch or a Promise was not awaited. These special objects should not be caught ` + - `by your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error` - ) + // If we have pending revalidates, wait until they are all resolved. + if (staticGenerationStore.pendingRevalidates) { + options.waitUntil = Promise.all( + Object.values(staticGenerationStore.pendingRevalidates) + ) + } - if (capturedErrors.length > 0) { - warn( - 'The following error was thrown during build, and may help identify the source of the issue:' - ) + addImplicitTags(staticGenerationStore) - error(capturedErrors[0]) - } + if (staticGenerationStore.tags) { + metadata.fetchTags = staticGenerationStore.tags.join(',') + } - throw new MissingPostponeDataError( - `An unexpected error occurred while prerendering ${urlPathname}. Please check the logs above for more details.` + // Create the new render result for the response. + const result = new RenderResult(response, options) + + // If we aren't performing static generation, we can return the result now. + if (!isStaticGeneration) { + return result + } + + // If this is static generation, we should read this in now rather than + // sending it back to be sent to the client. + response = await result.toUnchunkedString(true) + + // Timeout after 1.5 seconds for the headers to write. If it takes + // longer than this it's more likely that the stream has stalled and + // there is a React bug. The headers will then be updated in the render + // result below when the metadata is re-added to the new render result. + const onTimeout = new DetachedPromise() + const timeout = setTimeout(() => { + onTimeout.reject( + new Error( + 'Timeout waiting for headers to be emitted, this is a bug in Next.js' ) - } + ) + }, 1500) + + // Race against the timeout and the headers being written. + await Promise.race([onHeadersFinished.promise, onTimeout.promise]) + + // It got here, which means it did not reject, so clear the timeout to avoid + // it from rejecting again (which is a no-op anyways). + clearTimeout(timeout) + + if ( + // if PPR is enabled + renderOpts.experimental.ppr && + // and a call to `maybePostpone` happened + staticGenerationStore.postponeWasTriggered && + // but there's no postpone state + !metadata.postponed + ) { + // a call to postpone was made but was caught and not detected by Next.js. We should fail the build immediately + // as we won't be able to generate the static part + warn('') + error( + `Prerendering ${urlPathname} needs to partially bail out because something dynamic was used. ` + + `React throws a special object to indicate where we need to bail out but it was caught ` + + `by a try/catch or a Promise was not awaited. These special objects should not be caught ` + + `by your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error` + ) - // if we encountered any unexpected errors during build - // we fail the prerendering phase and the build if (capturedErrors.length > 0) { - throw capturedErrors[0] - } + warn( + 'The following error was thrown during build, and may help identify the source of the issue:' + ) - if (staticGenerationStore.forceStatic === false) { - staticGenerationStore.revalidate = 0 + error(capturedErrors[0]) } - // TODO-APP: derive this from same pass to prevent additional - // render during static generation - extraRenderResultMeta.pageData = await stringifiedFlightPayloadPromise - extraRenderResultMeta.revalidate = - staticGenerationStore.revalidate ?? ctx.defaultRevalidate - - // provide bailout info for debugging - if (extraRenderResultMeta.revalidate === 0) { - extraRenderResultMeta.staticBailoutInfo = { - description: staticGenerationStore.dynamicUsageDescription, - stack: staticGenerationStore.dynamicUsageStack, - } - } + throw new MissingPostponeDataError( + `An unexpected error occurred while prerendering ${urlPathname}. Please check the logs above for more details.` + ) + } + + if (!flightDataResolver) { + throw new Error( + 'Invariant: Flight data resolver is missing when generating static HTML' + ) + } + + // If we encountered any unexpected errors during build we fail the + // prerendering phase and the build. + if (capturedErrors.length > 0) { + throw capturedErrors[0] + } - return new RenderResult(htmlResult, { ...extraRenderResultMeta }) + // Wait for and collect the flight payload data if we don't have it + // already + const flightData = await flightDataResolver() + if (flightData) { + metadata.flightData = flightData + } + + // If force static is specifically set to false, we should not revalidate + // the page. + if (staticGenerationStore.forceStatic === false) { + staticGenerationStore.revalidate = 0 + } + + // Copy the revalidation value onto the render result metadata. + metadata.revalidate = + staticGenerationStore.revalidate ?? ctx.defaultRevalidate + + // provide bailout info for debugging + if (metadata.revalidate === 0) { + metadata.staticBailoutInfo = { + description: staticGenerationStore.dynamicUsageDescription, + stack: staticGenerationStore.dynamicUsageStack, + } } - return renderResult + return new RenderResult(response, options) } export type AppPageRender = ( @@ -1140,7 +1191,7 @@ export type AppPageRender = ( pagePath: string, query: NextParsedUrlQuery, renderOpts: RenderOpts -) => Promise +) => Promise> export const renderToHTMLOrFlight: AppPageRender = ( req, diff --git a/packages/next/src/server/app-render/flight-render-result.ts b/packages/next/src/server/app-render/flight-render-result.ts index e37ffc8c95587..f14dfbc97b94b 100644 --- a/packages/next/src/server/app-render/flight-render-result.ts +++ b/packages/next/src/server/app-render/flight-render-result.ts @@ -6,6 +6,6 @@ import RenderResult from '../render-result' */ export class FlightRenderResult extends RenderResult { constructor(response: string | ReadableStream) { - super(response, { contentType: RSC_CONTENT_TYPE_HEADER }) + super(response, { contentType: RSC_CONTENT_TYPE_HEADER, metadata: {} }) } } diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 79504e567728d..ba353d82ee7bb 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -2406,7 +2406,7 @@ export default abstract class Server { // should return. // Handle `isNotFound`. - if (metadata.isNotFound) { + if ('isNotFound' in metadata && metadata.isNotFound) { return { value: null, revalidate: metadata.revalidate } } @@ -2415,7 +2415,7 @@ export default abstract class Server { return { value: { kind: 'REDIRECT', - props: metadata.pageData, + props: metadata.pageData ?? metadata.flightData, }, revalidate: metadata.revalidate, } @@ -2431,7 +2431,7 @@ export default abstract class Server { value: { kind: 'PAGE', html: result, - pageData: metadata.pageData, + pageData: metadata.pageData ?? metadata.flightData, postponed: metadata.postponed, headers, status: isAppPath ? res.statusCode : undefined, @@ -3224,7 +3224,7 @@ export default abstract class Server { if (this.renderOpts.dev && ctx.pathname === '/favicon.ico') { return { type: 'html', - body: new RenderResult(''), + body: RenderResult.fromStatic(''), } } const { res, query } = ctx diff --git a/packages/next/src/server/render-result.ts b/packages/next/src/server/render-result.ts index 8a498e6fb0bd1..6f9f87d0f6f50 100644 --- a/packages/next/src/server/render-result.ts +++ b/packages/next/src/server/render-result.ts @@ -1,6 +1,6 @@ import type { OutgoingHttpHeaders, ServerResponse } from 'http' -import type { StaticGenerationStore } from '../client/components/static-generation-async-storage.external' import type { Revalidate } from './lib/revalidate' +import type { FetchMetrics } from './base-http' import { chainStreams, @@ -11,38 +11,58 @@ import { isAbortError, pipeToNodeResponse } from './pipe-readable' type ContentTypeOption = string | undefined -export type RenderResultMetadata = { - pageData?: any +export type AppPageRenderResultMetadata = { + flightData?: string revalidate?: Revalidate staticBailoutInfo?: { stack?: string description?: string } - assetQueryString?: string - isNotFound?: boolean - isRedirect?: boolean - fetchMetrics?: StaticGenerationStore['fetchMetrics'] - fetchTags?: string - waitUntil?: Promise /** - * The headers to set on the response that were added by the render. + * The postponed state if the render had postponed and needs to be resumed. */ - headers?: OutgoingHttpHeaders + postponed?: string /** - * The postponed state if the render had postponed and needs to be resumed. + * The headers to set on the response that were added by the render. */ - postponed?: string + headers?: OutgoingHttpHeaders + fetchTags?: string + fetchMetrics?: FetchMetrics +} + +export type PagesRenderResultMetadata = { + pageData?: any + revalidate?: Revalidate + assetQueryString?: string + isNotFound?: boolean + isRedirect?: boolean } -type RenderResultResponse = +export type StaticRenderResultMetadata = {} + +export type RenderResultMetadata = AppPageRenderResultMetadata & + PagesRenderResultMetadata & + StaticRenderResultMetadata + +export type RenderResultResponse = | ReadableStream[] | ReadableStream | string | null -export default class RenderResult { +export type RenderResultOptions< + Metadata extends RenderResultMetadata = RenderResultMetadata +> = { + contentType?: ContentTypeOption + waitUntil?: Promise + metadata: Metadata +} + +export default class RenderResult< + Metadata extends RenderResultMetadata = RenderResultMetadata +> { /** * The detected content type for the response. This is used to set the * `Content-Type` header. @@ -53,7 +73,7 @@ export default class RenderResult { * The metadata for the response. This is used to set the revalidation times * and other metadata. */ - public readonly metadata: RenderResultMetadata + public readonly metadata: Readonly /** * The response itself. This can be a string, a stream, or null. If it's a @@ -69,21 +89,15 @@ export default class RenderResult { * @param value the static response value * @returns a new RenderResult instance */ - public static fromStatic(value: string): RenderResult { - return new RenderResult(value) + public static fromStatic(value: string) { + return new RenderResult(value, { metadata: {} }) } - private waitUntil?: Promise + private readonly waitUntil?: Promise constructor( response: RenderResultResponse, - { - contentType, - waitUntil, - ...metadata - }: { - contentType?: ContentTypeOption - } & RenderResultMetadata = {} + { contentType, waitUntil, metadata }: RenderResultOptions ) { this.response = response this.contentType = contentType @@ -91,7 +105,7 @@ export default class RenderResult { this.waitUntil = waitUntil } - public extendMetadata(metadata: RenderResultMetadata) { + public assignMetadata(metadata: Metadata) { Object.assign(this.metadata, metadata) } diff --git a/packages/next/src/server/render.tsx b/packages/next/src/server/render.tsx index 5ca9b50977162..7b079fbd7162e 100644 --- a/packages/next/src/server/render.tsx +++ b/packages/next/src/server/render.tsx @@ -78,7 +78,7 @@ import { normalizePagePath } from '../shared/lib/page-path/normalize-page-path' import { denormalizePagePath } from '../shared/lib/page-path/denormalize-page-path' import { getRequestMeta } from './request-meta' import { allowedStatusCodes, getRedirectStatus } from '../lib/redirect-status' -import RenderResult, { type RenderResultMetadata } from './render-result' +import RenderResult, { type PagesRenderResultMetadata } from './render-result' import isError from '../lib/is-error' import { streamFromString, @@ -414,20 +414,20 @@ export async function renderToHTMLImpl( // Adds support for reading `cookies` in `getServerSideProps` when SSR. setLazyProp({ req: req as any }, 'cookies', getCookieParser(req.headers)) - const renderResultMeta: RenderResultMetadata = {} + const metadata: PagesRenderResultMetadata = {} // In dev we invalidate the cache by appending a timestamp to the resource URL. // This is a workaround to fix https://github.com/vercel/next.js/issues/5860 // TODO: remove this workaround when https://bugs.webkit.org/show_bug.cgi?id=187726 is fixed. - renderResultMeta.assetQueryString = renderOpts.dev + metadata.assetQueryString = renderOpts.dev ? renderOpts.assetQueryString || `?ts=${Date.now()}` : '' // if deploymentId is provided we append it to all asset requests if (renderOpts.deploymentId) { - renderResultMeta.assetQueryString += `${ - renderResultMeta.assetQueryString ? '&' : '?' - }dpl=${renderOpts.deploymentId}` + metadata.assetQueryString += `${metadata.assetQueryString ? '&' : '?'}dpl=${ + renderOpts.deploymentId + }` } // don't modify original query object @@ -454,7 +454,7 @@ export async function renderToHTMLImpl( } = renderOpts const { App } = extra - const assetQueryString = renderResultMeta.assetQueryString + const assetQueryString = metadata.assetQueryString let Document = extra.Document @@ -892,7 +892,7 @@ export async function renderToHTMLImpl( ) } - renderResultMeta.isNotFound = true + metadata.isNotFound = true } if ( @@ -916,12 +916,12 @@ export async function renderToHTMLImpl( if (typeof data.redirect.basePath !== 'undefined') { ;(data as any).props.__N_REDIRECT_BASE_PATH = data.redirect.basePath } - renderResultMeta.isRedirect = true + metadata.isRedirect = true } if ( (dev || isBuildTimeSSG) && - !renderResultMeta.isNotFound && + !metadata.isNotFound && !isSerializableProps(pathname, 'getStaticProps', (data as any).props) ) { // this fn should throw an error instead of ever returning `false` @@ -992,12 +992,12 @@ export async function renderToHTMLImpl( ) // pass up revalidate and props for export - renderResultMeta.revalidate = revalidate - renderResultMeta.pageData = props + metadata.revalidate = revalidate + metadata.pageData = props // this must come after revalidate is added to renderResultMeta - if (renderResultMeta.isNotFound) { - return new RenderResult(null, renderResultMeta) + if (metadata.isNotFound) { + return new RenderResult(null, { metadata }) } } @@ -1110,8 +1110,8 @@ export async function renderToHTMLImpl( ) } - renderResultMeta.isNotFound = true - return new RenderResult(null, renderResultMeta) + metadata.isNotFound = true + return new RenderResult(null, { metadata }) } if ('redirect' in data && typeof data.redirect === 'object') { @@ -1123,7 +1123,7 @@ export async function renderToHTMLImpl( if (typeof data.redirect.basePath !== 'undefined') { ;(data as any).props.__N_REDIRECT_BASE_PATH = data.redirect.basePath } - renderResultMeta.isRedirect = true + metadata.isRedirect = true } if (deferredContent) { @@ -1141,7 +1141,7 @@ export async function renderToHTMLImpl( } props.pageProps = Object.assign({}, props.pageProps, (data as any).props) - renderResultMeta.pageData = props + metadata.pageData = props } if ( @@ -1158,8 +1158,10 @@ export async function renderToHTMLImpl( // Avoid rendering page un-necessarily for getServerSideProps data request // and getServerSideProps/getStaticProps redirects - if ((isDataReq && !isSSG) || renderResultMeta.isRedirect) { - return new RenderResult(JSON.stringify(props), renderResultMeta) + if ((isDataReq && !isSSG) || metadata.isRedirect) { + return new RenderResult(JSON.stringify(props), { + metadata, + }) } // We don't call getStaticProps or getServerSideProps while generating @@ -1169,7 +1171,7 @@ export async function renderToHTMLImpl( } // the response might be finished on the getInitialProps call - if (isResSent(res) && !isSSG) return new RenderResult(null, renderResultMeta) + if (isResSent(res) && !isSSG) return new RenderResult(null, { metadata }) // we preload the buildManifest for auto-export dynamic pages // to speed up hydrating query values @@ -1333,7 +1335,7 @@ export async function renderToHTMLImpl( return continueFizzStream(initialStream, { suffix, inlinedDataStream: serverComponentsInlinedTransformStream?.readable, - generateStaticHTML: true, + isStaticGeneration: true, // this must be called inside bodyResult so appWrappers is // up to date when `wrapApp` is called getServerInsertedHTML: () => { @@ -1408,7 +1410,7 @@ export async function renderToHTMLImpl( async () => renderDocument() ) if (!documentResult) { - return new RenderResult(null, renderResultMeta) + return new RenderResult(null, { metadata }) } const dynamicImportsIds = new Set() @@ -1567,7 +1569,7 @@ export async function renderToHTMLImpl( hybridAmp, }) - return new RenderResult(optimizedHtml, renderResultMeta) + return new RenderResult(optimizedHtml, { metadata }) } export type PagesRender = ( diff --git a/packages/next/src/server/stream-utils/node-web-streams-helper.ts b/packages/next/src/server/stream-utils/node-web-streams-helper.ts index 77a27cee01396..3b249ead98dcd 100644 --- a/packages/next/src/server/stream-utils/node-web-streams-helper.ts +++ b/packages/next/src/server/stream-utils/node-web-streams-helper.ts @@ -442,7 +442,7 @@ function chainTransformers( export type ContinueStreamOptions = { inlinedDataStream: ReadableStream | undefined - generateStaticHTML: boolean + isStaticGeneration: boolean getServerInsertedHTML: (() => Promise) | undefined serverInsertedHTMLToHead: boolean validateRootLayout: @@ -462,7 +462,7 @@ export async function continueFizzStream( { suffix, inlinedDataStream, - generateStaticHTML, + isStaticGeneration, getServerInsertedHTML, serverInsertedHTMLToHead, validateRootLayout, @@ -475,7 +475,7 @@ export async function continueFizzStream( // If we're generating static HTML and there's an `allReady` promise on the // stream, we need to wait for it to resolve before continuing. - if (generateStaticHTML && 'allReady' in renderStream) { + if (isStaticGeneration && 'allReady' in renderStream) { await renderStream.allReady } @@ -518,7 +518,7 @@ export async function continueFizzStream( type ContinuePostponedStreamOptions = Pick< ContinueStreamOptions, | 'inlinedDataStream' - | 'generateStaticHTML' + | 'isStaticGeneration' | 'getServerInsertedHTML' | 'serverInsertedHTMLToHead' > @@ -527,7 +527,7 @@ export async function continuePostponedFizzStream( renderStream: ReactReadableStream, { inlinedDataStream, - generateStaticHTML, + isStaticGeneration, getServerInsertedHTML, serverInsertedHTMLToHead, }: ContinuePostponedStreamOptions @@ -536,7 +536,7 @@ export async function continuePostponedFizzStream( // If we're generating static HTML and there's an `allReady` promise on the // stream, we need to wait for it to resolve before continuing. - if (generateStaticHTML && 'allReady' in renderStream) { + if (isStaticGeneration && 'allReady' in renderStream) { await renderStream.allReady } From 9c791866107d8818ea099f870d394d21acb87820 Mon Sep 17 00:00:00 2001 From: Leah Date: Tue, 28 Nov 2023 17:41:28 +0100 Subject: [PATCH 005/189] =?UTF-8?q?fix(turbopack):=20add=20list=20of=20pac?= =?UTF-8?q?kages=20that=20should=20never=20be=20marked=20as=20e=E2=80=A6?= =?UTF-8?q?=20(#59020)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### What? Turbopack was missing the list of modules / requests that should never be marked as external: https://github.com/vercel/next.js/blob/8d1c619ad650f5d147207f267441caf12acd91d1/packages/next/src/build/handle-externals.ts#L188 This could lead to errors with i.e. `next/image` not receiving the correct image config. Closes PACK-2047 Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com> --- .../crates/next-core/src/next_server/resolve.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/next-swc/crates/next-core/src/next_server/resolve.rs b/packages/next-swc/crates/next-core/src/next_server/resolve.rs index 2cee86cf225ab..411030c757ed1 100644 --- a/packages/next-swc/crates/next-core/src/next_server/resolve.rs +++ b/packages/next-swc/crates/next-core/src/next_server/resolve.rs @@ -80,7 +80,15 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin { if *condition(self.root).matches(context).await? { return Ok(ResolveResultOption::none()); } - if !matches!(&*request.await?, Request::Module { .. }) { + let request_value = &*request.await?; + if !matches!(request_value, Request::Module { .. }) { + return Ok(ResolveResultOption::none()); + } + + // from https://github.com/vercel/next.js/blob/8d1c619ad650f5d147207f267441caf12acd91d1/packages/next/src/build/handle-externals.ts#L188 + let never_external_regex = lazy_regex::regex!("^(?: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$)"); + + if never_external_regex.is_match(&request_value.request().unwrap_or_default()) { return Ok(ResolveResultOption::none()); } From 113a125a93316bed2f6a73184af9d2480fde9435 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 28 Nov 2023 16:44:35 +0000 Subject: [PATCH 006/189] v14.0.4-canary.20 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 18 +++++++++--------- 18 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lerna.json b/lerna.json index 3198bd6a9f2d3..6a9d6005180e8 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.19" + "version": "14.0.4-canary.20" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index b22b81f4d599e..1e1084867564b 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 10826c9eeafd1..e404a87720057 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.19", + "@next/eslint-plugin-next": "14.0.4-canary.20", "@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 0bc29fdb43db5..0e329b1758e4e 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 87703c001408c..76efd598eb21f 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "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 c4e2bb725b0c1..d2392c1046026 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 79acb0d78bb58..ff29fb14d5a1c 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index fec191f7e85ea..e0d6ae26917d2 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index f11d76a4accf6..52d6b79268165 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 80ee1d7264675..5b6121815b88c 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "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 7739a291d411a..b85a06bd9fa50 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "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 f48872688d982..6e1bcacefd7a6 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index ec2c9e6502717..1028e75335e09 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index e731ddb990437..0957fc97e544a 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.19", + "@next/env": "14.0.4-canary.20", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.19", - "@next/polyfill-nomodule": "14.0.4-canary.19", - "@next/react-dev-overlay": "14.0.4-canary.19", - "@next/react-refresh-utils": "14.0.4-canary.19", - "@next/swc": "14.0.4-canary.19", + "@next/polyfill-module": "14.0.4-canary.20", + "@next/polyfill-nomodule": "14.0.4-canary.20", + "@next/react-dev-overlay": "14.0.4-canary.20", + "@next/react-refresh-utils": "14.0.4-canary.20", + "@next/swc": "14.0.4-canary.20", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index ab3a15b566c47..c96e0901cce7b 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": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 43c03b8d07cb9..b44431b8996ff 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "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 3a6cb5f628278..eecc3f4a59a68 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.19", + "version": "14.0.4-canary.20", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.19", + "next": "14.0.4-canary.20", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b26b30f633c53..c462e8b803790 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,7 +738,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -803,7 +803,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -930,19 +930,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1596,7 +1596,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.19 + specifier: 14.0.4-canary.20 version: link:../next outdent: specifier: 0.8.0 @@ -24649,7 +24649,7 @@ packages: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4} + resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4} id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 From 6fd3c3b9921e0732fb46738135a0667c234345f8 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 28 Nov 2023 17:00:46 +0000 Subject: [PATCH 007/189] v14.0.4-canary.21 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 6a9d6005180e8..ec99754294ba5 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.20" + "version": "14.0.4-canary.21" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 1e1084867564b..af1c7817b6944 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index e404a87720057..48d4f12e749b7 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.20", + "version": "14.0.4-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": "14.0.4-canary.20", + "@next/eslint-plugin-next": "14.0.4-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 0e329b1758e4e..314ff38296e3e 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 76efd598eb21f..c6f8d33fb190d 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.20", + "version": "14.0.4-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 d2392c1046026..0a89b3b0241e8 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.20", + "version": "14.0.4-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 ff29fb14d5a1c..a2d5517335be7 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index e0d6ae26917d2..961dd2fa6da24 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 52d6b79268165..80fdb4a950a5f 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.20", + "version": "14.0.4-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 5b6121815b88c..2c43fed816b41 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.20", + "version": "14.0.4-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 b85a06bd9fa50..c2b30b0021b74 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.20", + "version": "14.0.4-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 6e1bcacefd7a6..3a93b85969a54 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 1028e75335e09..745024cef8c35 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 0957fc97e544a..5f47cec572be1 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.20", + "@next/env": "14.0.4-canary.21", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.20", - "@next/polyfill-nomodule": "14.0.4-canary.20", - "@next/react-dev-overlay": "14.0.4-canary.20", - "@next/react-refresh-utils": "14.0.4-canary.20", - "@next/swc": "14.0.4-canary.20", + "@next/polyfill-module": "14.0.4-canary.21", + "@next/polyfill-nomodule": "14.0.4-canary.21", + "@next/react-dev-overlay": "14.0.4-canary.21", + "@next/react-refresh-utils": "14.0.4-canary.21", + "@next/swc": "14.0.4-canary.21", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index c96e0901cce7b..99ccdedd263c9 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": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index b44431b8996ff..0cd4cb428f1e0 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.20", + "version": "14.0.4-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 eecc3f4a59a68..e55265f5dfbbd 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.20", + "version": "14.0.4-canary.21", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.20", + "next": "14.0.4-canary.21", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c462e8b803790..a8c1ce7f7742d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,7 +738,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -803,7 +803,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -930,19 +930,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1596,7 +1596,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.20 + specifier: 14.0.4-canary.21 version: link:../next outdent: specifier: 0.8.0 From 38e9bc97704d2c299d9b247fbd39f039be8b1f9f Mon Sep 17 00:00:00 2001 From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:19:05 +0000 Subject: [PATCH 008/189] Docs: Add missing diagram (#59008) Slack feedback. Add missing diagram, and polish wording for `layout.tsx` explanation. --- .../02-file-conventions/layout.mdx | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/02-app/02-api-reference/02-file-conventions/layout.mdx b/docs/02-app/02-api-reference/02-file-conventions/layout.mdx index 91e7805948f64..8ad0337e940e9 100644 --- a/docs/02-app/02-api-reference/02-file-conventions/layout.mdx +++ b/docs/02-app/02-api-reference/02-file-conventions/layout.mdx @@ -100,17 +100,15 @@ When using client-side navigation, Next.js automatically only renders the part o For example, in the following directory structure, `dashboard/layout.tsx` is the common layout for both `/dashboard/settings` and `/dashboard/analytics`: -```txt highight={3} hideLineNumbers -app -└── dashboard - ├── layout.tsx - ├── settings - │ └── page.tsx - └── analytics - └── page.js -``` - -When navigating from `/dashboard/settings` to `/dashboard/analytics`, `page.tsx` in `/dashboard/analytics` will be rendered on the server because it is UI that changed, while `dashboard/layout.tsx` will **not** be re-rendered because it is a common UI between the two routes. +File structure showing a dashboard folder nesting a layout.tsx file, and settings and analytics folders with their own pages + +When navigating from `/dashboard/settings` to `/dashboard/analytics`, `page.tsx` in `/dashboard/analytics` will rerender on the server, while `dashboard/layout.tsx` will **not** rerender because it's a common UI shared between the two routes. This performance optimization allows navigation between pages that share a layout to be quicker as only the data fetching and rendering for the page has to run, instead of the entire route that could include shared layouts that fetch their own data. From c5acef61509f7f1388245b3b1cf80ececde5b059 Mon Sep 17 00:00:00 2001 From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:20:05 +0000 Subject: [PATCH 009/189] Docs: Update revalidate example (#59002) Closing: https://github.com/vercel/feedback/issues/47084 - The example previously showed `export const revalidate` being called from a `utils` file, whereas we want to call it from a route segment (layout or page) --- .../01-fetching-caching-and-revalidating.mdx | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/02-app/01-building-your-application/02-data-fetching/01-fetching-caching-and-revalidating.mdx b/docs/02-app/01-building-your-application/02-data-fetching/01-fetching-caching-and-revalidating.mdx index 0afee64dfe2de..a275d8cf600cc 100644 --- a/docs/02-app/01-building-your-application/02-data-fetching/01-fetching-caching-and-revalidating.mdx +++ b/docs/02-app/01-building-your-application/02-data-fetching/01-fetching-caching-and-revalidating.mdx @@ -210,25 +210,21 @@ You can also use the experimental [`unstable_cache` API](/docs/app/api-reference In the example below: -- The `revalidate` option is set to `3600`, meaning the data will be cached and revalidated at most every hour. - The React `cache` function is used to [memoize](/docs/app/building-your-application/caching#request-memoization) data requests. +- The `revalidate` option is set to `3600` in the `layout.ts` and `page.ts` segments, meaning the data will be cached and revalidated at most every hour. -```ts filename="utils/get-item.ts" switcher +```ts filename="app/utils.ts" switcher import { cache } from 'react' -export const revalidate = 3600 // revalidate the data at most every hour - export const getItem = cache(async (id: string) => { const item = await db.item.findUnique({ id }) return item }) ``` -```js filename="utils/get-item.js" switcher +```js filename="app/utils.js" switcher import { cache } from 'react' -export const revalidate = 3600 // revalidate the data at most every hour - export const getItem = cache(async (id) => { const item = await db.item.findUnique({ id }) return item @@ -240,6 +236,8 @@ Although the `getItem` function is called twice, only one query will be made to ```tsx filename="app/item/[id]/layout.tsx" switcher import { getItem } from '@/utils/get-item' +export const revalidate = 3600 // revalidate the data at most every hour + export default async function Layout({ params: { id }, }: { @@ -253,6 +251,8 @@ export default async function Layout({ ```jsx filename="app/item/[id]/layout.js" switcher import { getItem } from '@/utils/get-item' +export const revalidate = 3600 // revalidate the data at most every hour + export default async function Layout({ params: { id } }) { const item = await getItem(id) // ... @@ -262,6 +262,8 @@ export default async function Layout({ params: { id } }) { ```tsx filename="app/item/[id]/page.tsx" switcher import { getItem } from '@/utils/get-item' +export const revalidate = 3600 // revalidate the data at most every hour + export default async function Page({ params: { id }, }: { @@ -275,6 +277,8 @@ export default async function Page({ ```jsx filename="app/item/[id]/page.js" switcher import { getItem } from '@/utils/get-item' +export const revalidate = 3600 // revalidate the data at most every hour + export default async function Page({ params: { id } }) { const item = await getItem(id) // ... From d0c5673d37c0393cbab8152ae951ffa8411d31f2 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 28 Nov 2023 18:26:06 +0000 Subject: [PATCH 010/189] v14.0.4-canary.22 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index ec99754294ba5..965d4a266d76a 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.21" + "version": "14.0.4-canary.22" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index af1c7817b6944..1b3ffe29dc234 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 48d4f12e749b7..9975c9945e36c 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.21", + "@next/eslint-plugin-next": "14.0.4-canary.22", "@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 314ff38296e3e..d141545d7021c 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index c6f8d33fb190d..9b1beace9e363 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "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 0a89b3b0241e8..66acf7e60c74b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index a2d5517335be7..ce4fe6d633553 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 961dd2fa6da24..b73f564950e60 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 80fdb4a950a5f..90fa6226da23d 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 2c43fed816b41..75c4235d747d5 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "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 c2b30b0021b74..de4a813e0f32a 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "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 3a93b85969a54..2ab1f2747c1d6 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 745024cef8c35..2631d27649ee6 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 5f47cec572be1..b41109e25bc9f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.21", + "@next/env": "14.0.4-canary.22", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.21", - "@next/polyfill-nomodule": "14.0.4-canary.21", - "@next/react-dev-overlay": "14.0.4-canary.21", - "@next/react-refresh-utils": "14.0.4-canary.21", - "@next/swc": "14.0.4-canary.21", + "@next/polyfill-module": "14.0.4-canary.22", + "@next/polyfill-nomodule": "14.0.4-canary.22", + "@next/react-dev-overlay": "14.0.4-canary.22", + "@next/react-refresh-utils": "14.0.4-canary.22", + "@next/swc": "14.0.4-canary.22", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 99ccdedd263c9..2b3ed37b02e17 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": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 0cd4cb428f1e0..c226bec7d456c 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "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 e55265f5dfbbd..3cc952b41c939 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.21", + "version": "14.0.4-canary.22", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.21", + "next": "14.0.4-canary.22", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8c1ce7f7742d..25ea12b9f69d6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,7 +738,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -803,7 +803,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -930,19 +930,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1596,7 +1596,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.21 + specifier: 14.0.4-canary.22 version: link:../next outdent: specifier: 0.8.0 From 91471878e1e5049a3f090d4c3cc38ce162c9a88d Mon Sep 17 00:00:00 2001 From: Dima Voytenko Date: Tue, 28 Nov 2023 11:40:15 -0800 Subject: [PATCH 011/189] Testmode: provide test info for rewrite requests (#59033) The rewrite request appear to bypass the `BaseServer` or are executed in the sandbox. However, these requests have the correct test info in the headers that can be used instead of the `AsyncLocalStorage`. --- .../next/src/experimental/testmode/server.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/packages/next/src/experimental/testmode/server.ts b/packages/next/src/experimental/testmode/server.ts index 0bb53755693ab..cfad40108b32a 100644 --- a/packages/next/src/experimental/testmode/server.ts +++ b/packages/next/src/experimental/testmode/server.ts @@ -84,11 +84,26 @@ function buildResponse(proxyResponse: ProxyFetchResponse): Response { }) } +function extractTestInfoFromRequest(req: Request): TestReqInfo | undefined { + const proxyPortHeader = req.headers.get('next-test-proxy-port') + if (!proxyPortHeader) { + return undefined + } + const url = req.url + const proxyPort = Number(proxyPortHeader) + const testData = req.headers.get('next-test-data') ?? '' + return { + url, + proxyPort, + testData, + } +} + async function handleFetch( originalFetch: Fetch, request: Request ): Promise { - const testInfo = testStorage.getStore() + const testInfo = testStorage.getStore() ?? extractTestInfoFromRequest(request) if (!testInfo) { throw new Error('No test info') } From 05f2c68b7a31f94ca9e298f41af89ac0d0b5d67a Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Tue, 28 Nov 2023 12:15:35 -0800 Subject: [PATCH 012/189] Increase default timeout for swc build (#59035) x-ref: https://github.com/vercel/next.js/actions/runs/7022943529/attempts/3 --- .github/workflows/build_and_deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_and_deploy.yml b/.github/workflows/build_and_deploy.yml index 583a5c0be50f5..134b082e194d3 100644 --- a/.github/workflows/build_and_deploy.yml +++ b/.github/workflows/build_and_deploy.yml @@ -228,7 +228,7 @@ jobs: name: stable - ${{ matrix.settings.target }} - node@16 runs-on: ${{ matrix.settings.host }} - timeout-minutes: 30 + timeout-minutes: 45 steps: # https://github.com/actions/virtual-environments/issues/1187 - name: tune linux network From 72af59a1c1e47d983142adc2d0b647643dfbbbd7 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Tue, 28 Nov 2023 12:42:26 -0800 Subject: [PATCH 013/189] build(cargo): bump up turbopack (#59032) ### What? Bump up turbopack which includes url rewrite related improvements. This makes `test/integration/url` test passes. Note there are some lacking behavior around edge runtime + url behavior, it is being tracked in PACK-2014. Closes PACK-2051 --- Cargo.lock | 68 +++++++++++++++--------------- Cargo.toml | 6 +-- packages/next/package.json | 2 +- pnpm-lock.yaml | 10 ++--- test/turbopack-tests-manifest.json | 5 +-- 5 files changed, 45 insertions(+), 46 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 456f2d6b7660a..6d85b6ef8043a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "serde", "smallvec", @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "serde", @@ -7678,7 +7678,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-trait", @@ -7710,7 +7710,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "cargo-lock", @@ -7722,7 +7722,7 @@ dependencies = [ [[package]] name = "turbo-tasks-bytes" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "bytes", @@ -7737,7 +7737,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "dotenvs", @@ -7751,7 +7751,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7768,7 +7768,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "auto-hash-map", @@ -7798,7 +7798,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "base16", "hex", @@ -7810,7 +7810,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -7824,7 +7824,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "proc-macro2", "quote", @@ -7834,7 +7834,7 @@ dependencies = [ [[package]] name = "turbo-tasks-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "mimalloc", ] @@ -7842,7 +7842,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "auto-hash-map", @@ -7867,7 +7867,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-recursion", @@ -7898,7 +7898,7 @@ dependencies = [ [[package]] name = "turbopack-binding" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "auto-hash-map", "mdxjs", @@ -7939,7 +7939,7 @@ dependencies = [ [[package]] name = "turbopack-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7962,7 +7962,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "clap 4.4.2", @@ -7980,7 +7980,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-recursion", @@ -8010,7 +8010,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-trait", @@ -8036,7 +8036,7 @@ dependencies = [ [[package]] name = "turbopack-dev" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8060,7 +8060,7 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-compression", @@ -8097,7 +8097,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-trait", @@ -8131,7 +8131,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-hmr-protocol" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "serde", "serde_json", @@ -8142,7 +8142,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-plugins" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-trait", @@ -8165,7 +8165,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-runtime" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "indoc", @@ -8182,7 +8182,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8198,7 +8198,7 @@ dependencies = [ [[package]] name = "turbopack-image" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "base64 0.21.4", @@ -8218,7 +8218,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "serde", @@ -8233,7 +8233,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "mdxjs", @@ -8248,7 +8248,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "async-stream", @@ -8283,7 +8283,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "serde", @@ -8299,7 +8299,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "swc_core", "turbo-tasks", @@ -8310,7 +8310,7 @@ dependencies = [ [[package]] name = "turbopack-trace-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "crossbeam-channel", @@ -8325,7 +8325,7 @@ dependencies = [ [[package]] name = "turbopack-wasm" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231127.4#df8666fcd6177e926e7f17c63860e62cdc9ded34" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231128.2#0f828c5744c17c19235fe3a6cb4006a3102183bb" dependencies = [ "anyhow", "indexmap 1.9.3", diff --git a/Cargo.toml b/Cargo.toml index 4a27aa315019c..6590c2b0352ed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,11 +43,11 @@ swc_core = { version = "0.86.81", features = [ testing = { version = "0.35.11" } # Turbo crates -turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.4" } +turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231128.2" } # [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros.. -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.4" } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231128.2" } # [TODO]: need to refactor embed_directory! macro usage in next-core -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231127.4" } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231128.2" } # General Deps diff --git a/packages/next/package.json b/packages/next/package.json index b41109e25bc9f..bdb80dd520841 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -195,7 +195,7 @@ "@types/ws": "8.2.0", "@vercel/ncc": "0.34.0", "@vercel/nft": "0.22.6", - "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4", + "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2", "acorn": "8.5.0", "amphtml-validator": "1.0.35", "anser": "1.4.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25ea12b9f69d6..b109c54d0c55c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1074,8 +1074,8 @@ importers: specifier: 0.22.6 version: 0.22.6 '@vercel/turbopack-ecmascript-runtime': - specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4 - version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4(react-refresh@0.12.0)(webpack@5.86.0)' + specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2 + version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2(react-refresh@0.12.0)(webpack@5.86.0)' acorn: specifier: 8.5.0 version: 8.5.0 @@ -24648,9 +24648,9 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4} - id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231127.4' + '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2(react-refresh@0.12.0)(webpack@5.86.0)': + resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2} + id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 dependencies: diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index 352c2623a12e2..b2cdc1c95a857 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -14886,12 +14886,11 @@ "Handle new URL asset references in next dev should render the /ssr page", "Handle new URL asset references in next dev should render the /static page", "Handle new URL asset references in next dev should respond on basename api", - "Handle new URL asset references in next dev should respond on size api" - ], - "failed": [ + "Handle new URL asset references in next dev should respond on size api", "Handle new URL asset references in next dev should client-render the /ssg page", "Handle new URL asset references in next dev should client-render the /ssr page" ], + "failed": [], "pending": [ "Handle new URL asset references in next build should client-render the /ssg page", "Handle new URL asset references in next build should client-render the /ssr page", From 6ac1367687aebeeec1530bc6d6528ac296ffc2db Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 28 Nov 2023 22:24:13 +0000 Subject: [PATCH 014/189] v14.0.4-canary.23 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 18 +++++++++--------- 18 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lerna.json b/lerna.json index 965d4a266d76a..8d6d402166f51 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.22" + "version": "14.0.4-canary.23" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 1b3ffe29dc234..0b6a1ec0f1364 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 9975c9945e36c..4f38ef5a79997 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.22", + "@next/eslint-plugin-next": "14.0.4-canary.23", "@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 d141545d7021c..16e17c13f82d3 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 9b1beace9e363..2ca00e4ba41b7 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "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 66acf7e60c74b..0d8a3f99e679f 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index ce4fe6d633553..113703bb9a866 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index b73f564950e60..aba071f003a97 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 90fa6226da23d..d0bb708a02264 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 75c4235d747d5..37ea68836d1bc 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "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 de4a813e0f32a..02ed553fed981 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "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 2ab1f2747c1d6..c9273e7497334 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 2631d27649ee6..1bf0ee5613b4e 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index bdb80dd520841..fe0d003b6c23a 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.22", + "@next/env": "14.0.4-canary.23", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.22", - "@next/polyfill-nomodule": "14.0.4-canary.22", - "@next/react-dev-overlay": "14.0.4-canary.22", - "@next/react-refresh-utils": "14.0.4-canary.22", - "@next/swc": "14.0.4-canary.22", + "@next/polyfill-module": "14.0.4-canary.23", + "@next/polyfill-nomodule": "14.0.4-canary.23", + "@next/react-dev-overlay": "14.0.4-canary.23", + "@next/react-refresh-utils": "14.0.4-canary.23", + "@next/swc": "14.0.4-canary.23", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 2b3ed37b02e17..1e55f9fbb6d92 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": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index c226bec7d456c..5ec55766b1371 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "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 3cc952b41c939..e768ce7d02832 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.22", + "version": "14.0.4-canary.23", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.22", + "next": "14.0.4-canary.23", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b109c54d0c55c..eb26c8202eda1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,7 +738,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -803,7 +803,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -930,19 +930,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1596,7 +1596,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.22 + specifier: 14.0.4-canary.23 version: link:../next outdent: specifier: 0.8.0 @@ -24649,7 +24649,7 @@ packages: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2} + resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2} id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231128.2' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 From 298bbe54896a5c26fa23605d431c950914c9f7ed Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 28 Nov 2023 14:54:04 -0800 Subject: [PATCH 015/189] fix async action queue behavior (#59038) ### What? When the router action queue receives a bunch of async actions in quick succession, some of those requests are dropped, and as a result, anything observing pending transitions will be stuck in a pending state. ### Why? When adding items to the action queue, the intended behavior is for new actions to be added to the end of the action queue, to be picked up by `runRemainingActions` once the in-flight action is processed. However, new actions are erroneously overwriting pending actions in the queue rather than appending them, as `actionQueue.last` might have a pending action attached to it. ### How? This moves the assignment of `actionQueue.last` to always be in `dispatchAction`, rather than the function that processes the action, so that we always have a single spot where `last` is assigned and to prevent it from erroneously omitted/overwritten. Fixes #59011 --- .../src/shared/lib/router/action-queue.ts | 9 ++++- test/e2e/app-dir/actions/app-action.test.ts | 39 +++++++++++++++++++ .../actions/app/use-transition/action.js | 9 +++++ .../actions/app/use-transition/page.js | 24 ++++++++++++ 4 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 test/e2e/app-dir/actions/app/use-transition/action.js create mode 100644 test/e2e/app-dir/actions/app/use-transition/page.js diff --git a/packages/next/src/shared/lib/router/action-queue.ts b/packages/next/src/shared/lib/router/action-queue.ts index ad212a233e696..4310faba9caf3 100644 --- a/packages/next/src/shared/lib/router/action-queue.ts +++ b/packages/next/src/shared/lib/router/action-queue.ts @@ -67,7 +67,6 @@ async function runAction({ } actionQueue.pending = action - actionQueue.last = action const payload = action.payload const actionResult = actionQueue.action(prevState, payload) @@ -142,6 +141,9 @@ function dispatchAction( // Check if the queue is empty if (actionQueue.pending === null) { // The queue is empty, so add the action and start it immediately + // Mark this action as the last in the queue + actionQueue.last = newAction + runAction({ actionQueue, action: newAction, @@ -152,6 +154,9 @@ function dispatchAction( // Mark the pending action as discarded (so the state is never applied) and start the navigation action immediately. actionQueue.pending.discarded = true + // Mark this action as the last in the queue + actionQueue.last = newAction + // if the pending action was a server action, mark the queue as needing a refresh once events are processed if (actionQueue.pending.payload.type === ACTION_SERVER_ACTION) { actionQueue.needsRefresh = true @@ -164,7 +169,7 @@ function dispatchAction( }) } else { // The queue is not empty, so add the action to the end of the queue - // It will be started by finishRunningAction after the previous action finishes + // It will be started by runRemainingActions after the previous action finishes if (actionQueue.last !== null) { actionQueue.last.next = newAction } diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 90423006d4997..7fa91cbb1884c 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -370,6 +370,45 @@ createNextDescribe( expect(requestCount).toBe(1) }) + it('should handle actions executed in quick succession', async () => { + let requestCount = 0 + const browser = await next.browser('/use-transition', { + beforePageLoad(page) { + page.on('request', (request) => { + const url = new URL(request.url()) + if (url.pathname === '/use-transition') { + requestCount++ + } + }) + }, + }) + + expect(await browser.elementByCss('h1').text()).toBe( + 'Transition is: idle' + ) + const button = await browser.elementById('action-button') + + // fire off 6 successive requests by clicking the button 6 times + for (let i = 0; i < 6; i++) { + await button.click() + + // add a little bit of delay to simulate user behavior & give + // the requests a moment to start running + await waitFor(500) + } + + expect(await browser.elementByCss('h1').text()).toBe( + 'Transition is: pending' + ) + + await check(() => requestCount, 6) + + await check( + () => browser.elementByCss('h1').text(), + 'Transition is: idle' + ) + }) + if (isNextStart) { it('should not expose action content in sourcemaps', async () => { const sourcemap = ( diff --git a/test/e2e/app-dir/actions/app/use-transition/action.js b/test/e2e/app-dir/actions/app/use-transition/action.js new file mode 100644 index 0000000000000..fdc8fc8c93abb --- /dev/null +++ b/test/e2e/app-dir/actions/app/use-transition/action.js @@ -0,0 +1,9 @@ +'use server' + +export async function addToCart() { + return new Promise((resolve, reject) => { + setTimeout(() => { + resolve('Add to cart') + }, 1000) + }) +} diff --git a/test/e2e/app-dir/actions/app/use-transition/page.js b/test/e2e/app-dir/actions/app/use-transition/page.js new file mode 100644 index 0000000000000..a7df1d63b9252 --- /dev/null +++ b/test/e2e/app-dir/actions/app/use-transition/page.js @@ -0,0 +1,24 @@ +'use client' + +import { useTransition } from 'react' +import { addToCart } from './action' + +export default function Page() { + const [isPending, startTransition] = useTransition() + + return ( +
+

Transition is: {isPending ? 'pending' : 'idle'}

+ +
+ ) +} From 266fc8e3187c47238afe1d6ddbea213b6b4345ac Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 28 Nov 2023 23:04:45 +0000 Subject: [PATCH 016/189] v14.0.4-canary.24 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 8d6d402166f51..ac22f4678fdc8 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.23" + "version": "14.0.4-canary.24" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 0b6a1ec0f1364..7560651fafb52 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 4f38ef5a79997..8ad742e9a1572 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.23", + "@next/eslint-plugin-next": "14.0.4-canary.24", "@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 16e17c13f82d3..9d23a48262a6e 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 2ca00e4ba41b7..920a417dd0cd1 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "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 0d8a3f99e679f..68c1fb28934f7 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 113703bb9a866..05186945d7332 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index aba071f003a97..22b3fd6f8f8f4 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index d0bb708a02264..fac4f31eb0fa9 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 37ea68836d1bc..472b3a9f7192a 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "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 02ed553fed981..f2f97bdbf45d3 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "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 c9273e7497334..5797cbebeb5e6 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 1bf0ee5613b4e..e1d2b1e3d5e13 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index fe0d003b6c23a..52bcb8e3a332a 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.23", + "@next/env": "14.0.4-canary.24", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.23", - "@next/polyfill-nomodule": "14.0.4-canary.23", - "@next/react-dev-overlay": "14.0.4-canary.23", - "@next/react-refresh-utils": "14.0.4-canary.23", - "@next/swc": "14.0.4-canary.23", + "@next/polyfill-module": "14.0.4-canary.24", + "@next/polyfill-nomodule": "14.0.4-canary.24", + "@next/react-dev-overlay": "14.0.4-canary.24", + "@next/react-refresh-utils": "14.0.4-canary.24", + "@next/swc": "14.0.4-canary.24", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 1e55f9fbb6d92..2d95f7a89f6f5 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": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 5ec55766b1371..0ae91b6f7ec3a 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "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 e768ce7d02832..37686abc819cb 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.23", + "version": "14.0.4-canary.24", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.23", + "next": "14.0.4-canary.24", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eb26c8202eda1..b57385b86dd65 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,7 +738,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -803,7 +803,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -930,19 +930,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1596,7 +1596,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.23 + specifier: 14.0.4-canary.24 version: link:../next outdent: specifier: 0.8.0 From e1a2b12beeeca2f7b4c5b7214ec44dece7039485 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 28 Nov 2023 23:22:30 +0000 Subject: [PATCH 017/189] v14.0.4-canary.25 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index ac22f4678fdc8..e8cda90f644db 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.24" + "version": "14.0.4-canary.25" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 7560651fafb52..f445caa5d3298 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8ad742e9a1572..e4c352d47dd48 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.24", + "@next/eslint-plugin-next": "14.0.4-canary.25", "@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 9d23a48262a6e..349f543fdeff3 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 920a417dd0cd1..0fd534874a73b 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "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 68c1fb28934f7..06bf49a923a53 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 05186945d7332..2823e3f3d3b62 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 22b3fd6f8f8f4..70a96c4f789b9 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index fac4f31eb0fa9..5af0e73617afb 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 472b3a9f7192a..442f4ac923e4e 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "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 f2f97bdbf45d3..6b5a678b384a3 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "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 5797cbebeb5e6..370ba33ce6b88 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index e1d2b1e3d5e13..97b943b199e23 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 52bcb8e3a332a..a5b438b7f82aa 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.24", + "@next/env": "14.0.4-canary.25", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.24", - "@next/polyfill-nomodule": "14.0.4-canary.24", - "@next/react-dev-overlay": "14.0.4-canary.24", - "@next/react-refresh-utils": "14.0.4-canary.24", - "@next/swc": "14.0.4-canary.24", + "@next/polyfill-module": "14.0.4-canary.25", + "@next/polyfill-nomodule": "14.0.4-canary.25", + "@next/react-dev-overlay": "14.0.4-canary.25", + "@next/react-refresh-utils": "14.0.4-canary.25", + "@next/swc": "14.0.4-canary.25", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 2d95f7a89f6f5..434ebddf216b2 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": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 0ae91b6f7ec3a..091400d33ab01 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "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 37686abc819cb..3fccaf91b5f16 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.24", + "version": "14.0.4-canary.25", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.24", + "next": "14.0.4-canary.25", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b57385b86dd65..9fc5f7abb5430 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,7 +738,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -803,7 +803,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -930,19 +930,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1596,7 +1596,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.24 + specifier: 14.0.4-canary.25 version: link:../next outdent: specifier: 0.8.0 From ef3c6490fe6eabcbf9a1bd51244f4d14473e1c64 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Wed, 29 Nov 2023 03:35:06 +0100 Subject: [PATCH 018/189] start performance profiling after node.js version is checked (#59028) Providing better feedback loop for next bindary. Some users with old node.js version are seeing `performance` is not defined in #57385, we should check the version first. For compilation, `performace.mark` will also be compiled after those imports since they're hoisted as ESM. This PR moves performance profiling after the `--help` and `--version` processures and node.js version check. So users can see the "upgrade node.js" hint if the node.js version is too old instead of "performance is not defined" --- packages/next/src/bin/next.ts | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/packages/next/src/bin/next.ts b/packages/next/src/bin/next.ts index dc36f33e1f921..061227d66f78e 100755 --- a/packages/next/src/bin/next.ts +++ b/packages/next/src/bin/next.ts @@ -1,5 +1,5 @@ #!/usr/bin/env node -performance.mark('next-start') + import '../server/require-hook' import * as log from '../build/output/log' import arg from 'next/dist/compiled/arg/index.js' @@ -9,7 +9,6 @@ import { commands } from '../lib/commands' import { commandArgs } from '../lib/command-args' import { getValidatedArgs } from '../lib/get-validated-args' -const defaultCommand = 'dev' const args = arg( { // Types @@ -56,6 +55,20 @@ if (!foundCommand && args['--help']) { process.exit(0) } +// Check supported Node.js version first +if ( + semver.lt(process.versions.node, process.env.__NEXT_REQUIRED_NODE_VERSION!) +) { + console.error( + `You are using Node.js ${process.versions.node}. For Next.js, Node.js version >= v${process.env.__NEXT_REQUIRED_NODE_VERSION} is required.` + ) + process.exit(1) +} + +// Start performance profiling after Node.js version is checked +performance.mark('next-start') + +const defaultCommand = 'dev' const command = foundCommand ? args._[0] : defaultCommand if (['experimental-compile', 'experimental-generate'].includes(command)) { @@ -116,15 +129,6 @@ async function main() { } } - if ( - semver.lt(process.versions.node, process.env.__NEXT_REQUIRED_NODE_VERSION!) - ) { - console.error( - `You are using Node.js ${process.versions.node}. For Next.js, Node.js version >= v${process.env.__NEXT_REQUIRED_NODE_VERSION} is required.` - ) - process.exit(1) - } - await commands[command]() .then((exec) => exec(validatedArgs)) .then(() => { From ca19ffb63b6a17e55828f601eb3677033e523e41 Mon Sep 17 00:00:00 2001 From: Tore Lervik Date: Wed, 29 Nov 2023 03:54:31 +0100 Subject: [PATCH 019/189] Fixed stale fetch using when page regenerates (#58926) fixes: #58909 x-ref: #58321, #56472, #56231 Removed the Math.round of age since it can cause stale fetch data to be considered not stale if the age rounds downwards. (5.49 is rounded to 5) Note: This most likely also fixes some bugs with revalidateTag/revalidatePath. Tested some tag/path issues that got fixed with this change. I think this is because revalidatetag/path sets [data.revalidatedAt = Date.now()](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/lib/incremental-cache/file-system-cache.ts#L120) for file-system-cache. And with the current code that value would continue to be "not stale" for up to 0.499 ms. Co-authored-by: JJ Kasper Co-authored-by: Zack Tanner --- packages/next/src/server/lib/incremental-cache/index.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/next/src/server/lib/incremental-cache/index.ts b/packages/next/src/server/lib/incremental-cache/index.ts index 271cff2ae4fa6..39c2278eca0a0 100644 --- a/packages/next/src/server/lib/incremental-cache/index.ts +++ b/packages/next/src/server/lib/incremental-cache/index.ts @@ -460,9 +460,7 @@ export class IncrementalCache implements IncrementalCacheType { } revalidate = revalidate || cacheData.value.revalidate - const age = Math.round( - (Date.now() - (cacheData.lastModified || 0)) / 1000 - ) + const age = (Date.now() - (cacheData.lastModified || 0)) / 1000 const isStale = age > revalidate const data = cacheData.value.data From 809164d7768369f4cfda0111fbdfe66bef97213e Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 28 Nov 2023 19:22:45 -0800 Subject: [PATCH 020/189] Enable PPR tests for test suites (#59030) Cherry-picks #58708 without the dependency on https://github.com/vercel/next.js/pull/58779 Co-authored-by: Wyatt Johnson <633002+wyattjoh@users.noreply.github.com> --- .github/workflows/build_and_test.yml | 52 +++++++++- package.json | 3 +- packages/next/src/server/config-shared.ts | 10 +- packages/next/src/server/config.ts | 9 ++ pnpm-lock.yaml | 3 + run-tests.js | 103 +++++++++---------- test/e2e/app-dir/rsc-basic/rsc-basic.test.ts | 18 ++-- test/get-test-filter.js | 85 +++++++++++++++ test/ppr-tests-manifest.json | 67 ++++++++++++ 9 files changed, 286 insertions(+), 64 deletions(-) create mode 100644 test/get-test-filter.js create mode 100644 test/ppr-tests-manifest.json diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index b1534867b9f19..fb0dd41371923 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -183,12 +183,10 @@ jobs: fail-fast: false matrix: group: [1, 2, 3] - uses: ./.github/workflows/build_reusable.yml with: skipForDocsOnly: 'yes' afterBuild: NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type development - secrets: inherit test-prod: @@ -198,7 +196,6 @@ jobs: fail-fast: false matrix: group: [1, 2, 3, 4, 5] - uses: ./.github/workflows/build_reusable.yml with: skipForDocsOnly: 'yes' @@ -212,7 +209,6 @@ jobs: fail-fast: false matrix: group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] - uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 @@ -230,6 +226,48 @@ jobs: afterBuild: pnpm playwright install && BROWSER_NAME=firefox node run-tests.js test/production/pages-dir/production/test/index.test.ts && BROWSER_NAME=safari NEXT_TEST_MODE=start node run-tests.js -c 1 test/production/pages-dir/production/test/index.test.ts test/e2e/basepath.test.ts && BROWSER_NAME=safari DEVICE_NAME='iPhone XR' node run-tests.js -c 1 test/production/prerender-prefetch/index.test.ts secrets: inherit + # TODO: remove these jobs once PPR is the default + # Manifest generated via: https://gist.github.com/wyattjoh/2ceaebd82a5bcff4819600fd60126431 + test-ppr-integration: + name: test ppr integration + needs: ['build-native', 'build-next'] + strategy: + fail-fast: false + matrix: + group: [1, 2, 3] + uses: ./.github/workflows/build_reusable.yml + with: + nodeVersion: 18.17.0 + skipForDocsOnly: 'yes' + afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type integration + secrets: inherit + + test-ppr-dev: + name: test ppr dev + needs: ['build-native', 'build-next'] + strategy: + fail-fast: false + matrix: + group: [1, 2, 3] + uses: ./.github/workflows/build_reusable.yml + with: + skipForDocsOnly: 'yes' + afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type development + secrets: inherit + + test-ppr-prod: + name: test ppr prod + needs: ['build-native', 'build-next'] + strategy: + fail-fast: false + matrix: + group: [1, 2, 3] + uses: ./.github/workflows/build_reusable.yml + with: + skipForDocsOnly: 'yes' + afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type production + secrets: inherit + report-test-results: needs: [ @@ -237,6 +275,9 @@ jobs: 'test-dev', 'test-prod', 'test-integration', + 'test-ppr-dev', + 'test-ppr-prod', + 'test-ppr-integration', 'test-turbopack-dev', 'test-turbopack-integration', ] @@ -275,6 +316,9 @@ jobs: 'test-dev', 'test-prod', 'test-integration', + 'test-ppr-dev', + 'test-ppr-prod', + 'test-ppr-integration', 'test-cargo-unit', 'test-cargo-integration', 'test-cargo-bench', diff --git a/package.json b/package.json index 8df96c207df80..d7f2939cbfa14 100644 --- a/package.json +++ b/package.json @@ -235,7 +235,8 @@ "webpack": "5.86.0", "webpack-bundle-analyzer": "4.7.0", "whatwg-fetch": "3.0.0", - "ws": "8.2.3" + "ws": "8.2.3", + "yargs": "16.2.0" }, "resolutions": { "webpack": "5.86.0", diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index 34f4f749ff2ca..d2dda84b82f4b 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -797,7 +797,15 @@ export const defaultConfig: NextConfig = { typedRoutes: false, instrumentationHook: false, bundlePagesExternals: false, - ppr: false, + ppr: + // TODO: remove once we've made PPR default + // If we're testing, and the `__NEXT_EXPERIMENTAL_PPR` environment variable + // has been set to `true`, enable the experimental PPR feature so long as it + // wasn't explicitly disabled in the config. + process.env.__NEXT_TEST_MODE && + process.env.__NEXT_EXPERIMENTAL_PPR === 'true' + ? true + : false, }, } diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index b0cba57e061da..3968b19e60a7a 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -251,6 +251,15 @@ function assignDefaults( {} ) + // TODO: remove once we've made PPR default + // If this was defaulted to true, it implies that the configuration was + // overridden for testing to be defaulted on. + if (defaultConfig.experimental?.ppr) { + Log.warn( + `\`experimental.ppr\` has been defaulted to \`true\` because \`__NEXT_EXPERIMENTAL_PPR\` was set to \`true\` during testing.` + ) + } + const result = { ...defaultConfig, ...config } if ( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9fc5f7abb5430..096a7bf6957e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -554,6 +554,9 @@ importers: ws: specifier: 8.2.3 version: 8.2.3 + yargs: + specifier: 16.2.0 + version: 16.2.0 bench/app-router-server: dependencies: diff --git a/run-tests.js b/run-tests.js index 95a835de6ef9a..38fa2cdfd4b6b 100644 --- a/run-tests.js +++ b/run-tests.js @@ -13,6 +13,18 @@ const { createNextInstall } = require('./test/lib/create-next-install') const glob = promisify(_glob) const exec = promisify(execOrig) const core = require('@actions/core') +const { getTestFilter } = require('./test/get-test-filter') + +let argv = require('yargs/yargs')(process.argv.slice(2)) + .string('type') + .string('test-pattern') + .boolean('timings') + .boolean('write-timings') + .boolean('debug') + .string('g') + .alias('g', 'group') + .number('c') + .alias('c', 'concurrency').argv function escapeRegexp(str) { return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') @@ -25,11 +37,8 @@ function escapeRegexp(str) { const GROUP = process.env.CI ? '##[group]' : '' const ENDGROUP = process.env.CI ? '##[endgroup]' : '' -// Try to read an external array-based json to filter tests to be allowed / or disallowed. -// If process.argv contains a test to be executed, this'll append it to the list. -const externalTestsFilterLists = process.env.NEXT_EXTERNAL_TESTS_FILTERS - ? require(process.env.NEXT_EXTERNAL_TESTS_FILTERS) - : null +const externalTestsFilter = getTestFilter() + const timings = [] const DEFAULT_NUM_RETRIES = os.platform() === 'win32' ? 2 : 1 const DEFAULT_CONCURRENCY = 2 @@ -173,23 +182,25 @@ async function getTestTimings() { async function main() { let numRetries = DEFAULT_NUM_RETRIES - let concurrencyIdx = process.argv.indexOf('-c') - let concurrency = - (concurrencyIdx > -1 && parseInt(process.argv[concurrencyIdx + 1], 10)) || - DEFAULT_CONCURRENCY - - const hideOutput = !process.argv.includes('--debug') - const outputTimings = process.argv.includes('--timings') - const writeTimings = process.argv.includes('--write-timings') - const groupIdx = process.argv.indexOf('-g') - const groupArg = groupIdx !== -1 && process.argv[groupIdx + 1] - const testPatternIdx = process.argv.indexOf('--test-pattern') - const testPattern = testPatternIdx !== -1 && process.argv[testPatternIdx + 1] - const testTypeIdx = process.argv.indexOf('--type') - const testType = testTypeIdx > -1 ? process.argv[testTypeIdx + 1] : undefined + + // Ensure we have the arguments awaited from yargs. + argv = await argv + + const options = { + concurrency: argv.concurrency || DEFAULT_CONCURRENCY, + debug: argv.debug ?? false, + timings: argv.timings ?? false, + writeTimings: argv.writeTimings ?? false, + group: argv.group ?? false, + testPattern: argv.testPattern ?? false, + type: argv.type ?? false, + } + + const hideOutput = !options.debug + let filterTestsBy - switch (testType) { + switch (options.type) { case 'unit': { numRetries = 0 filterTestsBy = testFilters.unit @@ -200,27 +211,27 @@ async function main() { break } default: { - filterTestsBy = testFilters[testType] + filterTestsBy = testFilters[options.type] break } } - console.log('Running tests with concurrency:', concurrency) + console.log('Running tests with concurrency:', options.concurrency) /** @type TestFile[] */ - let tests = process.argv - .filter((arg) => arg.match(/\.test\.(js|ts|tsx)/)) - .map((file) => ({ + let tests = argv._.filter((arg) => arg.match(/\.test\.(js|ts|tsx)/)).map( + (file) => ({ file, excludedCases: [], - })) + }) + ) let prevTimings if (tests.length === 0) { let testPatternRegex - if (testPattern) { - testPatternRegex = new RegExp(testPattern) + if (options.testPattern) { + testPatternRegex = new RegExp(options.testPattern) } tests = ( @@ -252,7 +263,7 @@ async function main() { })) } - if (outputTimings && groupArg) { + if (options.timings && options.group) { console.log('Fetching previous timings data') try { const timingsFile = path.join(process.cwd(), 'test-timings.json') @@ -267,7 +278,7 @@ async function main() { prevTimings = await getTestTimings() console.log('Fetched previous timings data successfully') - if (writeTimings) { + if (options.writeTimings) { await fsp.writeFile(timingsFile, JSON.stringify(prevTimings)) console.log('Wrote previous timings data to', timingsFile) await cleanUpAndExit(0) @@ -280,20 +291,8 @@ async function main() { } // If there are external manifest contains list of tests, apply it to the test lists. - if (externalTestsFilterLists) { - tests = tests - .filter((test) => { - const info = externalTestsFilterLists[test.file] - return info && info.passed.length > 0 && !info.runtimeError - }) - .map((test) => { - const info = externalTestsFilterLists[test.file] - // Exclude failing and flakey tests, newly added tests are automatically included - if (info.failed.length > 0 || info.flakey.length > 0) { - test.excludedCases = info.failed.concat(info.flakey) - } - return test - }) + if (externalTestsFilter) { + tests = externalTestsFilter(tests) } let testSet = new Set() @@ -308,8 +307,8 @@ async function main() { return true }) - if (groupArg) { - const groupParts = groupArg.split('/') + if (options.group) { + const groupParts = options.group.split('/') const groupPos = parseInt(groupParts[0], 10) const groupTotal = parseInt(groupParts[1], 10) @@ -354,7 +353,7 @@ async function main() { } if (tests.length === 0) { - console.log('No tests found for', testType, 'exiting..') + console.log('No tests found for', options.type, 'exiting..') return cleanUpAndExit(1) } @@ -373,7 +372,7 @@ ${ENDGROUP}`) if ( process.platform !== 'win32' && process.env.NEXT_TEST_MODE !== 'deploy' && - ((testType && testType !== 'unit') || hasIsolatedTests) + ((options.type && options.type !== 'unit') || hasIsolatedTests) ) { // for isolated next tests: e2e, dev, prod we create // a starter Next.js install to re-use to speed up tests @@ -400,7 +399,7 @@ ${ENDGROUP}`) console.log(`${ENDGROUP}`) } - const sema = new Sema(concurrency, { capacity: tests.length }) + const sema = new Sema(options.concurrency, { capacity: tests.length }) const outputSema = new Sema(1, { capacity: tests.length }) const children = new Set() const jestPath = path.join( @@ -462,8 +461,8 @@ ${ENDGROUP}`) // [NOTE]: This won't affect if junit reporter is not enabled JEST_SUITE_NAME: [ `${process.env.NEXT_TEST_MODE ?? 'default'}`, - groupArg, - testType, + options.group, + options.type, test.file, ] .filter(Boolean) @@ -681,7 +680,7 @@ ${ENDGROUP}`) }) ) - if (outputTimings) { + if (options.timings) { const curTimings = {} // let junitData = `` /* diff --git a/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts b/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts index b8d7c7f336adf..3d8b005d2115e 100644 --- a/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts +++ b/test/e2e/app-dir/rsc-basic/rsc-basic.test.ts @@ -454,6 +454,12 @@ createNextDescribe( expect(await res.text()).toBe('Hello from import-test.js') }) + // TODO: (PPR) remove once PPR is stable + const bundledReactVersionPattern = + process.env.__NEXT_EXPERIMENTAL_PPR === 'true' + ? '-experimental-' + : '-canary-' + it('should not use bundled react for pages with app', async () => { const ssrPaths = ['/pages-react', '/edge-pages-react'] const promises = ssrPaths.map(async (pathname) => { @@ -465,7 +471,7 @@ createNextDescribe( ] ssrPagesReactVersions.forEach((version) => { - expect(version).not.toMatch('-canary-') + expect(version).not.toMatch(bundledReactVersionPattern) }) }) await Promise.all(promises) @@ -478,7 +484,7 @@ createNextDescribe( ] ssrAppReactVersions.forEach((version) => - expect(version).toMatch('-canary-') + expect(version).toMatch(bundledReactVersionPattern) ) const browser = await next.browser('/pages-react') @@ -500,10 +506,10 @@ createNextDescribe( `) browserPagesReactVersions.forEach((version) => - expect(version).not.toMatch('-canary-') + expect(version).not.toMatch(bundledReactVersionPattern) ) browserEdgePagesReactVersions.forEach((version) => - expect(version).not.toMatch('-canary-') + expect(version).not.toMatch(bundledReactVersionPattern) ) }) @@ -519,7 +525,7 @@ createNextDescribe( ] ssrPagesReactVersions.forEach((version) => { - expect(version).toMatch('-canary-') + expect(version).toMatch(bundledReactVersionPattern) }) const browser = await next.browser('/app-react') @@ -534,7 +540,7 @@ createNextDescribe( ] `) browserAppReactVersions.forEach((version) => - expect(version).toMatch('-canary-') + expect(version).toMatch(bundledReactVersionPattern) ) }) diff --git a/test/get-test-filter.js b/test/get-test-filter.js new file mode 100644 index 0000000000000..4eacd8f083ac6 --- /dev/null +++ b/test/get-test-filter.js @@ -0,0 +1,85 @@ +const path = require('path') +const minimatch = require('minimatch') + +function getTestFilter() { + const manifest = process.env.NEXT_EXTERNAL_TESTS_FILTERS + ? require(path.resolve(process.env.NEXT_EXTERNAL_TESTS_FILTERS)) + : null + if (!manifest) return null + + // For the legacy manifest without a version, we assume it's a complete list + // of all the tests. + if (!manifest.version || typeof manifest.version !== 'number') { + return (tests) => + tests + .filter((test) => { + const info = manifest[test.file] + return info && info.passed.length > 0 && !info.runtimeError + }) + .map((test) => { + const info = manifest[test.file] + // Exclude failing and flakey tests, newly added tests are automatically included + if (info.failed.length > 0 || info.flakey.length > 0) { + test.excludedCases = info.failed.concat(info.flakey) + } + return test + }) + } + + // The new manifest version 2 only contains the list of tests that should + // be run, with exclusions added based on rules. Any new tests that are added + // will be automatically included if they match the include rules. + if (manifest.version === 2) { + return (tests) => + tests + .filter((test) => { + // Check to see if this was included as-is in the manifest. + if (test.file in manifest.suites) return true + + // If this file doesn't match any of the include patterns, then it + // should be excluded. + if ( + manifest.rules.include.every( + (pattern) => !minimatch(test.file, pattern) + ) + ) { + return false + } + + // If the file matches any of the exclude patterns, then it should be + // excluded. + if ( + manifest.rules.exclude?.some((pattern) => + minimatch(test.file, pattern) + ) + ) { + return false + } + + // Otherwise, it should be included. + return true + }) + .map((test) => { + const info = manifest.suites[test.file] + + // If there's no info for this test, then it's a test that has no + // failures or flakey tests, so we can just include it as-is. + if (!info) { + return test + } + + // Exclude failing and flakey tests, newly added tests are + // automatically included. + const { failed = [], flakey = [] } = info + if (failed.length > 0 || flakey.length > 0) { + test.excludedCases = failed.concat(flakey) + } + + return test + }) + } + + throw new Error(`Unknown manifest version: ${manifest.version}`) +} + +module.exports = { getTestFilter } diff --git a/test/ppr-tests-manifest.json b/test/ppr-tests-manifest.json new file mode 100644 index 0000000000000..faaa19186704e --- /dev/null +++ b/test/ppr-tests-manifest.json @@ -0,0 +1,67 @@ +{ + "version": 2, + "suites": { + "test/e2e/app-dir/app-client-cache/client-cache.test.ts": { + "failed": [ + "app dir client cache semantics prefetch={undefined} - default should re-use the full cache for only 30 seconds", + "app dir client cache semantics prefetch={undefined} - default should refetch below the fold after 30 seconds" + ] + }, + "test/e2e/app-dir/headers-static-bailout/headers-static-bailout.test.ts": { + "failed": [ + "headers-static-bailout it provides a helpful link in case static generation bailout is uncaught" + ] + }, + "test/e2e/app-dir/parallel-routes-and-interception/parallel-routes-and-interception.test.ts": { + "failed": [ + "parallel-routes-and-interception route intercepting should render modal when paired with parallel routes", + "parallel-routes-and-interception route intercepting should support intercepting local dynamic sibling routes" + ] + }, + "test/e2e/app-dir/error-boundary-navigation/override-node-env.test.ts": { + "failed": [ + "app dir - not found navigation - with overridden node env should be able to navigate to other page from root not-found page" + ] + }, + "test/e2e/opentelemetry/opentelemetry.test.ts": { + "failed": [ + "opentelemetry root context app router should handle RSC with fetch", + "opentelemetry incoming context propagation app router should handle RSC with fetch", + "opentelemetry incoming context propagation app router should handle route handlers in app router" + ] + }, + "test/e2e/app-dir/rsc-basic/rsc-basic.test.ts": { + "failed": [ + "app dir - rsc basics should render initial styles of css-in-js in edge SSR correctly", + "app dir - rsc basics should render initial styles of css-in-js in nodejs SSR correctly", + "app dir - rsc basics should render server components correctly" + ] + }, + "test/production/app-dir/unexpected-error/unexpected-error.test.ts": { + "failed": [ + "unexpected-error should set response status to 500 for unexpected errors in ssr app route", + "unexpected-error should set response status to 500 for unexpected errors in isr app route" + ] + } + }, + "rules": { + "include": [ + "test/e2e/**/*.test.{t,j}s{,x}", + "test/integration/app-*/**/*.test.{t,j}s{,x}", + "test/production/app-*/**/*.test.{t,j}s{,x}", + "test/development/app-*/**/*.test.{t,j}s{,x}" + ], + "exclude": [ + "test/integration/app-dir-export/**/*", + "test/e2e/app-dir/next-font/**/*", + "test/e2e/app-dir/ppr/**/*", + "test/e2e/app-dir/app-prefetch*/**/*", + "test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts", + "test/e2e/app-dir/searchparams-static-bailout/searchparams-static-bailout.test.ts", + "test/e2e/app-dir/app-static/app-static-custom-handler.test.ts", + "test/e2e/app-dir/app-static/app-static.test.ts", + "test/e2e/app-dir/app-static/app-static-custom-cache-handler-esm.test.ts", + "test/e2e/app-dir/navigation/navigation.test.ts" + ] + } +} From 4d55364b7a8a3c363fc0e72b191cc6f6cd7af0af Mon Sep 17 00:00:00 2001 From: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com> Date: Wed, 29 Nov 2023 03:08:15 -0500 Subject: [PATCH 021/189] Update font data (#59043) This auto-generated PR updates font data with latest available --- packages/font/src/google/font-data.json | 26 ++++++++++++++--- packages/font/src/google/index.ts | 39 ++++++++++++++++++++++--- 2 files changed, 57 insertions(+), 8 deletions(-) diff --git a/packages/font/src/google/font-data.json b/packages/font/src/google/font-data.json index dc9db8b040144..7a05dc31961a1 100644 --- a/packages/font/src/google/font-data.json +++ b/packages/font/src/google/font-data.json @@ -4583,6 +4583,24 @@ "styles": ["normal"], "subsets": ["latin", "latin-ext"] }, + "Hedvig Letters Sans": { + "weights": ["400"], + "styles": ["normal"], + "subsets": ["latin", "latin-ext", "math", "symbols"] + }, + "Hedvig Letters Serif": { + "weights": ["400", "variable"], + "styles": ["normal"], + "axes": [ + { + "tag": "opsz", + "min": 12, + "max": 24, + "defaultValue": 24 + } + ], + "subsets": ["latin", "latin-ext", "math", "symbols"] + }, "Heebo": { "weights": [ "100", @@ -7124,9 +7142,9 @@ "subsets": ["latin"] }, "Narnoor": { - "weights": ["400"], + "weights": ["400", "500", "600", "700", "800"], "styles": ["normal"], - "subsets": ["gunjala-gondi", "latin", "latin-ext"] + "subsets": ["gunjala-gondi", "latin", "latin-ext", "math", "symbols"] }, "Neonderthaw": { "weights": ["400"], @@ -7841,7 +7859,7 @@ "defaultValue": 400 } ], - "subsets": ["gujarati", "latin", "latin-ext"] + "subsets": ["gujarati", "latin", "latin-ext", "math", "symbols"] }, "Noto Sans Gunjala Gondi": { "weights": ["400", "500", "600", "700", "variable"], @@ -9370,7 +9388,7 @@ "defaultValue": 400 } ], - "subsets": ["gujarati", "latin", "latin-ext"] + "subsets": ["gujarati", "latin", "latin-ext", "math", "symbols"] }, "Noto Serif Gurmukhi": { "weights": [ diff --git a/packages/font/src/google/index.ts b/packages/font/src/google/index.ts index 8637b15f5a3c9..c6b9cd987f496 100644 --- a/packages/font/src/google/index.ts +++ b/packages/font/src/google/index.ts @@ -8078,6 +8078,31 @@ export declare function Headland_One< adjustFontFallback?: boolean subsets?: Array<'latin' | 'latin-ext'> }): T extends undefined ? NextFont : NextFontWithVariable +export declare function Hedvig_Letters_Sans< + T extends CssVariable | undefined = undefined +>(options: { + weight: '400' | Array<'400'> + style?: 'normal' | Array<'normal'> + display?: Display + variable?: T + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + subsets?: Array<'latin' | 'latin-ext' | 'math' | 'symbols'> +}): T extends undefined ? NextFont : NextFontWithVariable +export declare function Hedvig_Letters_Serif< + T extends CssVariable | undefined = undefined +>(options?: { + weight?: '400' | 'variable' | Array<'400'> + style?: 'normal' | Array<'normal'> + display?: Display + variable?: T + preload?: boolean + fallback?: string[] + adjustFontFallback?: boolean + subsets?: Array<'latin' | 'latin-ext' | 'math' | 'symbols'> + axes?: 'opsz'[] +}): T extends undefined ? NextFont : NextFontWithVariable export declare function Heebo< T extends CssVariable | undefined = undefined >(options?: { @@ -12960,14 +12985,20 @@ export declare function Nanum_Pen_Script< export declare function Narnoor< T extends CssVariable | undefined = undefined >(options: { - weight: '400' | Array<'400'> + weight: + | '400' + | '500' + | '600' + | '700' + | '800' + | Array<'400' | '500' | '600' | '700' | '800'> style?: 'normal' | Array<'normal'> display?: Display variable?: T preload?: boolean fallback?: string[] adjustFontFallback?: boolean - subsets?: Array<'gunjala-gondi' | 'latin' | 'latin-ext'> + subsets?: Array<'gunjala-gondi' | 'latin' | 'latin-ext' | 'math' | 'symbols'> }): T extends undefined ? NextFont : NextFontWithVariable export declare function Neonderthaw< T extends CssVariable | undefined = undefined @@ -14030,7 +14061,7 @@ export declare function Noto_Sans_Gujarati< preload?: boolean fallback?: string[] adjustFontFallback?: boolean - subsets?: Array<'gujarati' | 'latin' | 'latin-ext'> + subsets?: Array<'gujarati' | 'latin' | 'latin-ext' | 'math' | 'symbols'> axes?: 'wdth'[] }): T extends undefined ? NextFont : NextFontWithVariable export declare function Noto_Sans_Gunjala_Gondi< @@ -16178,7 +16209,7 @@ export declare function Noto_Serif_Gujarati< preload?: boolean fallback?: string[] adjustFontFallback?: boolean - subsets?: Array<'gujarati' | 'latin' | 'latin-ext'> + subsets?: Array<'gujarati' | 'latin' | 'latin-ext' | 'math' | 'symbols'> }): T extends undefined ? NextFont : NextFontWithVariable export declare function Noto_Serif_Gurmukhi< T extends CssVariable | undefined = undefined From 9656f15a484b94d3c1f76f76b3fa9ca37013a35a Mon Sep 17 00:00:00 2001 From: Lee Robinson Date: Wed, 29 Nov 2023 02:26:03 -0600 Subject: [PATCH 022/189] docs: patch upgrade guide to pin install version (#58993) Closes https://github.com/vercel/feedback/issues/47076. --- .../08-upgrading/04-version-13.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/03-pages/01-building-your-application/08-upgrading/04-version-13.mdx b/docs/03-pages/01-building-your-application/08-upgrading/04-version-13.mdx index a0ecf42876019..f58193db64ad7 100644 --- a/docs/03-pages/01-building-your-application/08-upgrading/04-version-13.mdx +++ b/docs/03-pages/01-building-your-application/08-upgrading/04-version-13.mdx @@ -8,19 +8,19 @@ description: Upgrade your Next.js Application from Version 12 to 13. To update to Next.js version 13, run the following command using your preferred package manager: ```bash filename="Terminal" -npm i next@latest react@latest react-dom@latest eslint-config-next@latest +npm i next@13 react@latest react-dom@latest eslint-config-next@13 ``` ```bash filename="Terminal" -yarn add next@latest react@latest react-dom@latest eslint-config-next@latest +yarn add next@13 react@latest react-dom@latest eslint-config-next@13 ``` ```bash filename="Terminal" -pnpm up next react react-dom eslint-config-next --latest +pnpm i next@13 react@latest react-dom@latest eslint-config-next@13 ``` ```bash filename="Terminal" -bun add next@latest react@latest react-dom@latest eslint-config-next@latest +bun add next@13 react@latest react-dom@latest eslint-config-next@13 ``` > **Good to know:** If you are using TypeScript, ensure you also upgrade `@types/react` and `@types/react-dom` to their latest versions. From eafaba39cba3287add4726f7884973a78430325d Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 29 Nov 2023 00:35:50 -0800 Subject: [PATCH 023/189] update status codes for `redirect` and `permanentRedirect` in action handlers (#58885) ### What? Calling `redirect` or `permanentRedirect` with a route handler used by a server action will result in that POST request following the redirect. This could result in unexpected behavior, such as re-submitting an action (in the case where the redirected URL makes use of the same server action). ### Why? By spec, 307 and 308 status codes will attempt to reuse the original request method & body on the redirected URL. ### How? In all cases when calling a `redirect` handler inside of an action, we'll return a `303 See Other` response which is a typical status code when redirecting to a success / confirmation page as a result of a POST/PUT. The other option would be to use 301 / 302 status codes, but since we're already doing a 303 status code [here](https://github.com/vercel/next.js/blob/canary/packages/next/src/server/app-render/action-handler.ts#L603), this aligns the behavior for the route handler case. Closes NEXT-1733 See also: https://github.com/vercel/next.js/issues/51592#issuecomment-1810212676 [Slack x-ref](https://vercel.slack.com/archives/C03S8ED1DKM/p1700060786749079) --- .../04-functions/permanentRedirect.mdx | 2 +- .../04-functions/redirect.mdx | 2 +- .../next/src/client/components/redirect.ts | 50 ++++++++++---- packages/next/src/lib/redirect-status.ts | 9 ++- .../src/server/app-render/action-handler.ts | 4 +- .../make-get-server-inserted-html.tsx | 4 +- packages/next/src/server/base-http/index.ts | 4 +- packages/next/src/server/base-server.ts | 4 +- .../future/route-modules/app-route/module.ts | 2 + packages/next/src/server/lib/router-server.ts | 4 +- .../server/lib/server-action-request-meta.ts | 14 ++-- packages/next/src/shared/lib/constants.ts | 8 ++- ...app-action-progressive-enhancement.test.ts | 13 ++++ test/e2e/app-dir/actions/app-action.test.ts | 67 ++++++++++++++++++- .../redirects/api-redirect-permanent/route.js | 5 ++ .../app/redirects/api-redirect/route.js | 5 ++ .../e2e/app-dir/actions/app/redirects/page.js | 18 +++++ 17 files changed, 181 insertions(+), 34 deletions(-) create mode 100644 test/e2e/app-dir/actions/app/redirects/api-redirect-permanent/route.js create mode 100644 test/e2e/app-dir/actions/app/redirects/api-redirect/route.js create mode 100644 test/e2e/app-dir/actions/app/redirects/page.js diff --git a/docs/02-app/02-api-reference/04-functions/permanentRedirect.mdx b/docs/02-app/02-api-reference/04-functions/permanentRedirect.mdx index 3162d2a8c7027..cd2279636fdb8 100644 --- a/docs/02-app/02-api-reference/04-functions/permanentRedirect.mdx +++ b/docs/02-app/02-api-reference/04-functions/permanentRedirect.mdx @@ -5,7 +5,7 @@ description: API Reference for the permanentRedirect function. The `permanentRedirect` function allows you to redirect the user to another URL. `permanentRedirect` can be used in Server Components, Client Components, [Route Handlers](/docs/app/building-your-application/routing/route-handlers), and [Server Actions](/docs/app/building-your-application/data-fetching/forms-and-mutations). -When used in a streaming context, this will insert a meta tag to emit the redirect on the client side. Otherwise, it will serve a 308 (Permanent) HTTP redirect response to the caller. +When used in a streaming context, this will insert a meta tag to emit the redirect on the client side. When used in a server action, it will serve a 303 HTTP redirect response to the caller. Otherwise, it will serve a 308 (Permanent) HTTP redirect response to the caller. If a resource doesn't exist, you can use the [`notFound` function](/docs/app/api-reference/functions/not-found) instead. diff --git a/docs/02-app/02-api-reference/04-functions/redirect.mdx b/docs/02-app/02-api-reference/04-functions/redirect.mdx index 6ab95b3bc5a6b..5ef879da65aac 100644 --- a/docs/02-app/02-api-reference/04-functions/redirect.mdx +++ b/docs/02-app/02-api-reference/04-functions/redirect.mdx @@ -5,7 +5,7 @@ description: API Reference for the redirect function. The `redirect` function allows you to redirect the user to another URL. `redirect` can be used in Server Components, Client Components, [Route Handlers](/docs/app/building-your-application/routing/route-handlers), and [Server Actions](/docs/app/building-your-application/data-fetching/forms-and-mutations). -When used in a [streaming context](/docs/app/building-your-application/routing/loading-ui-and-streaming#what-is-streaming), this will insert a meta tag to emit the redirect on the client side. Otherwise, it will serve a 307 HTTP redirect response to the caller. +When used in a [streaming context](/docs/app/building-your-application/routing/loading-ui-and-streaming#what-is-streaming), this will insert a meta tag to emit the redirect on the client side. When used in a server action, it will serve a 303 HTTP redirect response to the caller. Otherwise, it will serve a 307 HTTP redirect response to the caller. If a resource doesn't exist, you can use the [`notFound` function](/docs/app/api-reference/functions/not-found) instead. diff --git a/packages/next/src/client/components/redirect.ts b/packages/next/src/client/components/redirect.ts index d21deecb7754a..28ad8f0fafad8 100644 --- a/packages/next/src/client/components/redirect.ts +++ b/packages/next/src/client/components/redirect.ts @@ -1,5 +1,7 @@ import { requestAsyncStorage } from './request-async-storage.external' import type { ResponseCookies } from '../../server/web/spec-extension/cookies' +import { actionAsyncStorage } from './action-async-storage.external' +import { RedirectStatusCode } from '../../shared/lib/constants' const REDIRECT_ERROR_CODE = 'NEXT_REDIRECT' @@ -9,17 +11,17 @@ export enum RedirectType { } export type RedirectError = Error & { - digest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${U};${boolean}` + digest: `${typeof REDIRECT_ERROR_CODE};${RedirectType};${U};${RedirectStatusCode};` mutableCookies: ResponseCookies } export function getRedirectError( url: string, type: RedirectType, - permanent: boolean = false + statusCode: RedirectStatusCode = RedirectStatusCode.TemporaryRedirect ): RedirectError { const error = new Error(REDIRECT_ERROR_CODE) as RedirectError - error.digest = `${REDIRECT_ERROR_CODE};${type};${url};${permanent}` + error.digest = `${REDIRECT_ERROR_CODE};${type};${url};${statusCode};` const requestStore = requestAsyncStorage.getStore() if (requestStore) { error.mutableCookies = requestStore.mutableCookies @@ -30,7 +32,7 @@ export function getRedirectError( /** * When used in a streaming context, this will insert a meta tag to * redirect the user to the target page. When used in a custom app route, it - * will serve a 307 to the caller. + * will serve a 307/303 to the caller. * * @param url the url to redirect to */ @@ -38,13 +40,23 @@ export function redirect( url: string, type: RedirectType = RedirectType.replace ): never { - throw getRedirectError(url, type, false) + const actionStore = actionAsyncStorage.getStore() + throw getRedirectError( + url, + type, + // If we're in an action, we want to use a 303 redirect + // as we don't want the POST request to follow the redirect, + // as it could result in erroneous re-submissions. + actionStore?.isAction + ? RedirectStatusCode.SeeOther + : RedirectStatusCode.TemporaryRedirect + ) } /** * When used in a streaming context, this will insert a meta tag to * redirect the user to the target page. When used in a custom app route, it - * will serve a 308 to the caller. + * will serve a 308/303 to the caller. * * @param url the url to redirect to */ @@ -52,7 +64,17 @@ export function permanentRedirect( url: string, type: RedirectType = RedirectType.replace ): never { - throw getRedirectError(url, type, true) + const actionStore = actionAsyncStorage.getStore() + throw getRedirectError( + url, + type, + // If we're in an action, we want to use a 303 redirect + // as we don't want the POST request to follow the redirect, + // as it could result in erroneous re-submissions. + actionStore?.isAction + ? RedirectStatusCode.SeeOther + : RedirectStatusCode.PermanentRedirect + ) } /** @@ -67,15 +89,19 @@ export function isRedirectError( ): error is RedirectError { if (typeof error?.digest !== 'string') return false - const [errorCode, type, destination, permanent] = ( - error.digest as string - ).split(';', 4) + const [errorCode, type, destination, status] = (error.digest as string).split( + ';', + 4 + ) + + const statusCode = Number(status) return ( errorCode === REDIRECT_ERROR_CODE && (type === 'replace' || type === 'push') && typeof destination === 'string' && - (permanent === 'true' || permanent === 'false') + !isNaN(statusCode) && + statusCode in RedirectStatusCode ) } @@ -114,5 +140,5 @@ export function getRedirectStatusCodeFromError( throw new Error('Not a redirect error') } - return error.digest.split(';', 4)[3] === 'true' ? 308 : 307 + return Number(error.digest.split(';', 4)[3]) } diff --git a/packages/next/src/lib/redirect-status.ts b/packages/next/src/lib/redirect-status.ts index 5483a02a55e70..d4fd5740edfd2 100644 --- a/packages/next/src/lib/redirect-status.ts +++ b/packages/next/src/lib/redirect-status.ts @@ -1,7 +1,4 @@ -import { - PERMANENT_REDIRECT_STATUS, - TEMPORARY_REDIRECT_STATUS, -} from '../shared/lib/constants' +import { RedirectStatusCode } from '../shared/lib/constants' export const allowedStatusCodes = new Set([301, 302, 303, 307, 308]) @@ -11,7 +8,9 @@ export function getRedirectStatus(route: { }): number { return ( route.statusCode || - (route.permanent ? PERMANENT_REDIRECT_STATUS : TEMPORARY_REDIRECT_STATUS) + (route.permanent + ? RedirectStatusCode.PermanentRedirect + : RedirectStatusCode.TemporaryRedirect) ) } diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index d507553404e8a..11614419091fe 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -16,6 +16,7 @@ import { } from '../../client/components/app-router-headers' import { isNotFoundError } from '../../client/components/not-found' import { + getRedirectStatusCodeFromError, getURLFromRedirectError, isRedirectError, } from '../../client/components/redirect' @@ -574,6 +575,7 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc } catch (err) { if (isRedirectError(err)) { const redirectUrl = getURLFromRedirectError(err) + const statusCode = getRedirectStatusCodeFromError(err) // if it's a fetch action, we don't want to mess with the status code // and we'll handle it on the client router @@ -605,7 +607,7 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc } res.setHeader('Location', redirectUrl) - res.statusCode = 303 + res.statusCode = statusCode return { type: 'done', result: RenderResult.fromStatic(''), diff --git a/packages/next/src/server/app-render/make-get-server-inserted-html.tsx b/packages/next/src/server/app-render/make-get-server-inserted-html.tsx index 7e4505823105e..11c8e7ec46298 100644 --- a/packages/next/src/server/app-render/make-get-server-inserted-html.tsx +++ b/packages/next/src/server/app-render/make-get-server-inserted-html.tsx @@ -7,6 +7,7 @@ import { } from '../../client/components/redirect' import { renderToReadableStream } from 'react-dom/server.edge' import { streamToString } from '../stream-utils/node-web-streams-helper' +import { RedirectStatusCode } from '../../shared/lib/constants' export function makeGetServerInsertedHTML({ polyfills, @@ -38,8 +39,9 @@ export function makeGetServerInsertedHTML({ ) } else if (isRedirectError(error)) { const redirectUrl = getURLFromRedirectError(error) + const statusCode = getRedirectStatusCodeFromError(error) const isPermanent = - getRedirectStatusCodeFromError(error) === 308 ? true : false + statusCode === RedirectStatusCode.PermanentRedirect ? true : false if (redirectUrl) { errorMetaTags.push( { // Since IE11 doesn't support the 308 header add backwards // compatibility using refresh header - if (statusCode === PERMANENT_REDIRECT_STATUS) { + if (statusCode === RedirectStatusCode.PermanentRedirect) { this.setHeader('Refresh', `0;url=${destination}`) } return this diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index ba353d82ee7bb..bd8b872095bf2 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -50,8 +50,8 @@ import { APP_PATHS_MANIFEST, NEXT_BUILTIN_DOCUMENT, PAGES_MANIFEST, + RedirectStatusCode, STATIC_STATUS_PAGES, - TEMPORARY_REDIRECT_STATUS, } from '../shared/lib/constants' import { isDynamicRoute } from '../shared/lib/router/utils' import { checkIsOnDemandRevalidate } from './api-utils' @@ -1213,7 +1213,7 @@ export default abstract class Server { if (redirect) { return res - .redirect(redirect, TEMPORARY_REDIRECT_STATUS) + .redirect(redirect, RedirectStatusCode.TemporaryRedirect) .body(redirect) .send() } 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 0aab61b356361..eb8cc3e41d5f9 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 @@ -42,6 +42,7 @@ import { requestAsyncStorage } from '../../../../client/components/request-async 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' +import { getIsServerAction } from '../../../lib/server-action-request-meta' /** * The AppRouteModule is the type of the module exported by the bundled App @@ -274,6 +275,7 @@ export class AppRouteRouteModule extends RouteModule< const response: unknown = await this.actionAsyncStorage.run( { isAppRoute: true, + isAction: getIsServerAction(request), }, () => RequestAsyncStorageWrapper.wrap( diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index c04bb1ce4a4ec..46c563ca38e2a 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -29,7 +29,7 @@ import { isPostpone } from './router-utils/is-postpone' import { PHASE_PRODUCTION_SERVER, PHASE_DEVELOPMENT_SERVER, - PERMANENT_REDIRECT_STATUS, + RedirectStatusCode, } from '../../shared/lib/constants' import { DevBundlerService } from './dev-bundler-service' import { type Span, trace } from '../../trace' @@ -353,7 +353,7 @@ export async function initialize(opts: { res.statusCode = statusCode res.setHeader('location', destination) - if (statusCode === PERMANENT_REDIRECT_STATUS) { + if (statusCode === RedirectStatusCode.PermanentRedirect) { res.setHeader('Refresh', `0;url=${destination}`) } return res.end(destination) diff --git a/packages/next/src/server/lib/server-action-request-meta.ts b/packages/next/src/server/lib/server-action-request-meta.ts index 4d18a3dae58fb..45e5ff7a7dd8b 100644 --- a/packages/next/src/server/lib/server-action-request-meta.ts +++ b/packages/next/src/server/lib/server-action-request-meta.ts @@ -1,9 +1,10 @@ import type { IncomingMessage } from 'http' import type { BaseNextRequest } from '../base-http' +import type { NextRequest } from '../web/exports' import { ACTION } from '../../client/components/app-router-headers' export function getServerActionRequestMetadata( - req: IncomingMessage | BaseNextRequest + req: IncomingMessage | BaseNextRequest | NextRequest ): { actionId: string | null isURLEncodedAction: boolean @@ -13,8 +14,13 @@ export function getServerActionRequestMetadata( let actionId: string | null let contentType: string | null - actionId = (req.headers[ACTION.toLowerCase()] as string) ?? null - contentType = req.headers['content-type'] ?? null + if (req.headers instanceof Headers) { + actionId = req.headers.get(ACTION.toLowerCase()) ?? null + contentType = req.headers.get('content-type') + } else { + actionId = (req.headers[ACTION.toLowerCase()] as string) ?? null + contentType = req.headers['content-type'] ?? null + } const isURLEncodedAction = Boolean( req.method === 'POST' && contentType === 'application/x-www-form-urlencoded' @@ -32,7 +38,7 @@ export function getServerActionRequestMetadata( } export function getIsServerAction( - req: IncomingMessage | BaseNextRequest + req: IncomingMessage | BaseNextRequest | NextRequest ): boolean { const { isFetchAction, isURLEncodedAction, isMultipartAction } = getServerActionRequestMetadata(req) diff --git a/packages/next/src/shared/lib/constants.ts b/packages/next/src/shared/lib/constants.ts index 69ef1107ab3aa..d02e14896c7ac 100644 --- a/packages/next/src/shared/lib/constants.ts +++ b/packages/next/src/shared/lib/constants.ts @@ -95,8 +95,6 @@ export const CLIENT_STATIC_FILES_RUNTIME_POLYFILLS_SYMBOL = Symbol( CLIENT_STATIC_FILES_RUNTIME_POLYFILLS ) export const EDGE_RUNTIME_WEBPACK = 'edge-runtime-webpack' -export const TEMPORARY_REDIRECT_STATUS = 307 -export const PERMANENT_REDIRECT_STATUS = 308 export const STATIC_PROPS_ID = '__N_SSG' export const SERVER_PROPS_ID = '__N_SSP' export const PAGE_SEGMENT_KEY = '__PAGE__' @@ -156,3 +154,9 @@ export const SYSTEM_ENTRYPOINTS = new Set([ CLIENT_STATIC_FILES_RUNTIME_AMP, CLIENT_STATIC_FILES_RUNTIME_MAIN_APP, ]) + +export enum RedirectStatusCode { + SeeOther = 303, + TemporaryRedirect = 307, + PermanentRedirect = 308, +} diff --git a/test/e2e/app-dir/actions/app-action-progressive-enhancement.test.ts b/test/e2e/app-dir/actions/app-action-progressive-enhancement.test.ts index 13951b3448006..f1e17141a0284 100644 --- a/test/e2e/app-dir/actions/app-action-progressive-enhancement.test.ts +++ b/test/e2e/app-dir/actions/app-action-progressive-enhancement.test.ts @@ -1,6 +1,7 @@ /* eslint-disable jest/no-standalone-expect */ import { createNextDescribe } from 'e2e-utils' import { check } from 'next-test-utils' +import type { Response } from 'playwright-chromium' createNextDescribe( 'app-dir action progressive enhancement', @@ -15,8 +16,18 @@ createNextDescribe( }, ({ next, isNextDev, isNextStart, isNextDeploy }) => { it('should support formData and redirect without JS', async () => { + let responseCode const browser = await next.browser('/server', { disableJavaScript: true, + beforePageLoad(page) { + page.on('response', (response: Response) => { + const url = new URL(response.url()) + const status = response.status() + if (url.pathname.includes('/server')) { + responseCode = status + } + }) + }, }) await browser.eval(`document.getElementById('name').value = 'test'`) @@ -25,6 +36,8 @@ createNextDescribe( await check(() => { return browser.eval('window.location.pathname + window.location.search') }, '/header?name=test&constructor=_FormData&hidden-info=hi') + + expect(responseCode).toBe(303) }) it('should support actions from client without JS', async () => { diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 7fa91cbb1884c..5a3692a2b0266 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -1,7 +1,7 @@ /* eslint-disable jest/no-standalone-expect */ import { createNextDescribe } from 'e2e-utils' import { check, waitFor } from 'next-test-utils' -import { Request } from 'playwright-chromium' +import { Request, Response } from 'playwright-chromium' import fs from 'fs-extra' import { join } from 'path' @@ -897,5 +897,70 @@ createNextDescribe( expect(html).not.toContain('qwerty123') }) }) + + describe('redirects', () => { + it('redirects properly when server action handler uses `redirect`', async () => { + const postRequests = [] + const responseCodes = [] + + const browser = await next.browser('/redirects', { + beforePageLoad(page) { + page.on('request', (request: Request) => { + const url = new URL(request.url()) + if (request.method() === 'POST') { + postRequests.push(url.pathname) + } + }) + + page.on('response', (response: Response) => { + const url = new URL(response.url()) + const status = response.status() + + if (postRequests.includes(`${url.pathname}${url.search}`)) { + responseCodes.push(status) + } + }) + }, + }) + await browser.elementById('submit-api-redirect').click() + await check(() => browser.url(), /success=true/) + + // verify that the POST request was only made to the action handler + expect(postRequests).toEqual(['/redirects/api-redirect']) + expect(responseCodes).toEqual([303]) + }) + + it('redirects properly when server action handler uses `permanentRedirect`', async () => { + const postRequests = [] + const responseCodes = [] + + const browser = await next.browser('/redirects', { + beforePageLoad(page) { + page.on('request', (request: Request) => { + const url = new URL(request.url()) + if (request.method() === 'POST') { + postRequests.push(url.pathname) + } + }) + + page.on('response', (response: Response) => { + const url = new URL(response.url()) + const status = response.status() + + if (postRequests.includes(`${url.pathname}${url.search}`)) { + responseCodes.push(status) + } + }) + }, + }) + + await browser.elementById('submit-api-redirect-permanent').click() + await check(() => browser.url(), /success=true/) + + // verify that the POST request was only made to the action handler + expect(postRequests).toEqual(['/redirects/api-redirect-permanent']) + expect(responseCodes).toEqual([303]) + }) + }) } ) diff --git a/test/e2e/app-dir/actions/app/redirects/api-redirect-permanent/route.js b/test/e2e/app-dir/actions/app/redirects/api-redirect-permanent/route.js new file mode 100644 index 0000000000000..f09f5aacc586c --- /dev/null +++ b/test/e2e/app-dir/actions/app/redirects/api-redirect-permanent/route.js @@ -0,0 +1,5 @@ +import { permanentRedirect } from 'next/navigation' + +export function POST(request) { + permanentRedirect('/redirects/?success=true') +} diff --git a/test/e2e/app-dir/actions/app/redirects/api-redirect/route.js b/test/e2e/app-dir/actions/app/redirects/api-redirect/route.js new file mode 100644 index 0000000000000..8db7d6cd1ca6f --- /dev/null +++ b/test/e2e/app-dir/actions/app/redirects/api-redirect/route.js @@ -0,0 +1,5 @@ +import { redirect } from 'next/navigation' + +export function POST(request) { + redirect('/redirects/?success=true') +} diff --git a/test/e2e/app-dir/actions/app/redirects/page.js b/test/e2e/app-dir/actions/app/redirects/page.js new file mode 100644 index 0000000000000..68afb2f2d2fb1 --- /dev/null +++ b/test/e2e/app-dir/actions/app/redirects/page.js @@ -0,0 +1,18 @@ +export default function Home() { + return ( +
+

POST /api-redirect (`redirect()`)

+
+ +
+

POST /api-redirect-permanent (`permanentRedirect()`)

+
+ +
+
+ ) +} From d6d41dc66d60b5a2bdd732deb2ac3f99bb959ee1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Orb=C3=A1n?= Date: Wed, 29 Nov 2023 15:35:26 +0100 Subject: [PATCH 024/189] chore: bump `nissuer` (issue validator) (#59060) ### What? Bumping the issue validator action [`nissuer`](https://github.com/balazsorban44/nissuer) ### Why? It introduces two new features: - Comments made by members of the Vercel organization are never hidden to avoid hiding useful information. Example: https://github.com/vercel/next.js/actions/runs/6780069984/job/18428144215 - A new option was added to do not allow `https://github.com/vercel/next.js.*` URLs as valid reproductions, as they are non-modified versions. We should require the reporter to go through the process of creating an isolated reproduction that we can clone and verify easily. ### How? See https://github.com/balazsorban44/nissuer/releases/tag/1.8.0 --- .github/workflows/issue_validator.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/issue_validator.yml b/.github/workflows/issue_validator.yml index b6134dfbd9fe7..6337cdb2bbc9d 100644 --- a/.github/workflows/issue_validator.yml +++ b/.github/workflows/issue_validator.yml @@ -18,7 +18,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Nissuer - uses: balazsorban44/nissuer@1.5.0 + uses: balazsorban44/nissuer@1.8.1 with: label-area-prefix: 'area:' label-area-section: 'Which area\(s\) are affected\? \(Select all that apply\)(.*)### Additional context' @@ -30,6 +30,7 @@ jobs: } reproduction-comment: '.github/invalid-link.md' reproduction-hosts: 'github.com,codesandbox.io' + reproduction-blocklist: 'github.com/vercel/next.js.*' reproduction-link-section: '### Link to the code that reproduces this issue(.*)### To Reproduce' reproduction-invalid-label: 'invalid link' reproduction-issue-labels: 'template: bug' From 72388bc986f409d089a1f4ea0885e574558f189b Mon Sep 17 00:00:00 2001 From: Leah Date: Wed, 29 Nov 2023 18:13:58 +0100 Subject: [PATCH 025/189] fix(test): don't use latest sharp (#59074) --- test/integration/image-optimizer/test/sharp.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/integration/image-optimizer/test/sharp.test.ts b/test/integration/image-optimizer/test/sharp.test.ts index 6adb74221122a..e2b5b209d88d2 100644 --- a/test/integration/image-optimizer/test/sharp.test.ts +++ b/test/integration/image-optimizer/test/sharp.test.ts @@ -14,7 +14,7 @@ describe('with latest sharp', () => { packageManager: 'yarn@1.22.19', }) ) - await execa('yarn', ['add', 'sharp'], { + await execa('yarn', ['add', 'sharp@^0.32.0'], { cwd: appDir, stdio: 'inherit', }) From 9e33bf6ab929c81f694880460cce90156ecbfd6f Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Wed, 29 Nov 2023 18:19:00 +0100 Subject: [PATCH 026/189] misc: disable automerge (#59077) Disabling the auto merging behaviour from kodiak. You can queue stuff up by adding an automerge label though. Closes NEXT-1751 --- .github/.kodiak.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/.kodiak.toml b/.github/.kodiak.toml index c993778527988..9aa718b793eef 100644 --- a/.github/.kodiak.toml +++ b/.github/.kodiak.toml @@ -2,8 +2,8 @@ version = 1 [merge] -automerge_label = "ready to land" -require_automerge_label = false +automerge_label = "automerge" +require_automerge_label = true method = "squash" delete_branch_on_merge = true optimistic_updates = false From 7d129451910c72579811930a3c415ac9dbb5469f Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 29 Nov 2023 10:03:25 -0800 Subject: [PATCH 027/189] Ensure stale build fetch data is not unexpectedly used (#59076) If a build time fetch cache is present from a previous build we don't want to unexpectedly use it when flush to disk is set to false in a successive build as it can leverage stale data unexpectedly. x-ref: [slack thread](https://vercel.slack.com/archives/C03S8ED1DKM/p1701266754905909) Closes NEXT-1750 Co-authored-by: Zack Tanner --- .../incremental-cache/file-system-cache.ts | 2 +- test/lib/next-modes/base.ts | 3 +- .../app-fetch-build-cache.test.ts | 33 +++++++++++++++++++ .../app-fetch-build-cache/app/layout.tsx | 7 ++++ .../app-fetch-build-cache/app/page.tsx | 16 +++++++++ .../app-fetch-build-cache/next.config.js | 6 ++++ 6 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 test/production/app-dir/app-fetch-build-cache/app-fetch-build-cache.test.ts create mode 100644 test/production/app-dir/app-fetch-build-cache/app/layout.tsx create mode 100644 test/production/app-dir/app-fetch-build-cache/app/page.tsx create mode 100644 test/production/app-dir/app-fetch-build-cache/next.config.js diff --git a/packages/next/src/server/lib/incremental-cache/file-system-cache.ts b/packages/next/src/server/lib/incremental-cache/file-system-cache.ts index 0f0610452266b..dc4709bb4f364 100644 --- a/packages/next/src/server/lib/incremental-cache/file-system-cache.ts +++ b/packages/next/src/server/lib/incremental-cache/file-system-cache.ts @@ -187,7 +187,7 @@ export default class FileSystemCache implements CacheHandler { const fileData = await this.fs.readFile(filePath, 'utf8') const { mtime } = await this.fs.stat(filePath) - if (kind === 'fetch') { + if (kind === 'fetch' && this.flushToDisk) { const lastModified = mtime.getTime() const parsedData: CachedFetchValue = JSON.parse(fileData) data = { diff --git a/test/lib/next-modes/base.ts b/test/lib/next-modes/base.ts index 3543eff2751f3..f3c06e778e795 100644 --- a/test/lib/next-modes/base.ts +++ b/test/lib/next-modes/base.ts @@ -64,11 +64,12 @@ export class NextInstance { protected _parsedUrl: URL protected packageJson?: PackageJson = {} protected basePath?: string - protected env?: Record + public env: Record public forcedPort?: string public dirSuffix: string = '' constructor(opts: NextInstanceOpts) { + this.env = {} Object.assign(this, opts) if (!(global as any).isNextDeploy) { diff --git a/test/production/app-dir/app-fetch-build-cache/app-fetch-build-cache.test.ts b/test/production/app-dir/app-fetch-build-cache/app-fetch-build-cache.test.ts new file mode 100644 index 0000000000000..183025e8f3a04 --- /dev/null +++ b/test/production/app-dir/app-fetch-build-cache/app-fetch-build-cache.test.ts @@ -0,0 +1,33 @@ +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'app fetch build cache', + { + files: __dirname, + }, + ({ next }) => { + let initialData + + it('should have done initial build', async () => { + const $ = await next.render$('/') + expect($('#page').text()).toBe('index page') + + initialData = $('#data').text() + expect(initialData).toBeTruthy() + }) + + it('should not use stale data if present', async () => { + await next.stop() + + next.env['NOW_BUILDER'] = '1' + await next.start() + + const $ = await next.render$('/') + expect($('#page').text()).toBe('index page') + + const newData = $('#data').text() + expect(newData).toBeTruthy() + expect(newData).not.toBe(initialData) + }) + } +) diff --git a/test/production/app-dir/app-fetch-build-cache/app/layout.tsx b/test/production/app-dir/app-fetch-build-cache/app/layout.tsx new file mode 100644 index 0000000000000..e7077399c03ce --- /dev/null +++ b/test/production/app-dir/app-fetch-build-cache/app/layout.tsx @@ -0,0 +1,7 @@ +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/production/app-dir/app-fetch-build-cache/app/page.tsx b/test/production/app-dir/app-fetch-build-cache/app/page.tsx new file mode 100644 index 0000000000000..83a0c9dc90c4f --- /dev/null +++ b/test/production/app-dir/app-fetch-build-cache/app/page.tsx @@ -0,0 +1,16 @@ +import React from 'react' + +export const revalidate = 30 + +export default async function Page() { + const data = await fetch( + 'https://next-data-api-endpoint.vercel.app/api/random' + ).then((res) => res.text()) + + return ( + <> +

index page

+

{data}

+ + ) +} diff --git a/test/production/app-dir/app-fetch-build-cache/next.config.js b/test/production/app-dir/app-fetch-build-cache/next.config.js new file mode 100644 index 0000000000000..807126e4cf0bf --- /dev/null +++ b/test/production/app-dir/app-fetch-build-cache/next.config.js @@ -0,0 +1,6 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = {} + +module.exports = nextConfig From 5b94850d97a35eea138b21be0a4cf210ed452644 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Wed, 29 Nov 2023 10:07:22 -0800 Subject: [PATCH 028/189] Update checkout step (#59079) When jobs are cancelled we can end up with a bad `.git` tree so this updates to have a fresh checkout step to avoid this x-ref: https://github.com/vercel/next.js/actions/runs/7036193103/job/19148358339?pr=59076 --- .github/workflows/build_reusable.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build_reusable.yml b/.github/workflows/build_reusable.yml index f6dd49fc5b386..22ce68b9e5ddf 100644 --- a/.github/workflows/build_reusable.yml +++ b/.github/workflows/build_reusable.yml @@ -89,6 +89,8 @@ jobs: - run: corepack enable - run: pwd + - run: rm -rf .git + - uses: actions/checkout@v3 with: fetch-depth: 25 From 7ce4a02bdca2d18f7fd2c45ea24f0dc0f22ac533 Mon Sep 17 00:00:00 2001 From: Leah Date: Wed, 29 Nov 2023 19:25:01 +0100 Subject: [PATCH 029/189] ci: don't try to upload to datadog for docs only changes (#59068) --- .github/workflows/build_and_test.yml | 111 +++++++++++++++++++-------- .github/workflows/build_reusable.yml | 26 +------ scripts/run-for-change.js | 5 +- 3 files changed, 81 insertions(+), 61 deletions(-) diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index fb0dd41371923..f342b4c4179cf 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -28,6 +28,37 @@ env: NEXT_TEST_JOB: 1 jobs: + changes: + name: Determine changes + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 25 + + - name: check for docs only change + id: docs-change + run: | + echo "DOCS_ONLY<> $GITHUB_OUTPUT; + echo "$(node scripts/run-for-change.js --not --type docs --exec echo 'false')" >> $GITHUB_OUTPUT; + echo 'EOF' >> $GITHUB_OUTPUT + + - name: check for release + id: is-release + run: | + if [[ $(node ./scripts/check-is-release.js 2> /dev/null || :) = v* ]]; + then + echo "IS_RELEASE=true" >> $GITHUB_OUTPUT + else + echo "IS_RELEASE=false" >> $GITHUB_OUTPUT + fi + + outputs: + docs-only: ${{ steps.docs-change.outputs.DOCS_ONLY != 'false' }} + is-release: ${{ steps.is-release.outputs.IS_RELEASE == 'true' }} + build-native: name: build-native uses: ./.github/workflows/build_reusable.yml @@ -66,21 +97,21 @@ jobs: check-types-precompiled: name: types and precompiled - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} uses: ./.github/workflows/build_reusable.yml with: afterBuild: pnpm types-and-precompiled - skipForDocsOnly: 'yes' secrets: inherit test-cargo-unit: name: test cargo unit - needs: ['build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' needsRust: 'yes' skipInstallBuild: 'yes' skipNativeBuild: 'yes' @@ -90,11 +121,11 @@ jobs: test-cargo-integration: name: test cargo integration - needs: ['build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' needsNextest: 'yes' needsRust: 'yes' skipNativeBuild: 'yes' @@ -102,23 +133,22 @@ jobs: test-cargo-bench: name: test cargo benchmarks - needs: ['build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' || needs.changes.outputs.is-release == 'false' }} uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' - skipForRelease: 'yes' needsRust: 'yes' skipNativeBuild: 'yes' afterBuild: xvfb-run turbo run test-cargo-bench rust-check: name: rust check - needs: ['build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' needsRust: 'yes' skipInstallBuild: 'yes' skipNativeBuild: 'yes' @@ -127,20 +157,23 @@ jobs: test-turbopack-dev: name: test turbopack dev - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: group: [1, 2, 3, 4, 5] uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 NEXT_E2E_TEST_TIMEOUT=240000 NEXT_TEST_MODE=dev node run-tests.js --test-pattern '^(test\/(development|e2e))/.*\.test\.(js|jsx|ts|tsx)$' --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} secrets: inherit test-turbopack-integration: name: test turbopack integration - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: @@ -148,21 +181,24 @@ jobs: uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 - skipForDocsOnly: 'yes' afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 node run-tests.js --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} --type integration secrets: inherit test-next-swc-wasm: name: test next-swc wasm - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: rustup target add wasm32-unknown-unknown && curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh && node ./scripts/normalize-version-bump.js && turbo run build-wasm -- --target nodejs --features tracing/release_max_level_info && git checkout . && mv packages/next-swc/crates/wasm/pkg packages/next-swc/crates/wasm/pkg-nodejs && node ./scripts/setup-wasm.mjs && NEXT_TEST_MODE=start TEST_WASM=true node run-tests.js test/production/pages-dir/production/test/index.test.ts test/e2e/streaming-ssr/index.test.ts secrets: inherit test-unit: name: test unit + needs: ['changes'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: @@ -171,40 +207,43 @@ jobs: uses: ./.github/workflows/build_reusable.yml with: nodeVersion: ${{ matrix.node }} - skipForDocsOnly: 'yes' afterBuild: node run-tests.js -c ${TEST_CONCURRENCY} --type unit secrets: inherit test-dev: name: test dev - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: group: [1, 2, 3] uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type development secrets: inherit test-prod: name: test prod - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: group: [1, 2, 3, 4, 5] uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} --type production secrets: inherit test-integration: name: test integration - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: @@ -212,17 +251,16 @@ jobs: uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 - skipForDocsOnly: 'yes' afterBuild: node run-tests.js --timings -g ${{ matrix.group }}/12 -c ${TEST_CONCURRENCY} --type integration secrets: inherit test-firefox-safari: name: test firefox and safari - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: pnpm playwright install && BROWSER_NAME=firefox node run-tests.js test/production/pages-dir/production/test/index.test.ts && BROWSER_NAME=safari NEXT_TEST_MODE=start node run-tests.js -c 1 test/production/pages-dir/production/test/index.test.ts test/e2e/basepath.test.ts && BROWSER_NAME=safari DEVICE_NAME='iPhone XR' node run-tests.js -c 1 test/production/prerender-prefetch/index.test.ts secrets: inherit @@ -230,7 +268,9 @@ jobs: # Manifest generated via: https://gist.github.com/wyattjoh/2ceaebd82a5bcff4819600fd60126431 test-ppr-integration: name: test ppr integration - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: @@ -238,39 +278,41 @@ jobs: uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 - skipForDocsOnly: 'yes' afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type integration secrets: inherit test-ppr-dev: name: test ppr dev - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: group: [1, 2, 3] uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type development secrets: inherit test-ppr-prod: name: test ppr prod - needs: ['build-native', 'build-next'] + needs: ['changes', 'build-native', 'build-next'] + if: ${{ needs.changes.outputs.docs-only == 'false' }} + strategy: fail-fast: false matrix: group: [1, 2, 3] uses: ./.github/workflows/build_reusable.yml with: - skipForDocsOnly: 'yes' afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type production secrets: inherit report-test-results: needs: [ + 'changes', 'test-unit', 'test-dev', 'test-prod', @@ -281,7 +323,8 @@ jobs: 'test-turbopack-dev', 'test-turbopack-integration', ] - if: always() + if: ${{ always() && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork }} + runs-on: ubuntu-latest name: report test results to datadog steps: @@ -333,4 +376,4 @@ jobs: name: thank you, next steps: - run: exit 1 - if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') || contains(needs.*.result, 'cancelled')) }} + if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }} diff --git a/.github/workflows/build_reusable.yml b/.github/workflows/build_reusable.yml index 22ce68b9e5ddf..6e8778def5f29 100644 --- a/.github/workflows/build_reusable.yml +++ b/.github/workflows/build_reusable.yml @@ -25,14 +25,6 @@ on: required: false description: 'whether to upload analyzer artifacts' type: string - skipForDocsOnly: - required: false - description: 'skip for docs only changes' - type: string - skipForRelease: - required: false - description: 'skip for release' - type: string nodeVersion: required: false description: 'version of Node.js to use' @@ -132,28 +124,15 @@ jobs: - run: cargo clean if: ${{ inputs.skipNativeBuild != 'yes' || inputs.needsNextest == 'yes' || inputs.needsRust == 'yes' }} - - run: echo "DOCS_CHANGE<> $GITHUB_OUTPUT; echo "$(node scripts/run-for-change.js --not --type docs --exec echo 'nope')" >> $GITHUB_OUTPUT; echo 'EOF' >> $GITHUB_OUTPUT - name: check docs only change - id: docs-change - - - id: is-release - run: | - if [[ $(node ./scripts/check-is-release.js 2> /dev/null || :) = v* ]]; - then - echo "IS_RELEASE=yes" >> $GITHUB_OUTPUT - else - echo "IS_RELEASE=nope" >> $GITHUB_OUTPUT - fi - # normalize versions before build-native for better cache hits - run: node scripts/normalize-version-bump.js name: normalize versions - run: turbo run build-native-release -vvv --remote-cache-timeout 90 --summarize -- --target x86_64-unknown-linux-gnu - if: ${{ inputs.skipNativeBuild != 'yes' && steps.docs-change.outputs.DOCS_CHANGE == 'nope' }} + if: ${{ inputs.skipNativeBuild != 'yes' }} - name: Upload next-swc artifact - if: ${{ inputs.uploadSwcArtifact == 'yes' && steps.docs-change.outputs.DOCS_CHANGE == 'nope' }} + if: ${{ inputs.uploadSwcArtifact == 'yes' }} uses: actions/upload-artifact@v3 with: name: next-swc-binary @@ -178,7 +157,6 @@ jobs: - run: turbo run get-test-timings -- --build ${{ github.sha }} - run: /bin/bash -c "${{ inputs.afterBuild }}" - if: ${{(inputs.skipForDocsOnly != 'yes' || steps.docs-change.outputs.DOCS_CHANGE == 'nope') && (inputs.skipForRelease != 'yes' || steps.is-release.outputs.IS_RELEASE == 'nope')}} - name: Upload artifact uses: actions/upload-artifact@v3 diff --git a/scripts/run-for-change.js b/scripts/run-for-change.js index 62ae100d334d3..88aa740845307 100644 --- a/scripts/run-for-change.js +++ b/scripts/run-for-change.js @@ -60,9 +60,8 @@ async function main() { const remoteUrl = eventData?.head?.repo?.full_name || process.env.GITHUB_REPOSITORY || - (await exec('git remote get-url origin').stdout) + (await exec('git remote get-url origin')).stdout - let changedFilesOutput = '' const isCanary = branchName.trim() === 'canary' && remoteUrl.includes('vercel/next.js') @@ -85,7 +84,7 @@ async function main() { } ) console.error({ branchName, remoteUrl, isCanary, changesResult }) - changedFilesOutput = changesResult.stdout + const changedFilesOutput = changesResult.stdout const typeIndex = process.argv.indexOf('--type') const type = typeIndex > -1 && process.argv[typeIndex + 1] From cec374f98c8e6342b818b1465f5c93ede55dbe0e Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 29 Nov 2023 18:34:18 +0000 Subject: [PATCH 030/189] v14.0.4-canary.26 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index e8cda90f644db..eafb20a6a3a87 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.25" + "version": "14.0.4-canary.26" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index f445caa5d3298..4d2f23e9bd3f1 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index e4c352d47dd48..2937b5de1be82 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.25", + "@next/eslint-plugin-next": "14.0.4-canary.26", "@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 349f543fdeff3..9f847e2dcb45c 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 0fd534874a73b..d45e1ab992a05 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "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 06bf49a923a53..307b4e4a454de 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 2823e3f3d3b62..13f0d642ba42e 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 70a96c4f789b9..f4a5af6230ad6 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 5af0e73617afb..26df08c9bc798 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 442f4ac923e4e..051c82573376b 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "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 6b5a678b384a3..f9de50c1aff87 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "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 370ba33ce6b88..a27e4ebb307fb 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 97b943b199e23..541b9471936fc 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index a5b438b7f82aa..dd4d5aebc3f87 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.25", + "@next/env": "14.0.4-canary.26", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.25", - "@next/polyfill-nomodule": "14.0.4-canary.25", - "@next/react-dev-overlay": "14.0.4-canary.25", - "@next/react-refresh-utils": "14.0.4-canary.25", - "@next/swc": "14.0.4-canary.25", + "@next/polyfill-module": "14.0.4-canary.26", + "@next/polyfill-nomodule": "14.0.4-canary.26", + "@next/react-dev-overlay": "14.0.4-canary.26", + "@next/react-refresh-utils": "14.0.4-canary.26", + "@next/swc": "14.0.4-canary.26", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 434ebddf216b2..d4686b0639b56 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": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 091400d33ab01..d248bdac265b3 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "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 3fccaf91b5f16..463fd4c9f725f 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.25", + "version": "14.0.4-canary.26", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.25", + "next": "14.0.4-canary.26", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 096a7bf6957e2..ce979c1ac3d15 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.25 + specifier: 14.0.4-canary.26 version: link:../next outdent: specifier: 0.8.0 From e17b368760eae1aaa99cea086490a29a3105afdf Mon Sep 17 00:00:00 2001 From: Jimmy Lai Date: Wed, 29 Nov 2023 19:38:33 +0100 Subject: [PATCH 031/189] misc: delete kodiak (#59082) We don't need the auto merging from kodiak since Github has one. Closes NEXT-1753 --- .github/.kodiak.toml | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 .github/.kodiak.toml diff --git a/.github/.kodiak.toml b/.github/.kodiak.toml deleted file mode 100644 index 9aa718b793eef..0000000000000 --- a/.github/.kodiak.toml +++ /dev/null @@ -1,19 +0,0 @@ -# .kodiak.toml -version = 1 - -[merge] -automerge_label = "automerge" -require_automerge_label = true -method = "squash" -delete_branch_on_merge = true -optimistic_updates = false -prioritize_ready_to_merge = true -notify_on_conflict = false - -[merge.message] -title = "pull_request_title" -body = "pull_request_body" -include_coauthors= true -include_pr_number = true -body_type = "markdown" -strip_html_comments = true \ No newline at end of file From 6b651b0b12b4c1889ead0bf39cd391c884f37256 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 29 Nov 2023 20:01:38 +0100 Subject: [PATCH 032/189] add support for instrumentation (#59070) Closes PACK-2057 --- .../crates/napi/src/next_api/endpoint.rs | 10 +- .../crates/napi/src/next_api/project.rs | 36 +++- packages/next-swc/crates/next-api/src/app.rs | 18 +- .../crates/next-api/src/entrypoints.rs | 3 +- .../crates/next-api/src/instrumentation.rs | 197 +++++++++++++++++ packages/next-swc/crates/next-api/src/lib.rs | 1 + .../crates/next-api/src/middleware.rs | 25 +-- .../next-swc/crates/next-api/src/pages.rs | 18 +- .../next-swc/crates/next-api/src/project.rs | 78 ++++++- .../next-swc/crates/next-api/src/route.rs | 3 - .../crates/next-core/src/instrumentation.rs | 16 ++ packages/next-swc/crates/next-core/src/lib.rs | 1 + .../crates/next-core/src/next_edge/context.rs | 3 +- .../crates/next-core/src/next_import_map.rs | 9 +- .../next-core/src/next_manifests/mod.rs | 14 ++ .../next-core/src/next_server/context.rs | 24 ++- .../next-core/src/next_server/transforms.rs | 5 +- packages/next/src/build/swc/index.ts | 24 ++- packages/next/src/lib/turbopack-warning.ts | 2 +- .../lib/router-utils/setup-dev-bundler.ts | 71 +++++- .../instrumentation-hook-src.test.ts | 113 +++++----- .../instrumentation-hook.test.ts | 202 +++++++++--------- 22 files changed, 622 insertions(+), 251 deletions(-) create mode 100644 packages/next-swc/crates/next-api/src/instrumentation.rs create mode 100644 packages/next-swc/crates/next-core/src/instrumentation.rs diff --git a/packages/next-swc/crates/napi/src/next_api/endpoint.rs b/packages/next-swc/crates/napi/src/next_api/endpoint.rs index f1ae5c58f4445..06704354a0bc9 100644 --- a/packages/next-swc/crates/napi/src/next_api/endpoint.rs +++ b/packages/next-swc/crates/napi/src/next_api/endpoint.rs @@ -39,8 +39,6 @@ pub struct NapiWrittenEndpoint { pub r#type: String, pub entry_path: Option, pub server_paths: Option>, - pub files: Option>, - pub global_var_name: Option, pub config: NapiEndpointConfig, } @@ -56,15 +54,9 @@ impl From<&WrittenEndpoint> for NapiWrittenEndpoint { server_paths: Some(server_paths.iter().map(From::from).collect()), ..Default::default() }, - WrittenEndpoint::Edge { - files, - global_var_name, - server_paths, - } => Self { + WrittenEndpoint::Edge { server_paths } => Self { r#type: "edge".to_string(), - files: Some(files.clone()), server_paths: Some(server_paths.iter().map(From::from).collect()), - global_var_name: Some(global_var_name.clone()), ..Default::default() }, } diff --git a/packages/next-swc/crates/napi/src/next_api/project.rs b/packages/next-swc/crates/napi/src/next_api/project.rs index 80ef449ec1b77..a4c4e375026cb 100644 --- a/packages/next-swc/crates/napi/src/next_api/project.rs +++ b/packages/next-swc/crates/napi/src/next_api/project.rs @@ -7,7 +7,10 @@ use napi::{ JsFunction, Status, }; use next_api::{ - project::{DefineEnv, Middleware, PartialProjectOptions, ProjectContainer, ProjectOptions}, + project::{ + DefineEnv, Instrumentation, Middleware, PartialProjectOptions, ProjectContainer, + ProjectOptions, + }, route::{Endpoint, Route}, }; use next_core::tracing_presets::{ @@ -385,10 +388,36 @@ impl NapiMiddleware { }) } } + +#[napi(object)] +struct NapiInstrumentation { + pub node_js: External, + pub edge: External, +} + +impl NapiInstrumentation { + fn from_instrumentation( + value: &Instrumentation, + turbo_tasks: &Arc>, + ) -> Result { + Ok(NapiInstrumentation { + node_js: External::new(ExternalEndpoint(VcArc::new( + turbo_tasks.clone(), + value.node_js, + ))), + edge: External::new(ExternalEndpoint(VcArc::new( + turbo_tasks.clone(), + value.edge, + ))), + }) + } +} + #[napi(object)] struct NapiEntrypoints { pub routes: Vec, pub middleware: Option, + pub instrumentation: Option, pub pages_document_endpoint: External, pub pages_app_endpoint: External, pub pages_error_endpoint: External, @@ -430,6 +459,11 @@ pub fn project_entrypoints_subscribe( .as_ref() .map(|m| NapiMiddleware::from_middleware(m, &turbo_tasks)) .transpose()?, + instrumentation: entrypoints + .instrumentation + .as_ref() + .map(|m| NapiInstrumentation::from_instrumentation(m, &turbo_tasks)) + .transpose()?, pages_document_endpoint: External::new(ExternalEndpoint(VcArc::new( turbo_tasks.clone(), entrypoints.pages_document_endpoint, diff --git a/packages/next-swc/crates/next-api/src/app.rs b/packages/next-swc/crates/next-api/src/app.rs index 5c4255063b809..37d792e02112b 100644 --- a/packages/next-swc/crates/next-api/src/app.rs +++ b/packages/next-swc/crates/next-api/src/app.rs @@ -918,10 +918,10 @@ impl AppEndpoint { }; let middleware_manifest_v2 = MiddlewaresManifestV2 { sorted_middleware: vec![app_entry.original_name.clone()], - middleware: Default::default(), functions: [(app_entry.original_name.clone(), edge_function_definition)] .into_iter() .collect(), + ..Default::default() }; let manifest_path_prefix = get_asset_prefix_from_pathname(&app_entry.pathname); let middleware_manifest_v2 = Vc::upcast(VirtualOutputAsset::new( @@ -1111,21 +1111,7 @@ impl Endpoint for AppEndpoint { .to_string(), server_paths, }, - AppEndpointOutput::Edge { files, .. } => WrittenEndpoint::Edge { - files: files - .await? - .iter() - .map(|&file| async move { - Ok(node_root_ref - .get_path_to(&*file.ident().path().await?) - .context("edge chunk file path must be inside the node root")? - .to_string()) - }) - .try_join() - .await?, - global_var_name: "TODO".to_string(), - server_paths, - }, + AppEndpointOutput::Edge { .. } => WrittenEndpoint::Edge { server_paths }, }; Ok(written_endpoint.cell()) } diff --git a/packages/next-swc/crates/next-api/src/entrypoints.rs b/packages/next-swc/crates/next-api/src/entrypoints.rs index 9268ba6dc1818..578a3aba34695 100644 --- a/packages/next-swc/crates/next-api/src/entrypoints.rs +++ b/packages/next-swc/crates/next-api/src/entrypoints.rs @@ -2,7 +2,7 @@ use indexmap::IndexMap; use turbo_tasks::Vc; use crate::{ - project::Middleware, + project::{Instrumentation, Middleware}, route::{Endpoint, Route}, }; @@ -10,6 +10,7 @@ use crate::{ pub struct Entrypoints { pub routes: IndexMap, pub middleware: Option, + pub instrumentation: Option, pub pages_document_endpoint: Vc>, pub pages_app_endpoint: Vc>, pub pages_error_endpoint: Vc>, diff --git a/packages/next-swc/crates/next-api/src/instrumentation.rs b/packages/next-swc/crates/next-api/src/instrumentation.rs new file mode 100644 index 0000000000000..b25607bb2ce6d --- /dev/null +++ b/packages/next-swc/crates/next-api/src/instrumentation.rs @@ -0,0 +1,197 @@ +use anyhow::{bail, Context, Result}; +use next_core::{ + mode::NextMode, + next_edge::entry::wrap_edge_entry, + next_manifests::{InstrumentationDefinition, MiddlewaresManifestV2}, + next_server::{get_server_chunking_context, get_server_runtime_entries, ServerContextType}, +}; +use turbo_tasks::{Completion, TryJoinIterExt, Value, Vc}; +use turbopack_binding::{ + turbo::tasks_fs::{File, FileContent}, + turbopack::{ + core::{ + asset::AssetContent, + chunk::ChunkingContext, + context::AssetContext, + module::Module, + output::{OutputAsset, OutputAssets}, + virtual_output::VirtualOutputAsset, + }, + ecmascript::chunk::EcmascriptChunkPlaceable, + }, +}; + +use crate::{ + project::Project, + route::{Endpoint, WrittenEndpoint}, + server_paths::all_server_paths, +}; + +#[turbo_tasks::value] +pub struct InstrumentationEndpoint { + project: Vc, + context: Vc>, + userland_module: Vc>, + is_edge: bool, +} + +#[turbo_tasks::value_impl] +impl InstrumentationEndpoint { + #[turbo_tasks::function] + pub fn new( + project: Vc, + context: Vc>, + userland_module: Vc>, + is_edge: bool, + ) -> Vc { + Self { + project, + context, + userland_module, + is_edge, + } + .cell() + } + + #[turbo_tasks::function] + async fn edge_files(&self) -> Result> { + let module = wrap_edge_entry( + self.context, + self.project.project_path(), + self.userland_module, + "instrumentation".to_string(), + ); + + let mut evaluatable_assets = get_server_runtime_entries( + Value::new(ServerContextType::Middleware), + NextMode::Development, + ) + .resolve_entries(self.context) + .await? + .clone_value(); + + let Some(module) = + Vc::try_resolve_downcast::>(module).await? + else { + bail!("Entry module must be evaluatable"); + }; + + let Some(evaluatable) = Vc::try_resolve_sidecast(module).await? else { + bail!("Entry module must be evaluatable"); + }; + evaluatable_assets.push(evaluatable); + + let edge_chunking_context = self.project.edge_chunking_context(); + + let edge_files = edge_chunking_context + .evaluated_chunk_group(module.ident(), Vc::cell(evaluatable_assets)); + + Ok(edge_files) + } + + #[turbo_tasks::function] + async fn node_chunk(&self) -> Result>> { + let chunking_context = get_server_chunking_context( + self.project.project_path(), + self.project.node_root(), + self.project.client_relative_path(), + self.project.next_config().computed_asset_prefix(), + self.project.server_compile_time_info().environment(), + ); + + let Some(module) = Vc::try_resolve_downcast(self.userland_module).await? else { + bail!("Entry module must be evaluatable"); + }; + + let chunk = chunking_context.entry_chunk_group( + self.project + .node_root() + .join("server/instrumentation.js".to_string()), + module, + get_server_runtime_entries( + Value::new(ServerContextType::Instrumentation), + NextMode::Development, + ) + .resolve_entries(self.context), + ); + Ok(chunk) + } + + #[turbo_tasks::function] + async fn output_assets(self: Vc) -> Result> { + let this = self.await?; + + if this.is_edge { + let mut output_assets = self.edge_files().await?.clone_value(); + + let node_root = this.project.node_root(); + + let files_paths_from_root = { + let node_root = &node_root.await?; + output_assets + .iter() + .map(|&file| async move { + Ok(node_root + .get_path_to(&*file.ident().path().await?) + .context("middleware file path must be inside the node root")? + .to_string()) + }) + .try_join() + .await? + }; + + let instrumentation_definition = InstrumentationDefinition { + files: files_paths_from_root, + name: "instrumentation".to_string(), + ..Default::default() + }; + let middleware_manifest_v2 = MiddlewaresManifestV2 { + instrumentation: Some(instrumentation_definition), + ..Default::default() + }; + let middleware_manifest_v2 = Vc::upcast(VirtualOutputAsset::new( + node_root.join("server/instrumentation/middleware-manifest.json".to_string()), + AssetContent::file( + FileContent::Content(File::from(serde_json::to_string_pretty( + &middleware_manifest_v2, + )?)) + .cell(), + ), + )); + output_assets.push(middleware_manifest_v2); + + Ok(Vc::cell(output_assets)) + } else { + Ok(Vc::cell(vec![self.node_chunk()])) + } + } +} + +#[turbo_tasks::value_impl] +impl Endpoint for InstrumentationEndpoint { + #[turbo_tasks::function] + async fn write_to_disk(self: Vc) -> Result> { + let this = self.await?; + let output_assets = self.output_assets(); + this.project + .emit_all_output_assets(Vc::cell(output_assets)) + .await?; + + let node_root = this.project.node_root(); + let server_paths = all_server_paths(output_assets, node_root) + .await? + .clone_value(); + + Ok(WrittenEndpoint::Edge { server_paths }.cell()) + } + + #[turbo_tasks::function] + async fn server_changed(self: Vc) -> Result> { + Ok(self.await?.project.server_changed(self.output_assets())) + } + + #[turbo_tasks::function] + fn client_changed(self: Vc) -> Vc { + Completion::immutable() + } +} diff --git a/packages/next-swc/crates/next-api/src/lib.rs b/packages/next-swc/crates/next-api/src/lib.rs index 299adf0a061a4..0a1402928e328 100644 --- a/packages/next-swc/crates/next-api/src/lib.rs +++ b/packages/next-swc/crates/next-api/src/lib.rs @@ -4,6 +4,7 @@ mod app; mod dynamic_imports; mod entrypoints; +mod instrumentation; mod middleware; mod pages; pub mod project; diff --git a/packages/next-swc/crates/next-api/src/middleware.rs b/packages/next-swc/crates/next-api/src/middleware.rs index e8e613dfd0e72..ed49350c90f47 100644 --- a/packages/next-swc/crates/next-api/src/middleware.rs +++ b/packages/next-swc/crates/next-api/src/middleware.rs @@ -143,11 +143,10 @@ impl MiddlewareEndpoint { ..Default::default() }; let middleware_manifest_v2 = MiddlewaresManifestV2 { - sorted_middleware: Default::default(), middleware: [("/".to_string(), edge_function_definition)] .into_iter() .collect(), - functions: Default::default(), + ..Default::default() }; let middleware_manifest_v2 = Vc::upcast(VirtualOutputAsset::new( node_root.join("server/middleware/middleware-manifest.json".to_string()), @@ -169,7 +168,6 @@ impl Endpoint for MiddlewareEndpoint { #[turbo_tasks::function] async fn write_to_disk(self: Vc) -> Result> { let this = self.await?; - let files = self.edge_files(); let output_assets = self.output_assets(); this.project .emit_all_output_assets(Vc::cell(output_assets)) @@ -180,26 +178,7 @@ impl Endpoint for MiddlewareEndpoint { .await? .clone_value(); - let node_root = &node_root.await?; - - let files = files - .await? - .iter() - .map(|&file| async move { - Ok(node_root - .get_path_to(&*file.ident().path().await?) - .context("middleware file path must be inside the node root")? - .to_string()) - }) - .try_join() - .await?; - - Ok(WrittenEndpoint::Edge { - files, - global_var_name: "TODO".to_string(), - server_paths, - } - .cell()) + Ok(WrittenEndpoint::Edge { server_paths }.cell()) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-api/src/pages.rs b/packages/next-swc/crates/next-api/src/pages.rs index 35bb83441799c..8d18ef351b533 100644 --- a/packages/next-swc/crates/next-api/src/pages.rs +++ b/packages/next-swc/crates/next-api/src/pages.rs @@ -1012,10 +1012,10 @@ impl PageEndpoint { }; let middleware_manifest_v2 = MiddlewaresManifestV2 { sorted_middleware: vec![pathname.to_string()], - middleware: Default::default(), functions: [(pathname.to_string(), edge_function_definition)] .into_iter() .collect(), + ..Default::default() }; let manifest_path_prefix = get_asset_prefix_from_pathname(&this.pathname.await?); let middleware_manifest_v2 = Vc::upcast(VirtualOutputAsset::new( @@ -1081,21 +1081,7 @@ impl Endpoint for PageEndpoint { .to_string(), server_paths, }, - PageEndpointOutput::Edge { files, .. } => WrittenEndpoint::Edge { - files: files - .await? - .iter() - .map(|&file| async move { - Ok(node_root - .get_path_to(&*file.ident().path().await?) - .context("ssr chunk file path must be inside the node root")? - .to_string()) - }) - .try_join() - .await?, - global_var_name: "TODO".to_string(), - server_paths, - }, + PageEndpointOutput::Edge { .. } => WrittenEndpoint::Edge { server_paths }, }; Ok(written_endpoint.cell()) diff --git a/packages/next-swc/crates/next-api/src/project.rs b/packages/next-swc/crates/next-api/src/project.rs index 84fe32744bace..b5431ac3774f6 100644 --- a/packages/next-swc/crates/next-api/src/project.rs +++ b/packages/next-swc/crates/next-api/src/project.rs @@ -7,13 +7,14 @@ use next_core::{ app_structure::find_app_dir, emit_assets, get_edge_chunking_context, get_edge_compile_time_info, get_edge_resolve_options_context, + instrumentation::instrumentation_files, middleware::middleware_files, mode::NextMode, next_client::{get_client_chunking_context, get_client_compile_time_info}, next_config::{JsConfig, NextConfig}, next_server::{ get_server_chunking_context, get_server_compile_time_info, - get_server_module_options_context, ServerContextType, + get_server_module_options_context, get_server_resolve_options_context, ServerContextType, }, next_telemetry::NextFeatureTelemetry, }; @@ -57,6 +58,7 @@ use crate::{ app::{AppProject, OptionAppProject}, build, entrypoints::Entrypoints, + instrumentation::InstrumentationEndpoint, middleware::MiddlewareEndpoint, pages::PagesProject, route::{Endpoint, Route}, @@ -136,6 +138,12 @@ pub struct Middleware { pub endpoint: Vc>, } +#[derive(Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, ValueDebugFormat)] +pub struct Instrumentation { + pub node_js: Vc>, + pub edge: Vc>, +} + #[turbo_tasks::value] pub struct ProjectContainer { options_state: State, @@ -661,9 +669,34 @@ impl Project { None }; + let instrumentation = find_context_file( + self.project_path(), + instrumentation_files(self.next_config().page_extensions()), + ); + let instrumentation = if let FindContextFileResult::Found(fs_path, _) = + *instrumentation.await? + { + let source = Vc::upcast(FileSource::new(fs_path)); + Some(Instrumentation { + node_js: TraitRef::cell( + Vc::upcast::>(self.instrumentation_endpoint(source, false)) + .into_trait_ref() + .await?, + ), + edge: TraitRef::cell( + Vc::upcast::>(self.instrumentation_endpoint(source, true)) + .into_trait_ref() + .await?, + ), + }) + } else { + None + }; + Ok(Entrypoints { routes, middleware, + instrumentation, pages_document_endpoint, pages_app_endpoint, pages_error_endpoint, @@ -706,6 +739,49 @@ impl Project { MiddlewareEndpoint::new(self, context, module) } + #[turbo_tasks::function] + fn node_instrumentation_context(self: Vc) -> Vc> { + Vc::upcast(ModuleAssetContext::new( + Default::default(), + self.server_compile_time_info(), + get_server_module_options_context( + self.project_path(), + self.execution_context(), + Value::new(ServerContextType::Instrumentation), + NextMode::Development, + self.next_config(), + ), + get_server_resolve_options_context( + self.project_path(), + Value::new(ServerContextType::Instrumentation), + NextMode::Development, + self.next_config(), + self.execution_context(), + ), + Vc::cell("instrumentation".to_string()), + )) + } + + #[turbo_tasks::function] + fn instrumentation_endpoint( + self: Vc, + source: Vc>, + is_edge: bool, + ) -> Vc { + let context = if is_edge { + self.middleware_context() + } else { + self.node_instrumentation_context() + }; + + let module = context.process( + source, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), + ); + + InstrumentationEndpoint::new(self, context, module, is_edge) + } + #[turbo_tasks::function] pub async fn emit_all_output_assets( self: Vc, diff --git a/packages/next-swc/crates/next-api/src/route.rs b/packages/next-swc/crates/next-api/src/route.rs index c313f90fffd4e..8dd78f029c749 100644 --- a/packages/next-swc/crates/next-api/src/route.rs +++ b/packages/next-swc/crates/next-api/src/route.rs @@ -39,9 +39,6 @@ pub enum WrittenEndpoint { server_paths: Vec, }, Edge { - /// Relative to the root_path - files: Vec, - global_var_name: String, server_paths: Vec, }, } diff --git a/packages/next-swc/crates/next-core/src/instrumentation.rs b/packages/next-swc/crates/next-core/src/instrumentation.rs new file mode 100644 index 0000000000000..21df0efcec2e3 --- /dev/null +++ b/packages/next-swc/crates/next-core/src/instrumentation.rs @@ -0,0 +1,16 @@ +use anyhow::Result; +use turbo_tasks::Vc; + +#[turbo_tasks::function] +pub async fn instrumentation_files(page_extensions: Vc>) -> Result>> { + let extensions = page_extensions.await?; + let files = ["instrumentation.", "src/instrumentation."] + .into_iter() + .flat_map(|f| { + extensions + .iter() + .map(move |ext| String::from(f) + ext.as_str()) + }) + .collect(); + Ok(Vc::cell(files)) +} diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 1eff791f9a41b..b789484cef712 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -11,6 +11,7 @@ mod babel; mod bootstrap; mod embed_js; mod emit; +pub mod instrumentation; mod loader_tree; pub mod middleware; pub mod mode; 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 3566acf915ae6..f0c58bbdad633 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 @@ -117,7 +117,8 @@ pub async fn get_edge_resolve_options_context( | ServerContextType::PagesData { .. } | ServerContextType::PagesApi { .. } | ServerContextType::AppSSR { .. } - | ServerContextType::Middleware { .. } => {} + | ServerContextType::Middleware { .. } + | ServerContextType::Instrumentation { .. } => {} }; let resolve_options_context = ResolveOptionsContext { 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 031fbd8cb0fbc..34c14a3131cde 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 @@ -318,7 +318,7 @@ pub async fn get_next_server_import_map( request_to_import_mapping(project_path, "next/dist/shared/lib/app-dynamic"), ); } - ServerContextType::Middleware => {} + ServerContextType::Middleware | ServerContextType::Instrumentation => {} } insert_next_server_special_aliases( @@ -428,7 +428,7 @@ pub async fn get_next_edge_import_map( request_to_import_mapping(project_path, "next/dist/shared/lib/app-dynamic"), ); } - ServerContextType::Middleware => {} + ServerContextType::Middleware | ServerContextType::Instrumentation => {} } insert_next_server_special_aliases( @@ -562,7 +562,7 @@ async fn insert_next_server_special_aliases( rsc_aliases(import_map, project_path, ty, runtime, next_config).await?; } - ServerContextType::Middleware => {} + ServerContextType::Middleware | ServerContextType::Instrumentation => {} } // see https://github.com/vercel/next.js/blob/8013ef7372fc545d49dbd060461224ceb563b454/packages/next/src/build/webpack-config.ts#L1449-L1531 @@ -584,7 +584,8 @@ async fn insert_next_server_special_aliases( // TODO: should include `ServerContextType::PagesApi` routes, but that type doesn't exist. ServerContextType::AppRSC { .. } | ServerContextType::AppRoute { .. } - | ServerContextType::Middleware => { + | ServerContextType::Middleware + | ServerContextType::Instrumentation => { insert_exact_alias_map( import_map, project_path, diff --git a/packages/next-swc/crates/next-core/src/next_manifests/mod.rs b/packages/next-swc/crates/next-core/src/next_manifests/mod.rs index b6f727de4ccd0..5f9e5e2447305 100644 --- a/packages/next-swc/crates/next-core/src/next_manifests/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_manifests/mod.rs @@ -29,6 +29,7 @@ pub struct BuildManifest { #[derive(Serialize, Debug)] #[serde(rename_all = "camelCase", tag = "version")] +#[allow(clippy::large_enum_variant)] pub enum MiddlewaresManifest { #[serde(rename = "2")] MiddlewaresManifestV2(MiddlewaresManifestV2), @@ -100,6 +101,18 @@ pub struct EdgeFunctionDefinition { pub regions: Option, } +#[derive(Serialize, Default, Debug)] +pub struct InstrumentationDefinition { + pub files: Vec, + pub name: String, + // TODO: AssetBinding[] + #[serde(skip_serializing_if = "Option::is_none")] + pub wasm: Option>, + // TODO: AssetBinding[] + #[serde(skip_serializing_if = "Option::is_none")] + pub assets: Option>, +} + #[derive(Serialize, Debug)] #[serde(untagged)] pub enum Regions { @@ -111,6 +124,7 @@ pub enum Regions { pub struct MiddlewaresManifestV2 { pub sorted_middleware: Vec, pub middleware: HashMap, + pub instrumentation: Option, pub functions: HashMap, } 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 02e3adbb12edd..41efaa11ecba1 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 @@ -90,6 +90,7 @@ pub enum ServerContextType { app_dir: Vc, }, Middleware, + Instrumentation, } #[turbo_tasks::function] @@ -140,7 +141,8 @@ pub async fn get_server_resolve_options_context( | ServerContextType::PagesData { .. } | ServerContextType::PagesApi { .. } | ServerContextType::AppSSR { .. } - | ServerContextType::Middleware { .. } => {} + | ServerContextType::Middleware { .. } + | ServerContextType::Instrumentation { .. } => {} }; let external_cjs_modules_plugin = ExternalCjsModulesResolvePlugin::new( project_path, @@ -168,8 +170,7 @@ pub async fn get_server_resolve_options_context( } ServerContextType::AppSSR { .. } | ServerContextType::AppRSC { .. } - | ServerContextType::AppRoute { .. } - | ServerContextType::Middleware { .. } => { + | ServerContextType::AppRoute { .. } => { vec![ Vc::upcast(module_feature_report_resolve_plugin), Vc::upcast(server_component_externals_plugin), @@ -178,6 +179,21 @@ pub async fn get_server_resolve_options_context( Vc::upcast(next_node_shared_runtime_plugin), ] } + ServerContextType::Middleware { .. } => { + vec![ + Vc::upcast(module_feature_report_resolve_plugin), + Vc::upcast(unsupported_modules_resolve_plugin), + Vc::upcast(next_node_shared_runtime_plugin), + ] + } + ServerContextType::Instrumentation { .. } => { + vec![ + Vc::upcast(module_feature_report_resolve_plugin), + Vc::upcast(unsupported_modules_resolve_plugin), + Vc::upcast(next_external_plugin), + Vc::upcast(next_node_shared_runtime_plugin), + ] + } }; let resolve_options_context = ResolveOptionsContext { enable_node_modules: Some(root_dir), @@ -594,7 +610,7 @@ pub async fn get_server_module_options_context( ..module_options_context } } - ServerContextType::Middleware => { + ServerContextType::Middleware | ServerContextType::Instrumentation => { let mut base_source_transforms: Vec> = vec![ styled_components_transform_plugin, styled_jsx_transform_plugin, diff --git a/packages/next-swc/crates/next-core/src/next_server/transforms.rs b/packages/next-swc/crates/next-core/src/next_server/transforms.rs index 61e48d91c6851..019b8366b1a38 100644 --- a/packages/next-swc/crates/next-core/src/next_server/transforms.rs +++ b/packages/next-swc/crates/next-core/src/next_server/transforms.rs @@ -68,7 +68,9 @@ pub async fn get_next_server_transforms_rules( (true, None) } ServerContextType::AppRoute { .. } => (false, None), - ServerContextType::Middleware { .. } => (false, None), + ServerContextType::Middleware { .. } | ServerContextType::Instrumentation { .. } => { + (false, None) + } }; rules.push( @@ -112,6 +114,7 @@ pub async fn get_next_server_internal_transforms_rules( } ServerContextType::AppRoute { .. } => {} ServerContextType::Middleware { .. } => {} + ServerContextType::Instrumentation { .. } => {} }; Ok(rules) diff --git a/packages/next/src/build/swc/index.ts b/packages/next/src/build/swc/index.ts index 225a0e9a4107c..116ca37b277da 100644 --- a/packages/next/src/build/swc/index.ts +++ b/packages/next/src/build/swc/index.ts @@ -531,9 +531,15 @@ export interface Middleware { endpoint: Endpoint } +export interface Instrumentation { + nodeJs: Endpoint + edge: Endpoint +} + export interface Entrypoints { routes: Map middleware?: Middleware + instrumentation?: Instrumentation pagesDocumentEndpoint: Endpoint pagesAppEndpoint: Endpoint pagesErrorEndpoint: Endpoint @@ -648,10 +654,8 @@ export type WrittenEndpoint = } | { type: 'edge' - files: string[] /** All server paths that has been written for the endpoint. */ serverPaths: ServerPath[] - globalVarName: string config: EndpointConfig } @@ -797,6 +801,7 @@ function bindingToApi(binding: any, _wasm: boolean) { type NapiEntrypoints = { routes: NapiRoute[] middleware?: NapiMiddleware + instrumentation?: NapiInstrumentation pagesDocumentEndpoint: NapiEndpoint pagesAppEndpoint: NapiEndpoint pagesErrorEndpoint: NapiEndpoint @@ -808,6 +813,11 @@ function bindingToApi(binding: any, _wasm: boolean) { matcher?: string[] } + type NapiInstrumentation = { + nodeJs: NapiEndpoint + edge: NapiEndpoint + } + type NapiRoute = { pathname: string } & ( @@ -894,9 +904,19 @@ function bindingToApi(binding: any, _wasm: boolean) { const middleware = entrypoints.middleware ? napiMiddlewareToMiddleware(entrypoints.middleware) : undefined + const napiInstrumentationToInstrumentation = ( + instrumentation: NapiInstrumentation + ) => ({ + nodeJs: new EndpointImpl(instrumentation.nodeJs), + edge: new EndpointImpl(instrumentation.edge), + }) + const instrumentation = entrypoints.instrumentation + ? napiInstrumentationToInstrumentation(entrypoints.instrumentation) + : undefined yield { routes, middleware, + instrumentation, pagesDocumentEndpoint: new EndpointImpl( entrypoints.pagesDocumentEndpoint ), diff --git a/packages/next/src/lib/turbopack-warning.ts b/packages/next/src/lib/turbopack-warning.ts index aff0d1d2ce7f5..70290ee3a4dd7 100644 --- a/packages/next/src/lib/turbopack-warning.ts +++ b/packages/next/src/lib/turbopack-warning.ts @@ -68,6 +68,7 @@ const supportedTurbopackNextConfigOptions = [ 'experimental.deploymentId', 'experimental.useLightningcss', 'experimental.windowHistorySupport', + 'experimental.instrumentationHook', // Experimental options that don't affect compilation 'experimental.ppr', @@ -106,7 +107,6 @@ const supportedTurbopackNextConfigOptions = [ // 'compiler.removeConsole', // 'compiler.styledComponents', // 'experimental.fetchCacheKeyPrefix', - // 'experimental.instrumentationHook', // Left to be implemented 'excludeDefaultMomentLocales', diff --git a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts index 1a0a5aca5fc9f..59d561927cee2 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @@ -573,13 +573,18 @@ async function startWatcher(opts: SetupOpts) { async function loadPartialManifest( name: string, pageName: string, - type: 'pages' | 'app' | 'app-route' | 'middleware' = 'pages' + type: + | 'pages' + | 'app' + | 'app-route' + | 'middleware' + | 'instrumentation' = 'pages' ): Promise { const manifestPath = path.posix.join( distDir, `server`, type === 'app-route' ? 'app' : type, - type === 'middleware' + type === 'middleware' || type === 'instrumentation' ? '' : pageName === '/' ? 'index' @@ -594,11 +599,18 @@ async function startWatcher(opts: SetupOpts) { ) as T } + type TurbopackMiddlewareManifest = MiddlewareManifest & { + instrumentation?: { + files: string[] + name: 'instrumentation' + } + } + const buildManifests = new Map() const appBuildManifests = new Map() const pagesManifests = new Map() const appPathsManifests = new Map() - const middlewareManifests = new Map() + const middlewareManifests = new Map() const actionManifests = new Map() const clientToHmrSubscription = new Map< ws, @@ -609,7 +621,7 @@ async function startWatcher(opts: SetupOpts) { async function loadMiddlewareManifest( pageName: string, - type: 'pages' | 'app' | 'app-route' | 'middleware' + type: 'pages' | 'app' | 'app-route' | 'middleware' | 'instrumentation' ): Promise { middlewareManifests.set( pageName, @@ -751,7 +763,7 @@ async function startWatcher(opts: SetupOpts) { } function mergeMiddlewareManifests( - manifests: Iterable + manifests: Iterable ): MiddlewareManifest { const manifest: MiddlewareManifest = { version: 2, @@ -759,13 +771,20 @@ async function startWatcher(opts: SetupOpts) { sortedMiddleware: [], functions: {}, } + let instrumentation = undefined for (const m of manifests) { Object.assign(manifest.functions, m.functions) Object.assign(manifest.middleware, m.middleware) + if (m.instrumentation) { + instrumentation = m.instrumentation + } } for (const fun of Object.values(manifest.functions).concat( Object.values(manifest.middleware) )) { + if (instrumentation) { + fun.files.unshift(...instrumentation.files) + } for (const matcher of fun.matchers) { if (!matcher.regexp) { matcher.regexp = pathToRegexp(matcher.originalSource, [], { @@ -777,6 +796,7 @@ async function startWatcher(opts: SetupOpts) { } } manifest.sortedMiddleware = Object.keys(manifest.middleware) + return manifest } @@ -1091,7 +1111,7 @@ async function startWatcher(opts: SetupOpts) { } } - const { middleware } = entrypoints + const { middleware, instrumentation } = entrypoints // We check for explicit true/false, since it's initialized to // undefined during the first loop (middlewareChanges event is // unnecessary during the first serve) @@ -1107,6 +1127,43 @@ async function startWatcher(opts: SetupOpts) { event: HMR_ACTIONS_SENT_TO_BROWSER.MIDDLEWARE_CHANGES, }) } + if (instrumentation) { + const processInstrumentation = async ( + displayName: string, + name: string, + prop: 'nodeJs' | 'edge' + ) => { + const writtenEndpoint = await processResult( + displayName, + await instrumentation[prop].writeToDisk() + ) + processIssues(displayName, name, writtenEndpoint) + } + await processInstrumentation( + 'instrumentation (node.js)', + 'instrumentation.nodeJs', + 'nodeJs' + ) + await processInstrumentation( + 'instrumentation (edge)', + 'instrumentation.edge', + 'edge' + ) + await loadMiddlewareManifest('instrumentation', 'instrumentation') + NextBuildContext.hasInstrumentationHook = true + serverFields.actualInstrumentationHookFile = '/instrumentation' + await propagateServerField( + 'actualInstrumentationHookFile', + serverFields.actualInstrumentationHookFile + ) + } else { + NextBuildContext.hasInstrumentationHook = false + serverFields.actualInstrumentationHookFile = undefined + await propagateServerField( + 'actualInstrumentationHookFile', + serverFields.actualInstrumentationHookFile + ) + } if (middleware) { const processMiddleware = async () => { const writtenEndpoint = await processResult( @@ -1418,6 +1475,8 @@ async function startWatcher(opts: SetupOpts) { if (page === '/_document') return if (page === '/middleware') return if (page === '/src/middleware') return + if (page === '/instrumentation') return + if (page === '/src/instrumentation') return throw new PageNotFoundError(`route not found ${page}`) } diff --git a/test/e2e/instrumentation-hook-src/instrumentation-hook-src.test.ts b/test/e2e/instrumentation-hook-src/instrumentation-hook-src.test.ts index 80577132112e6..bc840d423a0a6 100644 --- a/test/e2e/instrumentation-hook-src/instrumentation-hook-src.test.ts +++ b/test/e2e/instrumentation-hook-src/instrumentation-hook-src.test.ts @@ -1,65 +1,62 @@ import { createNextDescribe } from 'e2e-utils' import { check } from 'next-test-utils' -;(process.env.TURBOPACK ? describe.skip : describe)( - 'instrumentation-hook-rsc', - () => { - createNextDescribe( - 'instrumentation', - { - files: __dirname, - nextConfig: { - experimental: { - instrumentationHook: true, - }, +describe('instrumentation-hook-rsc', () => { + createNextDescribe( + 'instrumentation', + { + files: __dirname, + nextConfig: { + experimental: { + instrumentationHook: true, }, - skipDeployment: true, }, - ({ next, isNextDev }) => { - it('should run the instrumentation hook', async () => { + skipDeployment: true, + }, + ({ next, isNextDev }) => { + it('should run the instrumentation hook', async () => { + await next.render('/') + await check(() => next.cliOutput, /instrumentation hook/) + }) + it('should not overlap with a instrumentation page', async () => { + const page = await next.render('/instrumentation') + expect(page).toContain('Hello') + }) + it('should run the edge instrumentation compiled version with the edge runtime', async () => { + await next.render('/edge') + await check(() => next.cliOutput, /instrumentation hook on the edge/) + }) + if (isNextDev) { + // TODO: Implement handling for changing the instrument file. + it.skip('should reload the server when the instrumentation hook changes', async () => { await next.render('/') - await check(() => next.cliOutput, /instrumentation hook/) + await next.patchFile( + './src/instrumentation.js', + `export function register() {console.log('toast')}` + ) + await check(() => next.cliOutput, /toast/) + await next.renameFile( + './src/instrumentation.js', + './src/instrumentation.js.bak' + ) + await check( + () => next.cliOutput, + /The instrumentation file has been removed/ + ) + await next.patchFile( + './src/instrumentation.js.bak', + `export function register() {console.log('bread')}` + ) + await next.renameFile( + './src/instrumentation.js.bak', + './src/instrumentation.js' + ) + await check( + () => next.cliOutput, + /The instrumentation file was added/ + ) + await check(() => next.cliOutput, /bread/) }) - it('should not overlap with a instrumentation page', async () => { - const page = await next.render('/instrumentation') - expect(page).toContain('Hello') - }) - it('should run the edge instrumentation compiled version with the edge runtime', async () => { - await next.render('/edge') - await check(() => next.cliOutput, /instrumentation hook on the edge/) - }) - if (isNextDev) { - // TODO: Implement handling for changing the instrument file. - it.skip('should reload the server when the instrumentation hook changes', async () => { - await next.render('/') - await next.patchFile( - './src/instrumentation.js', - `export function register() {console.log('toast')}` - ) - await check(() => next.cliOutput, /toast/) - await next.renameFile( - './src/instrumentation.js', - './src/instrumentation.js.bak' - ) - await check( - () => next.cliOutput, - /The instrumentation file has been removed/ - ) - await next.patchFile( - './src/instrumentation.js.bak', - `export function register() {console.log('bread')}` - ) - await next.renameFile( - './src/instrumentation.js.bak', - './src/instrumentation.js' - ) - await check( - () => next.cliOutput, - /The instrumentation file was added/ - ) - await check(() => next.cliOutput, /bread/) - }) - } } - ) - } -) + } + ) +}) diff --git a/test/e2e/instrumentation-hook/instrumentation-hook.test.ts b/test/e2e/instrumentation-hook/instrumentation-hook.test.ts index 7e83ce4dd1512..a4fafd0424bb0 100644 --- a/test/e2e/instrumentation-hook/instrumentation-hook.test.ts +++ b/test/e2e/instrumentation-hook/instrumentation-hook.test.ts @@ -20,123 +20,117 @@ const describeCase = ( callback ) } -;(process.env.TURBOPACK ? describe.skip : describe)( - 'Instrumentation Hook', - () => { - // TODO: investigate the failure with esm import - // createNextDescribe( - // 'with-esm-import', - // { - // files: path.join(__dirname, 'with-esm-import'), - // nextConfig: { - // experimental: { - // instrumentationHook: true, - // }, - // }, - // dependencies: { - // // This test is mostly for compatibility with this package - // '@vercel/otel': 'latest', - // }, - // skipDeployment: true, - // }, - // ({ next }) => { - // eslint-disable-next-line jest/no-commented-out-tests - // it('with-esm-import should run the instrumentation hook', async () => { - // await next.render('/') - // await check( - // () => next.cliOutput, - // /register in instrumentation\.js is running/ - // ) - // }) - // } - // ) +describe('Instrumentation Hook', () => { + // TODO: investigate the failure with esm import + // createNextDescribe( + // 'with-esm-import', + // { + // files: path.join(__dirname, 'with-esm-import'), + // nextConfig: { + // experimental: { + // instrumentationHook: true, + // }, + // }, + // dependencies: { + // // This test is mostly for compatibility with this package + // '@vercel/otel': 'latest', + // }, + // skipDeployment: true, + // }, + // ({ next }) => { + // eslint-disable-next-line jest/no-commented-out-tests + // it('with-esm-import should run the instrumentation hook', async () => { + // await next.render('/') + // await check( + // () => next.cliOutput, + // /register in instrumentation\.js is running/ + // ) + // }) + // } + // ) - describeCase('with-middleware', ({ next }) => { - it('with-middleware should run the instrumentation hook', async () => { - await next.render('/') - await check(() => next.cliOutput, /instrumentation hook on the edge/) - }) + describeCase('with-middleware', ({ next }) => { + it('with-middleware should run the instrumentation hook', async () => { + await next.render('/') + await check(() => next.cliOutput, /instrumentation hook on the edge/) }) + }) - describeCase('with-edge-api', ({ next }) => { - it('with-edge-api should run the instrumentation hook', async () => { - await next.render('/api') - await check(() => next.cliOutput, /instrumentation hook on the edge/) - }) + describeCase('with-edge-api', ({ next }) => { + it('with-edge-api should run the instrumentation hook', async () => { + await next.render('/api') + await check(() => next.cliOutput, /instrumentation hook on the edge/) }) + }) - describeCase('with-edge-page', ({ next }) => { - it('with-edge-page should run the instrumentation hook', async () => { - await next.render('/') - await check(() => next.cliOutput, /instrumentation hook on the edge/) - }) + describeCase('with-edge-page', ({ next }) => { + it('with-edge-page should run the instrumentation hook', async () => { + await next.render('/') + await check(() => next.cliOutput, /instrumentation hook on the edge/) }) + }) - describeCase('with-node-api', ({ next }) => { - it('with-node-api should run the instrumentation hook', async () => { - await next.render('/api') - await check(() => next.cliOutput, /instrumentation hook on nodejs/) - }) + describeCase('with-node-api', ({ next }) => { + it('with-node-api should run the instrumentation hook', async () => { + await next.render('/api') + await check(() => next.cliOutput, /instrumentation hook on nodejs/) }) + }) - describeCase('with-node-page', ({ next }) => { - it('with-node-page should run the instrumentation hook', async () => { - await next.render('/') - await check(() => next.cliOutput, /instrumentation hook on nodejs/) - }) + describeCase('with-node-page', ({ next }) => { + it('with-node-page should run the instrumentation hook', async () => { + await next.render('/') + await check(() => next.cliOutput, /instrumentation hook on nodejs/) }) + }) - describeCase('with-async-node-page', ({ next }) => { - it('with-async-node-page should run the instrumentation hook', async () => { - const page = await next.render('/') - expect(page).toContain('Node - finished: true') - }) + describeCase('with-async-node-page', ({ next }) => { + it('with-async-node-page should run the instrumentation hook', async () => { + const page = await next.render('/') + expect(page).toContain('Node - finished: true') }) + }) - describeCase('with-async-edge-page', ({ next }) => { - it('with-async-edge-page should run the instrumentation hook', async () => { - const page = await next.render('/') - expect(page).toContain('Edge - finished: true') - }) + describeCase('with-async-edge-page', ({ next }) => { + it('with-async-edge-page should run the instrumentation hook', async () => { + const page = await next.render('/') + expect(page).toContain('Edge - finished: true') }) + }) - describeCase('general', ({ next, isNextDev }) => { - it('should not overlap with a instrumentation page', async () => { - const page = await next.render('/instrumentation') - expect(page).toContain('Hello') - }) - if (isNextDev) { - // TODO: Implement handling for changing the instrument file. - it.skip('should reload the server when the instrumentation hook changes', async () => { - await next.render('/') - await next.patchFile( - './instrumentation.js', - `export function register() {console.log('toast')}` - ) - await check(() => next.cliOutput, /toast/) - await next.renameFile( - './instrumentation.js', - './instrumentation.js.bak' - ) - await check( - () => next.cliOutput, - /The instrumentation file has been removed/ - ) - await next.patchFile( - './instrumentation.js.bak', - `export function register() {console.log('bread')}` - ) - await next.renameFile( - './instrumentation.js.bak', - './instrumentation.js' - ) - await check( - () => next.cliOutput, - /The instrumentation file was added/ - ) - await check(() => next.cliOutput, /bread/) - }) - } + describeCase('general', ({ next, isNextDev }) => { + it('should not overlap with a instrumentation page', async () => { + const page = await next.render('/instrumentation') + expect(page).toContain('Hello') }) - } -) + if (isNextDev) { + // TODO: Implement handling for changing the instrument file. + it.skip('should reload the server when the instrumentation hook changes', async () => { + await next.render('/') + await next.patchFile( + './instrumentation.js', + `export function register() {console.log('toast')}` + ) + await check(() => next.cliOutput, /toast/) + await next.renameFile( + './instrumentation.js', + './instrumentation.js.bak' + ) + await check( + () => next.cliOutput, + /The instrumentation file has been removed/ + ) + await next.patchFile( + './instrumentation.js.bak', + `export function register() {console.log('bread')}` + ) + await next.renameFile( + './instrumentation.js.bak', + './instrumentation.js' + ) + await check(() => next.cliOutput, /The instrumentation file was added/) + await check(() => next.cliOutput, /bread/) + }) + } + }) +}) From e8c0273677bade4801ab6229a013f146e3e209f0 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 29 Nov 2023 11:34:01 -0800 Subject: [PATCH 033/189] add full PPR e2e tests (#59025) This copies over the E2E tests that were added to `vercel/vercel` in https://github.com/vercel/vercel/pull/10808 and https://github.com/vercel/vercel/pull/10823, with some minor adjustments to reflect the differences in cache behavior between start & deploy. --- .../app/dynamic/force-dynamic/page.jsx | 16 ++ .../app/dynamic/force-static/page.jsx | 15 ++ test/e2e/app-dir/ppr-full/app/layout.jsx | 19 +++ .../ppr-full/app/loading/[slug]/page.jsx | 16 ++ .../app-dir/ppr-full/app/loading/loading.jsx | 3 + .../ppr-full/app/nested/[slug]/page.jsx | 16 ++ .../app/no-suspense/nested/[slug]/page.jsx | 10 ++ .../app-dir/ppr-full/app/no-suspense/page.jsx | 6 + .../ppr-full/app/on-demand/[slug]/page.jsx | 10 ++ test/e2e/app-dir/ppr-full/app/page.jsx | 10 ++ test/e2e/app-dir/ppr-full/app/static/page.jsx | 6 + .../app-dir/ppr-full/components/dynamic.jsx | 37 +++++ .../e2e/app-dir/ppr-full/components/links.jsx | 42 +++++ test/e2e/app-dir/ppr-full/next.config.js | 8 + test/e2e/app-dir/ppr-full/ppr-full.test.ts | 145 ++++++++++++++++++ test/e2e/app-dir/ppr/ppr.test.ts | 1 - 16 files changed, 359 insertions(+), 1 deletion(-) create mode 100644 test/e2e/app-dir/ppr-full/app/dynamic/force-dynamic/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/dynamic/force-static/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/layout.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/loading/[slug]/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/loading/loading.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/nested/[slug]/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/no-suspense/nested/[slug]/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/no-suspense/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/on-demand/[slug]/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/app/static/page.jsx create mode 100644 test/e2e/app-dir/ppr-full/components/dynamic.jsx create mode 100644 test/e2e/app-dir/ppr-full/components/links.jsx create mode 100644 test/e2e/app-dir/ppr-full/next.config.js create mode 100644 test/e2e/app-dir/ppr-full/ppr-full.test.ts diff --git a/test/e2e/app-dir/ppr-full/app/dynamic/force-dynamic/page.jsx b/test/e2e/app-dir/ppr-full/app/dynamic/force-dynamic/page.jsx new file mode 100644 index 0000000000000..97c8772e3bef9 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/dynamic/force-dynamic/page.jsx @@ -0,0 +1,16 @@ +import React, { Suspense } from 'react' +import { Dynamic } from '../../../components/dynamic' + +export const dynamic = 'force-dynamic' + +export default ({ params: { slug } }) => { + return ( + + } + > + + + ) +} diff --git a/test/e2e/app-dir/ppr-full/app/dynamic/force-static/page.jsx b/test/e2e/app-dir/ppr-full/app/dynamic/force-static/page.jsx new file mode 100644 index 0000000000000..195abf0da924c --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/dynamic/force-static/page.jsx @@ -0,0 +1,15 @@ +import React, { Suspense } from 'react' +import { Dynamic } from '../../../components/dynamic' + +export const dynamic = 'force-static' +export const revalidate = 60 + +export default ({ params: { slug } }) => { + return ( + } + > + + + ) +} diff --git a/test/e2e/app-dir/ppr-full/app/layout.jsx b/test/e2e/app-dir/ppr-full/app/layout.jsx new file mode 100644 index 0000000000000..a9a05c18834d6 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/layout.jsx @@ -0,0 +1,19 @@ +import { Links } from '../components/links' + +export default ({ children }) => { + return ( + + +

Partial Prerendering

+

+ Below are links that are associated with different pages that all will + partially prerender +

+ +
{children}
+ + + ) +} diff --git a/test/e2e/app-dir/ppr-full/app/loading/[slug]/page.jsx b/test/e2e/app-dir/ppr-full/app/loading/[slug]/page.jsx new file mode 100644 index 0000000000000..027d39da1c2b6 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/loading/[slug]/page.jsx @@ -0,0 +1,16 @@ +import React, { Suspense } from 'react' +import { Dynamic } from '../../../components/dynamic' + +export const revalidate = 60 + +export default ({ params: { slug } }) => { + return ( + }> + + + ) +} + +export const generateStaticParams = async () => { + return [{ slug: 'a' }] +} diff --git a/test/e2e/app-dir/ppr-full/app/loading/loading.jsx b/test/e2e/app-dir/ppr-full/app/loading/loading.jsx new file mode 100644 index 0000000000000..d3dcfed2a403a --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/loading/loading.jsx @@ -0,0 +1,3 @@ +export default () => { + return loading.jsx +} diff --git a/test/e2e/app-dir/ppr-full/app/nested/[slug]/page.jsx b/test/e2e/app-dir/ppr-full/app/nested/[slug]/page.jsx new file mode 100644 index 0000000000000..fec0c0923d427 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/nested/[slug]/page.jsx @@ -0,0 +1,16 @@ +import React, { Suspense } from 'react' +import { Dynamic } from '../../../components/dynamic' + +export const revalidate = 60 + +export default ({ params: { slug } }) => { + return ( + }> + + + ) +} + +export const generateStaticParams = async () => { + return [{ slug: 'a' }] +} diff --git a/test/e2e/app-dir/ppr-full/app/no-suspense/nested/[slug]/page.jsx b/test/e2e/app-dir/ppr-full/app/no-suspense/nested/[slug]/page.jsx new file mode 100644 index 0000000000000..d7f48f3a26137 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/no-suspense/nested/[slug]/page.jsx @@ -0,0 +1,10 @@ +import React from 'react' +import { Dynamic } from '../../../../components/dynamic' + +export default ({ params: { slug } }) => { + return +} + +export const generateStaticParams = async () => { + return [{ slug: 'a' }] +} diff --git a/test/e2e/app-dir/ppr-full/app/no-suspense/page.jsx b/test/e2e/app-dir/ppr-full/app/no-suspense/page.jsx new file mode 100644 index 0000000000000..ef2cf10a32aaa --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/no-suspense/page.jsx @@ -0,0 +1,6 @@ +import React from 'react' +import { Dynamic } from '../../components/dynamic' + +export default () => { + return +} diff --git a/test/e2e/app-dir/ppr-full/app/on-demand/[slug]/page.jsx b/test/e2e/app-dir/ppr-full/app/on-demand/[slug]/page.jsx new file mode 100644 index 0000000000000..289d8a9d63256 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/on-demand/[slug]/page.jsx @@ -0,0 +1,10 @@ +import React, { Suspense } from 'react' +import { Dynamic } from '../../../components/dynamic' + +export default ({ params: { slug } }) => { + return ( + }> + + + ) +} diff --git a/test/e2e/app-dir/ppr-full/app/page.jsx b/test/e2e/app-dir/ppr-full/app/page.jsx new file mode 100644 index 0000000000000..1d5918209416d --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/page.jsx @@ -0,0 +1,10 @@ +import React, { Suspense } from 'react' +import { Dynamic } from '../components/dynamic' + +export default () => { + return ( + }> + + + ) +} diff --git a/test/e2e/app-dir/ppr-full/app/static/page.jsx b/test/e2e/app-dir/ppr-full/app/static/page.jsx new file mode 100644 index 0000000000000..f90cd84e78518 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/app/static/page.jsx @@ -0,0 +1,6 @@ +import React from 'react' +import { Dynamic } from '../../components/dynamic' + +export default () => { + return +} diff --git a/test/e2e/app-dir/ppr-full/components/dynamic.jsx b/test/e2e/app-dir/ppr-full/components/dynamic.jsx new file mode 100644 index 0000000000000..0c931f8500f5e --- /dev/null +++ b/test/e2e/app-dir/ppr-full/components/dynamic.jsx @@ -0,0 +1,37 @@ +import React from 'react' +import { headers } from 'next/headers' + +export const Dynamic = ({ pathname, fallback }) => { + if (fallback) { + return
Loading...
+ } + + const messages = [] + const names = ['x-test-input', 'user-agent'] + const list = headers() + + for (const name of names) { + messages.push({ name, value: list.get(name) }) + } + + return ( +
+
+ {pathname && ( + <> +
Pathname
+
{pathname}
+ + )} + {messages.map(({ name, value }) => ( + +
+ Header: {name} +
+
{value ?? 'null'}
+
+ ))} +
+
+ ) +} diff --git a/test/e2e/app-dir/ppr-full/components/links.jsx b/test/e2e/app-dir/ppr-full/components/links.jsx new file mode 100644 index 0000000000000..645fcc8259542 --- /dev/null +++ b/test/e2e/app-dir/ppr-full/components/links.jsx @@ -0,0 +1,42 @@ +import React from 'react' +import Link from 'next/link' + +const links = [ + { href: '/', tag: 'pre-generated' }, + { href: '/nested/a', tag: 'pre-generated' }, + { href: '/nested/b', tag: 'on-demand' }, + { href: '/nested/c', tag: 'on-demand' }, + { href: '/on-demand/a', tag: 'on-demand, no-gsp' }, + { href: '/on-demand/b', tag: 'on-demand, no-gsp' }, + { href: '/on-demand/c', tag: 'on-demand, no-gsp' }, + { href: '/loading/a', tag: 'loading.jsx, pre-generated' }, + { href: '/loading/b', tag: 'loading.jsx, on-demand' }, + { href: '/loading/c', tag: 'loading.jsx, on-demand' }, + { href: '/static', tag: 'static' }, + { href: '/no-suspense', tag: 'no suspense' }, + { href: '/no-suspense/nested/a', tag: 'no suspense, pre-generated' }, + { href: '/no-suspense/nested/b', tag: 'no suspense, on-demand' }, + { href: '/no-suspense/nested/c', tag: 'no suspense, on-demand' }, + { href: '/dynamic/force-dynamic', tag: "dynamic = 'force-dynamic'" }, + { href: '/dynamic/force-static', tag: "dynamic = 'force-static'" }, + { href: '/edge/suspense', tag: 'edge, pre-generated' }, + { href: '/edge/suspense/a', tag: 'edge, pre-generated' }, + { href: '/edge/suspense/b', tag: 'edge, on-demand' }, + { href: '/edge/suspense/c', tag: 'edge, on-demand' }, + { href: '/edge/no-suspense', tag: 'edge, no suspense, pre-generated' }, + { href: '/edge/no-suspense/a', tag: 'edge, no suspense, pre-generated' }, + { href: '/edge/no-suspense/b', tag: 'edge, no suspense, on-demand' }, + { href: '/edge/no-suspense/c', tag: 'edge, no suspense, on-demand' }, +] + +export const Links = () => { + return ( +
    + {links.map(({ href, tag }) => ( +
  • + {href} {tag} +
  • + ))} +
+ ) +} diff --git a/test/e2e/app-dir/ppr-full/next.config.js b/test/e2e/app-dir/ppr-full/next.config.js new file mode 100644 index 0000000000000..49ab599c5039b --- /dev/null +++ b/test/e2e/app-dir/ppr-full/next.config.js @@ -0,0 +1,8 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + experimental: { + ppr: true, + }, +} + +module.exports = nextConfig diff --git a/test/e2e/app-dir/ppr-full/ppr-full.test.ts b/test/e2e/app-dir/ppr-full/ppr-full.test.ts new file mode 100644 index 0000000000000..b9086bb2499eb --- /dev/null +++ b/test/e2e/app-dir/ppr-full/ppr-full.test.ts @@ -0,0 +1,145 @@ +import { createNextDescribe } from 'e2e-utils' + +const pages = [ + { pathname: '/', dynamic: true }, + { pathname: '/nested/a', dynamic: true, revalidate: 60 }, + { pathname: '/nested/b', dynamic: true, revalidate: 60 }, + { pathname: '/nested/c', dynamic: true, revalidate: 60 }, + { pathname: '/on-demand/a', dynamic: true }, + { pathname: '/on-demand/b', dynamic: true }, + { pathname: '/on-demand/c', dynamic: true }, + { pathname: '/loading/a', dynamic: true, revalidate: 60 }, + { pathname: '/loading/b', dynamic: true, revalidate: 60 }, + { pathname: '/loading/c', dynamic: true, revalidate: 60 }, + { pathname: '/static', dynamic: false }, + { pathname: '/no-suspense', dynamic: true }, + { pathname: '/no-suspense/nested/a', dynamic: true }, + { pathname: '/no-suspense/nested/b', dynamic: true }, + { pathname: '/no-suspense/nested/c', dynamic: true }, + // TODO: uncomment when we've fixed the 404 case for force-dynamic pages + // { pathname: '/dynamic/force-dynamic', dynamic: 'force-dynamic' }, + { + pathname: '/dynamic/force-static', + dynamic: 'force-static', + revalidate: 60, + }, +] + +createNextDescribe( + 'ppr-full', + { + files: __dirname, + }, + ({ next, isNextDev, isNextStart, isNextDeploy }) => { + describe('dynamic pages should resume', () => { + it.each(pages.filter((p) => p.dynamic === true))( + 'should resume $pathname', + async ({ pathname }) => { + const expected = `${Date.now()}:${Math.random()}` + const res = await next.fetch(pathname, { + headers: { 'X-Test-Input': expected }, + }) + expect(res.status).toEqual(200) + expect(res.headers.get('content-type')).toEqual( + 'text/html; charset=utf-8' + ) + const html = await res.text() + expect(html).toContain(expected) + expect(html).toContain('') + } + ) + }) + + if (!isNextDev) { + describe('prefetch RSC payloads should return', () => { + it.each(pages)( + 'should prefetch $pathname', + async ({ pathname, dynamic, revalidate }) => { + const unexpected = `${Date.now()}:${Math.random()}` + const res = await next.fetch(pathname, { + headers: { + RSC: '1', + 'Next-Router-Prefetch': '1', + 'X-Test-Input': unexpected, + }, + }) + expect(res.status).toEqual(200) + expect(res.headers.get('content-type')).toEqual('text/x-component') + + const cache = res.headers.get('cache-control') + + // cache header handling is different when in minimal mode + if (isNextDeploy) { + expect(cache).toContain('public') + expect(cache).toContain('must-revalidate') + } else { + expect(cache).toContain(`s-maxage=${revalidate || '31536000'}`) + expect(cache).toContain('stale-while-revalidate') + } + + // Expect that static RSC prefetches do not contain the dynamic text. + const text = await res.text() + expect(text).not.toContain(unexpected) + + if (dynamic === true) { + // The dynamic component will contain the text "needle" if it was + // rendered using dynamic content. + expect(text).not.toContain('needle') + expect(res.headers.get('X-NextJS-Postponed')).toEqual('1') + } else { + if (dynamic !== false) { + expect(text).toContain('needle') + } + + expect(res.headers.has('X-NextJS-Postponed')).toEqual(false) + } + } + ) + }) + + describe('dynamic RSC payloads should return', () => { + it.each(pages)( + 'should fetch $pathname', + async ({ pathname, dynamic }) => { + const expected = `${Date.now()}:${Math.random()}` + const res = await next.fetch(pathname, { + headers: { RSC: '1', 'X-Test-Input': expected }, + }) + expect(res.status).toEqual(200) + expect(res.headers.get('content-type')).toEqual('text/x-component') + expect(res.headers.has('X-NextJS-Postponed')).toEqual(false) + + const cache = res.headers.get('cache-control') + + // cache header handling is different when in minimal mode + if (isNextDeploy) { + expect(cache).toContain('private') + expect(cache).toContain('no-store') + expect(cache).toContain('no-cache') + expect(cache).toContain('max-age=0') + expect(cache).toContain('must-revalidate') + } else { + expect(cache).toContain('s-maxage=1') + expect(cache).toContain('stale-while-revalidate') + } + + const text = await res.text() + + if (dynamic !== false) { + expect(text).toContain('needle') + } + + if (dynamic === true) { + // Expect that dynamic RSC prefetches do contain the dynamic text. + expect(text).toContain(expected) + } else { + // Expect that dynamic RSC prefetches do not contain the dynamic text + // when we're forced static. + expect(text).not.toContain(expected) + } + } + ) + }) + } + } +) diff --git a/test/e2e/app-dir/ppr/ppr.test.ts b/test/e2e/app-dir/ppr/ppr.test.ts index 8d12a693716a4..51151ee03b6e5 100644 --- a/test/e2e/app-dir/ppr/ppr.test.ts +++ b/test/e2e/app-dir/ppr/ppr.test.ts @@ -5,7 +5,6 @@ createNextDescribe( 'ppr', { files: __dirname, - skipDeployment: true, }, ({ next, isNextDev, isNextStart }) => { it('should indicate the feature is experimental', async () => { From 77f8889b7ca6072f386d382d7ce65b57a5065ce2 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 29 Nov 2023 11:45:06 -0800 Subject: [PATCH 034/189] use 303 status code for redirects in fetch actions (#59017) ### What? A `redirect` that occurs during a fetch action will get a status code of 200, while the redirection logic is handled client-side. ### Why? In this scenario, the redirect is handled by the client router, so no `Location` is set on the action response. However for debugging / logging purposes, it'd be useful to still return the same status code used in other cases (see #58885) ### How? Rather than selectively setting the status to 303 in the non-fetch action case, this always applies it. Closes NEXT-1745 --- .../next/src/server/app-render/action-handler.ts | 7 ++++--- test/e2e/app-dir/actions/app-action.test.ts | 13 ++++++++++++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 11614419091fe..9fcf679dfae61 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -577,13 +577,15 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc const redirectUrl = getURLFromRedirectError(err) const statusCode = getRedirectStatusCodeFromError(err) - // if it's a fetch action, we don't want to mess with the status code - // and we'll handle it on the client router await addRevalidationHeader(res, { staticGenerationStore, requestStore, }) + // if it's a fetch action, we'll set the status code for logging/debugging purposes + // but we won't set a Location header, as the redirect will be handled by the client router + res.statusCode = statusCode + if (isFetchAction) { return { type: 'done', @@ -607,7 +609,6 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc } res.setHeader('Location', redirectUrl) - res.statusCode = statusCode return { type: 'done', result: RenderResult.fromStatic(''), diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 5a3692a2b0266..77f287e91f8e9 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -592,7 +592,17 @@ createNextDescribe( }) it('should handle redirect to a relative URL in a single pass', async () => { - const browser = await next.browser('/client') + let responseCode: number + const browser = await next.browser('/client', { + beforePageLoad(page) { + page.on('response', async (res: Response) => { + const headers = await res.allHeaders() + if (headers['x-action-redirect']) { + responseCode = res.status() + } + }) + }, + }) await waitFor(3000) @@ -606,6 +616,7 @@ createNextDescribe( // no other requests should be made expect(requests).toEqual(['/client']) + await check(() => responseCode, 303) }) it('should handle regular redirects', async () => { From 8395059d3326d9dca089e6f0309fdb016ca7ace2 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 29 Nov 2023 11:55:00 -0800 Subject: [PATCH 035/189] verify action id before parsing body (#58977) ### What? When handling a server action, in the non-progressive enhanced case, React will attempt to parse the request body before verifying if a valid server action is received. This results in an "Error: Connection Closed" error being thrown, rather than ignoring the action and failing more gracefully ### Why? To support progressive enhancement with form actions, the `actionId` value is added as a hidden input in the form, so the action ID from the header shouldn't be verified until determining that we've reached the non-PE case. ([React ref](https://github.com/facebook/react/pull/26774)). However, in https://github.com/vercel/next.js/pull/49187, support was added for a URL encoded form (which is not currently used, as indicated on the PR). Despite it not being used for server actions, it's currently possible to trigger this codepath, ie by calling redirect in an action handler with a 307/308 status code with some data in the URL. This would result in a 500 error. ### How? React should not attempt to parse the URL encoded form data until after we've verified the server action header for the non-PE case. x-ref NEXT-1733 [Slack context](https://vercel.slack.com/archives/C03S8ED1DKM/p1700674895218399?thread_ts=1700060786.749079&cid=C03S8ED1DKM) --- .../src/server/app-render/action-handler.ts | 89 +++++++++++++++---- test/e2e/app-dir/actions/app-action.test.ts | 68 ++++++++++++++ .../app/redirects/api-redirect-307/route.js | 6 ++ .../app/redirects/api-redirect-308/route.js | 6 ++ .../e2e/app-dir/actions/app/redirects/page.js | 8 ++ 5 files changed, 158 insertions(+), 19 deletions(-) create mode 100644 test/e2e/app-dir/actions/app/redirects/api-redirect-307/route.js create mode 100644 test/e2e/app-dir/actions/app/redirects/api-redirect-308/route.js diff --git a/packages/next/src/server/app-render/action-handler.ts b/packages/next/src/server/app-render/action-handler.ts index 9fcf679dfae61..c89751955d905 100644 --- a/packages/next/src/server/app-render/action-handler.ts +++ b/packages/next/src/server/app-render/action-handler.ts @@ -238,6 +238,16 @@ function limitUntrustedHeaderValueForLogs(value: string) { return value.length > 100 ? value.slice(0, 100) + '...' : value } +type ServerModuleMap = Record< + string, + | { + id: string + chunks: string[] + name: string + } + | undefined +> + export async function handleAction({ req, res, @@ -252,13 +262,7 @@ export async function handleAction({ req: IncomingMessage res: ServerResponse ComponentMod: AppPageModule - serverModuleMap: { - [id: string]: { - id: string - chunks: string[] - name: string - } - } + serverModuleMap: ServerModuleMap generateFlight: GenerateFlight staticGenerationStore: StaticGenerationStore requestStore: RequestStore @@ -392,6 +396,7 @@ export async function handleAction({ let actionResult: RenderResult | undefined let formState: any | undefined + let actionModId: string | undefined try { await actionAsyncStorage.run({ isAction: true }, async () => { @@ -418,6 +423,15 @@ export async function handleAction({ return } } else { + try { + actionModId = getActionModIdOrError(actionId, serverModuleMap) + } catch (err) { + console.error(err) + return { + type: 'not-found', + } + } + let actionData = '' const reader = webRequest.body.getReader() @@ -487,6 +501,15 @@ export async function handleAction({ return } } else { + try { + actionModId = getActionModIdOrError(actionId, serverModuleMap) + } catch (err) { + console.error(err) + return { + type: 'not-found', + } + } + const chunks = [] for await (const chunk of req) { @@ -528,19 +551,11 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc // / -> fire action -> POST / -> appRender1 -> modId for the action file // /foo -> fire action -> POST /foo -> appRender2 -> modId for the action file - let actionModId: string try { - if (!actionId) { - throw new Error('Invariant: actionId should be set') - } - - actionModId = serverModuleMap[actionId].id + actionModId = + actionModId ?? getActionModIdOrError(actionId, serverModuleMap) } catch (err) { - // When this happens, it could be a deployment skew where the action came - // from a different deployment. We'll just return a 404 with a message logged. - console.error( - `Failed to find Server Action "${actionId}". This request might be from an older or newer deployment.` - ) + console.error(err) return { type: 'not-found', } @@ -548,7 +563,10 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc const actionHandler = ( await ComponentMod.__next_app__.require(actionModId) - )[actionId] + )[ + // `actionId` must exist if we got here, as otherwise we would have thrown an error above + actionId! + ] const returnVal = await actionHandler.apply(null, bound) @@ -675,3 +693,36 @@ To configure the body size limit for Server Actions, see: https://nextjs.org/doc throw err } } + +/** + * Attempts to find the module ID for the action from the module map. When this fails, it could be a deployment skew where + * the action came from a different deployment. It could also simply be an invalid POST request that is not a server action. + * In either case, we'll throw an error to be handled by the caller. + */ +function getActionModIdOrError( + actionId: string | null, + serverModuleMap: ServerModuleMap +): string { + try { + // if we're missing the action ID header, we can't do any further processing + if (!actionId) { + throw new Error("Invariant: Missing 'next-action' header.") + } + + const actionModId = serverModuleMap?.[actionId]?.id + + if (!actionModId) { + throw new Error( + "Invariant: Couldn't find action module ID from module map." + ) + } + + return actionModId + } catch (err) { + throw new Error( + `Failed to find Server Action "${actionId}". This request might be from an older or newer deployment. ${ + err instanceof Error ? `Original error: ${err.message}` : '' + }` + ) + } +} diff --git a/test/e2e/app-dir/actions/app-action.test.ts b/test/e2e/app-dir/actions/app-action.test.ts index 77f287e91f8e9..7a002f2f3712c 100644 --- a/test/e2e/app-dir/actions/app-action.test.ts +++ b/test/e2e/app-dir/actions/app-action.test.ts @@ -409,6 +409,34 @@ createNextDescribe( ) }) + it('should 404 when POSTing an invalid server action', async () => { + const res = await next.fetch('/non-existent-route', { + method: 'POST', + headers: { + 'content-type': 'application/x-www-form-urlencoded', + }, + body: 'foo=bar', + }) + + expect(res.status).toBe(404) + }) + + it('should log a warning when a server action is not found but an id is provided', async () => { + await next.fetch('/server', { + method: 'POST', + headers: { + 'content-type': 'application/x-www-form-urlencoded', + 'next-action': 'abc123', + }, + body: 'foo=bar', + }) + + await check( + () => next.cliOutput, + /Failed to find Server Action "abc123". This request might be from an older or newer deployment./ + ) + }) + if (isNextStart) { it('should not expose action content in sourcemaps', async () => { const sourcemap = ( @@ -972,6 +1000,46 @@ createNextDescribe( expect(postRequests).toEqual(['/redirects/api-redirect-permanent']) expect(responseCodes).toEqual([303]) }) + + it.each(['307', '308'])( + `redirects properly when server action handler redirects with a %s status code`, + async (statusCode) => { + const postRequests = [] + const responseCodes = [] + + const browser = await next.browser('/redirects', { + beforePageLoad(page) { + page.on('request', (request: Request) => { + const url = new URL(request.url()) + if (request.method() === 'POST') { + postRequests.push(`${url.pathname}${url.search}`) + } + }) + + page.on('response', (response: Response) => { + const url = new URL(response.url()) + const status = response.status() + + if (postRequests.includes(`${url.pathname}${url.search}`)) { + responseCodes.push(status) + } + }) + }, + }) + + await browser.elementById(`submit-api-redirect-${statusCode}`).click() + await check(() => browser.url(), /success=true/) + expect(await browser.elementById('redirect-page')).toBeTruthy() + + // since a 307/308 status code follows the redirect, the POST request should be made to both the action handler and the redirect target + expect(postRequests).toEqual([ + `/redirects/api-redirect-${statusCode}`, + `/redirects?success=true`, + ]) + + expect(responseCodes).toEqual([Number(statusCode), 200]) + } + ) }) } ) diff --git a/test/e2e/app-dir/actions/app/redirects/api-redirect-307/route.js b/test/e2e/app-dir/actions/app/redirects/api-redirect-307/route.js new file mode 100644 index 0000000000000..c3b2be27f1c2c --- /dev/null +++ b/test/e2e/app-dir/actions/app/redirects/api-redirect-307/route.js @@ -0,0 +1,6 @@ +export function POST(request) { + return Response.redirect( + `${request.nextUrl.origin}/redirects?success=true`, + 307 + ) +} diff --git a/test/e2e/app-dir/actions/app/redirects/api-redirect-308/route.js b/test/e2e/app-dir/actions/app/redirects/api-redirect-308/route.js new file mode 100644 index 0000000000000..f273fe224e652 --- /dev/null +++ b/test/e2e/app-dir/actions/app/redirects/api-redirect-308/route.js @@ -0,0 +1,6 @@ +export function POST(request) { + return Response.redirect( + `${request.nextUrl.origin}/redirects?success=true`, + 308 + ) +} diff --git a/test/e2e/app-dir/actions/app/redirects/page.js b/test/e2e/app-dir/actions/app/redirects/page.js index 68afb2f2d2fb1..99a64701d630d 100644 --- a/test/e2e/app-dir/actions/app/redirects/page.js +++ b/test/e2e/app-dir/actions/app/redirects/page.js @@ -13,6 +13,14 @@ export default function Home() { id="submit-api-redirect-permanent" /> +

POST /api-reponse-redirect-307

+
+ +
+

POST /api-reponse-redirect-308

+
+ +
) } From 0345ee85f8d72e09de2220e8f890eaf3fd75ed94 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 29 Nov 2023 20:00:26 +0000 Subject: [PATCH 036/189] v14.0.4-canary.27 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index eafb20a6a3a87..9ec81f43fd4f3 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.26" + "version": "14.0.4-canary.27" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 4d2f23e9bd3f1..eec873fdd1d52 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 2937b5de1be82..d9f69fc9d8cc0 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.26", + "@next/eslint-plugin-next": "14.0.4-canary.27", "@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 9f847e2dcb45c..82fb9d7fd5d1a 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index d45e1ab992a05..51323878d19f9 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "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 307b4e4a454de..acb82b138bc41 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 13f0d642ba42e..b33d825572cd3 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index f4a5af6230ad6..82425948fda27 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 26df08c9bc798..9ac4e29677736 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 051c82573376b..06dfc4e8992a9 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "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 f9de50c1aff87..68ffac87ea513 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "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 a27e4ebb307fb..a883f8777add9 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 541b9471936fc..806d5a7eefcc6 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index dd4d5aebc3f87..15ee51a69e6db 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.26", + "@next/env": "14.0.4-canary.27", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.26", - "@next/polyfill-nomodule": "14.0.4-canary.26", - "@next/react-dev-overlay": "14.0.4-canary.26", - "@next/react-refresh-utils": "14.0.4-canary.26", - "@next/swc": "14.0.4-canary.26", + "@next/polyfill-module": "14.0.4-canary.27", + "@next/polyfill-nomodule": "14.0.4-canary.27", + "@next/react-dev-overlay": "14.0.4-canary.27", + "@next/react-refresh-utils": "14.0.4-canary.27", + "@next/swc": "14.0.4-canary.27", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index d4686b0639b56..f815e1d368e7d 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": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index d248bdac265b3..35e8a8e5977cb 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "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 463fd4c9f725f..4ee5f72544075 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.26", + "version": "14.0.4-canary.27", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.26", + "next": "14.0.4-canary.27", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ce979c1ac3d15..0d3081fbfc6db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.26 + specifier: 14.0.4-canary.27 version: link:../next outdent: specifier: 0.8.0 From c1f94cfc7385d852b1d812ed0badf2a0ac4def93 Mon Sep 17 00:00:00 2001 From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com> Date: Wed, 29 Nov 2023 21:29:47 +0000 Subject: [PATCH 037/189] Docs: Delete fast refresh example (#59003) Closing: https://github.com/vercel/feedback/issues/47083 This example no longer exists in the Next.js repo. --- docs/04-architecture/fast-refresh.mdx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/04-architecture/fast-refresh.mdx b/docs/04-architecture/fast-refresh.mdx index 9a1f15702ee62..02ff4810aa941 100644 --- a/docs/04-architecture/fast-refresh.mdx +++ b/docs/04-architecture/fast-refresh.mdx @@ -3,13 +3,6 @@ title: Fast Refresh description: Fast Refresh is a hot module reloading experience that gives you instantaneous feedback on edits made to your React components. --- -
- Examples - -- [Fast Refresh Demo](https://github.com/vercel/next.js/tree/canary/examples/fast-refresh-demo) - -
- Fast Refresh is a Next.js feature that gives you instantaneous feedback on edits made to your React components. Fast Refresh is enabled by default in all Next.js applications on **9.4 or newer**. With Next.js Fast Refresh enabled, From 54544c90198f4839944fcaeed886a0d2d145a829 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 29 Nov 2023 23:22:05 +0000 Subject: [PATCH 038/189] v14.0.4-canary.28 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 9ec81f43fd4f3..8273886632ca5 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.27" + "version": "14.0.4-canary.28" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index eec873fdd1d52..43bfd6c638c26 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index d9f69fc9d8cc0..5b6833a2f19e7 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.27", + "@next/eslint-plugin-next": "14.0.4-canary.28", "@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 82fb9d7fd5d1a..491e33ed3f5b8 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 51323878d19f9..3bdcb4b9931ad 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "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 acb82b138bc41..16663e746f3cb 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index b33d825572cd3..fdf85f9a75812 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 82425948fda27..b393af8e0dadc 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 9ac4e29677736..c91d75144c59e 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 06dfc4e8992a9..9f834f812b0db 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "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 68ffac87ea513..b153602bf8423 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "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 a883f8777add9..70cc83594274e 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 806d5a7eefcc6..ff864cd1215ea 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 15ee51a69e6db..2e2b949d755a1 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.27", + "@next/env": "14.0.4-canary.28", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.27", - "@next/polyfill-nomodule": "14.0.4-canary.27", - "@next/react-dev-overlay": "14.0.4-canary.27", - "@next/react-refresh-utils": "14.0.4-canary.27", - "@next/swc": "14.0.4-canary.27", + "@next/polyfill-module": "14.0.4-canary.28", + "@next/polyfill-nomodule": "14.0.4-canary.28", + "@next/react-dev-overlay": "14.0.4-canary.28", + "@next/react-refresh-utils": "14.0.4-canary.28", + "@next/swc": "14.0.4-canary.28", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index f815e1d368e7d..80995b9c7458d 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": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 35e8a8e5977cb..c9d8745071fb3 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "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 4ee5f72544075..41e5febcdce60 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.27", + "version": "14.0.4-canary.28", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.27", + "next": "14.0.4-canary.28", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d3081fbfc6db..c066f462f8b52 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.27 + specifier: 14.0.4-canary.28 version: link:../next outdent: specifier: 0.8.0 From 92f7d0c5e9335f62a4fab6e20263439d27fd5b2b Mon Sep 17 00:00:00 2001 From: Luke Schlangen Date: Wed, 29 Nov 2023 18:54:44 -0600 Subject: [PATCH 039/189] examples: add direct link to Dockerfile (#58793) --- examples/with-docker/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/with-docker/README.md b/examples/with-docker/README.md index acfc0263f6011..12cb7cb60c5db 100644 --- a/examples/with-docker/README.md +++ b/examples/with-docker/README.md @@ -24,7 +24,7 @@ You can view your images created with `docker images`. ### In existing projects -To add support for Docker to an existing project, just copy the `Dockerfile` into the root of the project and add the following to the `next.config.js` file: +To add support for Docker to an existing project, just copy the [`Dockerfile`](https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile) into the root of the project and add the following to the `next.config.js` file: ```js // next.config.js From d509c2d52894e23e89eaec136847a0a60cd26519 Mon Sep 17 00:00:00 2001 From: Dylan700 <54528768+Dylan700@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:37:03 +1100 Subject: [PATCH 040/189] examples: Update Electron Typescript Example with Best Practices (#58947) Co-authored-by: Lee Robinson --- examples/with-electron-typescript/README.md | 4 +-- .../electron-src/index.ts | 2 +- .../electron-src/preload.ts | 25 +++++++++---------- .../with-electron-typescript/package.json | 16 ++++++------ .../renderer/interfaces/index.ts | 9 ++++--- .../renderer/pages/index.tsx | 8 +++--- .../renderer/tsconfig.json | 5 ++-- 7 files changed, 35 insertions(+), 34 deletions(-) diff --git a/examples/with-electron-typescript/README.md b/examples/with-electron-typescript/README.md index d4331039e6da8..26e7ae8197f27 100644 --- a/examples/with-electron-typescript/README.md +++ b/examples/with-electron-typescript/README.md @@ -1,6 +1,6 @@ # Electron with Typescript application example -This example show how you can use Next.js inside an Electron application to avoid a lot of configuration, use Next.js router as view and use server-render to speed up the initial render of the application. Both Next.js and Electron layers are written in TypeScript and compiled to JavaScript during the build process. +This example shows how to use Next.js inside an Electron application. To avoid a lot of configuration, we use Next.js as a router for pages, and use server rendering to speed up the initial render of the application. Both Next.js and Electron layers are written in TypeScript and compiled to JavaScript during the build process. | Part | Source code (Typescript) | Builds (JavaScript) | | ---------- | ------------------------ | ------------------- | @@ -8,7 +8,7 @@ This example show how you can use Next.js inside an Electron application to avoi | Electron | `/electron-src` | `/main` | | Production | | `/dist` | -For development it's going to run a HTTP server and let Next.js handle routing. In production it use `output: 'export'` to pre-generate HTML static files and use them in your app instead of running an HTTP server. +For development it's going to run a HTTP server and let Next.js handle routing. In production it will use `output: 'export'` to pre-generate HTML static files and use them in your app (instead of running a HTTP server). ## How to use diff --git a/examples/with-electron-typescript/electron-src/index.ts b/examples/with-electron-typescript/electron-src/index.ts index 424360a4f19fb..13a20750a0b2b 100644 --- a/examples/with-electron-typescript/electron-src/index.ts +++ b/examples/with-electron-typescript/electron-src/index.ts @@ -16,7 +16,7 @@ app.on('ready', async () => { height: 600, webPreferences: { nodeIntegration: false, - contextIsolation: false, + contextIsolation: true, preload: join(__dirname, 'preload.js'), }, }) diff --git a/examples/with-electron-typescript/electron-src/preload.ts b/examples/with-electron-typescript/electron-src/preload.ts index 607ed7667007b..926a9a75b96b5 100644 --- a/examples/with-electron-typescript/electron-src/preload.ts +++ b/examples/with-electron-typescript/electron-src/preload.ts @@ -1,17 +1,16 @@ /* eslint-disable @typescript-eslint/no-namespace */ // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { ipcRenderer, IpcRenderer } from 'electron' +import { contextBridge, ipcRenderer } from 'electron' +import { IpcRendererEvent } from 'electron/main' -declare global { - namespace NodeJS { - interface Global { - ipcRenderer: IpcRenderer - } - } -} - -// Since we disabled nodeIntegration we can reintroduce -// needed node functionality here -process.once('loaded', () => { - global.ipcRenderer = ipcRenderer +// We are using the context bridge to securely expose NodeAPIs. +// Please note that many Node APIs grant access to local system resources. +// Be very cautious about which globals and APIs you expose to untrusted remote content. +contextBridge.exposeInMainWorld('electron', { + sayHello: () => ipcRenderer.send('message', 'hi from next'), + receiveHello: (handler: (event: IpcRendererEvent, ...args: any[]) => void) => + ipcRenderer.on('message', handler), + stopReceivingHello: ( + handler: (event: IpcRendererEvent, ...args: any[]) => void + ) => ipcRenderer.removeListener('message', handler), }) diff --git a/examples/with-electron-typescript/package.json b/examples/with-electron-typescript/package.json index e1f5f9f2dbf0e..1c147597c6391 100644 --- a/examples/with-electron-typescript/package.json +++ b/examples/with-electron-typescript/package.json @@ -13,20 +13,20 @@ "type-check": "tsc -p ./renderer/tsconfig.json && tsc -p ./electron-src/tsconfig.json" }, "dependencies": { - "electron-is-dev": "^1.1.0", + "electron-is-dev": "^1.2.0", "electron-next": "^3.1.5", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { - "@types/node": "^14.14.6", - "@types/react": "^16.9.9", - "@types/react-dom": "^16.9.9", - "electron": "^13", - "electron-builder": "^23.0.3", + "@types/node": "^14.18.63", + "@types/react": "^16.14.52", + "@types/react-dom": "^16.9.24", + "electron": "^27.1.2", + "electron-builder": "^24.9.1", "next": "latest", - "rimraf": "^3.0.0", - "typescript": "^4.0.5" + "rimraf": "^3.0.2", + "typescript": "^4.9.5" }, "build": { "asar": true, diff --git a/examples/with-electron-typescript/renderer/interfaces/index.ts b/examples/with-electron-typescript/renderer/interfaces/index.ts index 76dd79475ba49..3179369fb109f 100644 --- a/examples/with-electron-typescript/renderer/interfaces/index.ts +++ b/examples/with-electron-typescript/renderer/interfaces/index.ts @@ -4,13 +4,14 @@ // // import User from 'path/to/interfaces'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { IpcRenderer } from 'electron' declare global { // eslint-disable-next-line @typescript-eslint/no-namespace - namespace NodeJS { - interface Global { - ipcRenderer: IpcRenderer + interface Window { + electron: { + sayHello: () => void + receiveHello: (handler: (event, args) => void) => void + stopReceivingHello: (handler: (event, args) => void) => void } } } diff --git a/examples/with-electron-typescript/renderer/pages/index.tsx b/examples/with-electron-typescript/renderer/pages/index.tsx index 50324118de465..8b4303901d5ac 100644 --- a/examples/with-electron-typescript/renderer/pages/index.tsx +++ b/examples/with-electron-typescript/renderer/pages/index.tsx @@ -6,16 +6,16 @@ const IndexPage = () => { useEffect(() => { const handleMessage = (_event, args) => alert(args) - // add a listener to 'message' channel - global.ipcRenderer.addListener('message', handleMessage) + // listen to the 'message' channel + window.electron.receiveHello(handleMessage) return () => { - global.ipcRenderer.removeListener('message', handleMessage) + window.electron.stopReceivingHello(handleMessage) } }, []) const onSayHiClick = () => { - global.ipcRenderer.send('message', 'hi from next') + window.electron.sayHello() } return ( diff --git a/examples/with-electron-typescript/renderer/tsconfig.json b/examples/with-electron-typescript/renderer/tsconfig.json index 93a83a407c40c..771b6d8ee5d3b 100644 --- a/examples/with-electron-typescript/renderer/tsconfig.json +++ b/examples/with-electron-typescript/renderer/tsconfig.json @@ -12,8 +12,9 @@ "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve" + "jsx": "preserve", + "incremental": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../next.config.js"], "exclude": ["node_modules"] } From d605ef610136b9bb62583b0d0f02c56f515188d8 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 29 Nov 2023 23:57:42 -0800 Subject: [PATCH 041/189] fix interception routes with rewrites (#59094) ### What? When using interception routes & rewrites, on first interception the router will properly handle the request. But when using the back button and attempting another interception, it won't work ### Why? Intercepting routes rely on the accuracy of `nextUrl` -- but when `ACTION_RESTORE` is dispatched (in the `popstate` event), `nextUrl` is restored from `url.pathname` rather than the flight router state. ### How? This uses the `extractPathFromFlightRouterState` util which will properly handle setting `nextUrl`. This util is also used when creating the initial router state. Closes NEXT-1747 Fixes #56072 --- .../router-reducer/reducers/restore-reducer.ts | 3 ++- .../app/[lang]/@modal/(.)photos/[id]/page.tsx | 7 +++++++ .../app/[lang]/layout.tsx | 4 ++++ .../app/[lang]/photos/[id]/page.tsx | 7 +++++++ .../interception-middleware-rewrite.test.ts | 17 +++++++++++++++++ 5 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/@modal/(.)photos/[id]/page.tsx create mode 100644 test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/photos/[id]/page.tsx diff --git a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.ts b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.ts index 06e453c6edfcc..801971be406ef 100644 --- a/packages/next/src/client/components/router-reducer/reducers/restore-reducer.ts +++ b/packages/next/src/client/components/router-reducer/reducers/restore-reducer.ts @@ -4,6 +4,7 @@ import type { ReducerState, RestoreAction, } from '../router-reducer-types' +import { extractPathFromFlightRouterState } from '../compute-changed-path' export function restoreReducer( state: ReadonlyReducerState, @@ -27,6 +28,6 @@ export function restoreReducer( prefetchCache: state.prefetchCache, // Restore provided tree tree: tree, - nextUrl: url.pathname, + nextUrl: extractPathFromFlightRouterState(tree) ?? url.pathname, } } diff --git a/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/@modal/(.)photos/[id]/page.tsx b/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/@modal/(.)photos/[id]/page.tsx new file mode 100644 index 0000000000000..97e9206db9830 --- /dev/null +++ b/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/@modal/(.)photos/[id]/page.tsx @@ -0,0 +1,7 @@ +export default function PhotoModal({ + params: { id: photoId }, +}: { + params: { id: string } +}) { + return
Intercepted Photo ID: {photoId}
+} diff --git a/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/layout.tsx b/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/layout.tsx index 58431c5495637..521cc03120ad5 100644 --- a/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/layout.tsx +++ b/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/layout.tsx @@ -6,6 +6,10 @@ export default function Layout({ children, modal, params }) {
feed
+
+ Photos: Photo 1{' '} + Photo 2 +
{params.lang}
{children}
diff --git a/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/photos/[id]/page.tsx b/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/photos/[id]/page.tsx new file mode 100644 index 0000000000000..d7f45379cfc72 --- /dev/null +++ b/test/e2e/app-dir/interception-middleware-rewrite/app/[lang]/photos/[id]/page.tsx @@ -0,0 +1,7 @@ +export default function PhotoPage({ + params: { id }, +}: { + params: { id: string } +}) { + return
Page Photo ID: {id}
+} diff --git a/test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts b/test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts index 490d8c34d150e..a92937cc684c1 100644 --- a/test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts +++ b/test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts @@ -31,5 +31,22 @@ createNextDescribe( await check(() => browser.waitForElementByCss('#modal').text(), '') }) + + it('should continue to work after using browser back button and following another intercepting route', async () => { + const browser = await next.browser('/') + await check(() => browser.elementById('children').text(), 'root') + + await browser.elementByCss('[href="/photos/1"]').click() + await check( + () => browser.elementById('modal').text(), + 'Intercepted Photo ID: 1' + ) + await browser.back() + await browser.elementByCss('[href="/photos/2"]').click() + await check( + () => browser.elementById('modal').text(), + 'Intercepted Photo ID: 2' + ) + }) } ) From 956636c86f508bb79cfc10c6a9bc40039de6366c Mon Sep 17 00:00:00 2001 From: Leah Date: Thu, 30 Nov 2023 14:03:44 +0100 Subject: [PATCH 042/189] ci: don't retry or notify on failures from forks (#59118) ### Why? For some reason the retry action can be triggered if there's a PR from the canary branch of a fork. https://github.com/vercel/next.js/actions/runs/7040561852/attempts/3 Closes PACK-2062 --- .github/workflows/retry_test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/retry_test.yml b/.github/workflows/retry_test.yml index a766f56b02ecc..478e2d1ddc282 100644 --- a/.github/workflows/retry_test.yml +++ b/.github/workflows/retry_test.yml @@ -16,7 +16,7 @@ permissions: jobs: retry-on-failure: name: retry failed jobs - if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.run_attempt < 3 }} + if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.run_attempt < 3 && github.repository == 'vercel/next.js' }} runs-on: ubuntu-latest steps: - name: send retry request to GitHub API @@ -31,7 +31,7 @@ jobs: report-failure: name: report failure to slack - if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.run_attempt >= 3 }} + if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.run_attempt >= 3 && github.repository == 'vercel/next.js' }} runs-on: ubuntu-latest steps: - name: send webhook From d37b5076297e39e11b81e9154ccb8fef3dafa56c Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 30 Nov 2023 16:36:14 +0100 Subject: [PATCH 043/189] Fix next internal is missing in flight manifest (#59085) --- .../build/webpack/loaders/next-app-loader.ts | 17 ++++++----- .../plugins/flight-client-entry-plugin.ts | 6 ++-- .../next/src/server/app-render/entry-base.ts | 6 ++-- .../catch-all/app/[lang]/[...slug]/page.js | 6 ++++ .../catch-all/app/[lang]/global-error.js | 11 +++++++ .../catch-all/app/[lang]/layout.js | 9 ++++++ .../global-error/catch-all/index.test.ts | 29 +++++++++++++++++++ test/e2e/app-dir/global-error/next.config.js | 1 - 8 files changed, 71 insertions(+), 14 deletions(-) create mode 100644 test/e2e/app-dir/global-error/catch-all/app/[lang]/[...slug]/page.js create mode 100644 test/e2e/app-dir/global-error/catch-all/app/[lang]/global-error.js create mode 100644 test/e2e/app-dir/global-error/catch-all/app/[lang]/layout.js create mode 100644 test/e2e/app-dir/global-error/catch-all/index.test.ts delete mode 100644 test/e2e/app-dir/global-error/next.config.js diff --git a/packages/next/src/build/webpack/loaders/next-app-loader.ts b/packages/next/src/build/webpack/loaders/next-app-loader.ts index 8731b5177096f..4f6fbc609bf27 100644 --- a/packages/next/src/build/webpack/loaders/next-app-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-app-loader.ts @@ -56,6 +56,8 @@ const PAGE_SEGMENT = 'page$' const PARALLEL_CHILDREN_SEGMENT = 'children$' const defaultNotFoundPath = 'next/dist/client/components/not-found-error' +const defaultGlobalErrorPath = 'next/dist/client/components/error-boundary' +const defaultLayoutPath = 'next/dist/client/components/default-layout' type DirResolver = (pathToResolve: string) => string type PathResolver = ( @@ -176,7 +178,7 @@ async function createTreeCodeFromPath( treeCode: string pages: string rootLayout: string | undefined - globalError: string | undefined + globalError: string }> { const splittedPath = pagePath.split(/[\\/]/, 1) const isNotFoundRoute = page === '/_not-found' @@ -188,7 +190,7 @@ async function createTreeCodeFromPath( const pages: string[] = [] let rootLayout: string | undefined - let globalError: string | undefined + let globalError: string = defaultGlobalErrorPath async function resolveAdjacentParallelSegments( segmentPath: string @@ -345,14 +347,17 @@ async function createTreeCodeFromPath( rootLayout = layoutPath if (isDefaultNotFound && !layoutPath) { - rootLayout = 'next/dist/client/components/default-layout' + rootLayout = defaultLayoutPath definedFilePaths.push(['layout', rootLayout]) } if (layoutPath) { - globalError = await resolver( + const resolvedGlobalErrorPath = await resolver( `${path.dirname(layoutPath)}/${GLOBAL_ERROR_FILE_TYPE}` ) + if (resolvedGlobalErrorPath) { + globalError = resolvedGlobalErrorPath + } } } @@ -698,9 +703,7 @@ const nextAppLoader: AppLoader = async function nextAppLoader() { { VAR_DEFINITION_PAGE: page, VAR_DEFINITION_PATHNAME: pathname, - VAR_MODULE_GLOBAL_ERROR: treeCodeResult.globalError - ? treeCodeResult.globalError - : 'next/dist/client/components/error-boundary', + VAR_MODULE_GLOBAL_ERROR: treeCodeResult.globalError, VAR_ORIGINAL_PATHNAME: page, }, { diff --git a/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts b/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts index 69a2700cd71a0..b9014ad967395 100644 --- a/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts +++ b/packages/next/src/build/webpack/plugins/flight-client-entry-plugin.ts @@ -393,14 +393,14 @@ export class FlightClientEntryPlugin { // We need to create extra action entries that are created from the // client layer. // Start from each entry's created SSR dependency from our previous step. - for (const [name, ssrEntryDepdendencies] of Object.entries( + for (const [name, ssrEntryDependencies] of Object.entries( createdSSRDependenciesForEntry )) { // Collect from all entries, e.g. layout.js, page.js, loading.js, ... - // add agregate them. + // add aggregate them. const actionEntryImports = this.collectClientActionsFromDependencies({ compilation, - dependencies: ssrEntryDepdendencies, + dependencies: ssrEntryDependencies, }) if (actionEntryImports.size > 0) { diff --git a/packages/next/src/server/app-render/entry-base.ts b/packages/next/src/server/app-render/entry-base.ts index 920c02b635b37..ebd618faa7eb0 100644 --- a/packages/next/src/server/app-render/entry-base.ts +++ b/packages/next/src/server/app-render/entry-base.ts @@ -16,7 +16,10 @@ import { staticGenerationBailout } from '../../client/components/static-generati 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 { NotFoundBoundary } from '../../client/components/not-found-boundary' import { patchFetch as _patchFetch } from '../lib/patch-fetch' +// not being used but needs to be included in the client manifest for /_not-found +import '../../client/components/error-boundary' import { preloadStyle, @@ -26,9 +29,6 @@ import { import { taintObjectReference } from '../../server/app-render/rsc/taint' -const { NotFoundBoundary } = - require('next/dist/client/components/not-found-boundary') as typeof import('../../client/components/not-found-boundary') - // patchFetch makes use of APIs such as `React.unstable_postpone` which are only available // in the experimental channel of React, so export it from here so that it comes from the bundled runtime function patchFetch() { diff --git a/test/e2e/app-dir/global-error/catch-all/app/[lang]/[...slug]/page.js b/test/e2e/app-dir/global-error/catch-all/app/[lang]/[...slug]/page.js new file mode 100644 index 0000000000000..8ed52fb421dab --- /dev/null +++ b/test/e2e/app-dir/global-error/catch-all/app/[lang]/[...slug]/page.js @@ -0,0 +1,6 @@ +export default async function Page({ params }) { + if (params.slug[0] === 'error') { + throw new Error('trigger error') + } + return 'catch-all page' +} diff --git a/test/e2e/app-dir/global-error/catch-all/app/[lang]/global-error.js b/test/e2e/app-dir/global-error/catch-all/app/[lang]/global-error.js new file mode 100644 index 0000000000000..48af4bf693b0a --- /dev/null +++ b/test/e2e/app-dir/global-error/catch-all/app/[lang]/global-error.js @@ -0,0 +1,11 @@ +'use client' + +export default function GlobalError() { + return ( + + +
global-error
+ + + ) +} diff --git a/test/e2e/app-dir/global-error/catch-all/app/[lang]/layout.js b/test/e2e/app-dir/global-error/catch-all/app/[lang]/layout.js new file mode 100644 index 0000000000000..4328f6b8b8aa2 --- /dev/null +++ b/test/e2e/app-dir/global-error/catch-all/app/[lang]/layout.js @@ -0,0 +1,9 @@ +export default async function RootLayout({ children }) { + return ( + + {children} + + ) +} + +export const dynamic = 'force-dynamic' diff --git a/test/e2e/app-dir/global-error/catch-all/index.test.ts b/test/e2e/app-dir/global-error/catch-all/index.test.ts new file mode 100644 index 0000000000000..e2a3bae8f8087 --- /dev/null +++ b/test/e2e/app-dir/global-error/catch-all/index.test.ts @@ -0,0 +1,29 @@ +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'app dir - global error - with catch-all route', + { + files: __dirname, + skipDeployment: true, + }, + ({ next, isNextStart }) => { + it('should render catch-all route correctly', async () => { + expect(await next.render('/en/foo')).toContain('catch-all page') + }) + + it('should render 404 page correctly', async () => { + expect(await next.render('/en')).toContain( + 'This page could not be found.' + ) + }) + + if (isNextStart) { + it('should render global error correctly', async () => { + const browser = await next.browser('/en/error') + + const text = await browser.elementByCss('#global-error').text() + expect(text).toBe('global-error') + }) + } + } +) diff --git a/test/e2e/app-dir/global-error/next.config.js b/test/e2e/app-dir/global-error/next.config.js deleted file mode 100644 index 4ba52ba2c8df6..0000000000000 --- a/test/e2e/app-dir/global-error/next.config.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = {} From 778fb871314e840390496f4147483ba18d974d83 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 30 Nov 2023 16:44:49 +0100 Subject: [PATCH 044/189] Support generating multi-meta tahs for metadata api other prop (#59106) --- .../04-functions/generate-metadata.mdx | 14 ++++++++++++++ .../next/src/lib/metadata/generate/alternate.tsx | 2 +- packages/next/src/lib/metadata/generate/basic.tsx | 15 +++++++++------ test/e2e/app-dir/metadata/metadata.test.ts | 1 + 4 files changed, 25 insertions(+), 7 deletions(-) diff --git a/docs/02-app/02-api-reference/04-functions/generate-metadata.mdx b/docs/02-app/02-api-reference/04-functions/generate-metadata.mdx index 00d5aab0e7dc0..4ec8b18f2bbaa 100644 --- a/docs/02-app/02-api-reference/04-functions/generate-metadata.mdx +++ b/docs/02-app/02-api-reference/04-functions/generate-metadata.mdx @@ -930,6 +930,20 @@ export const metadata = { ``` +If you want to generate multiple same key meta tags you can use array value. + +```jsx filename="layout.js | page.js" +export const metadata = { + other: { + custom: ['meta1', 'meta2'], + }, +} +``` + +```html filename=" output" hideLineNumbers + +``` + ## Unsupported Metadata The following metadata types do not currently have built-in support. However, they can still be rendered in the layout or page itself. diff --git a/packages/next/src/lib/metadata/generate/alternate.tsx b/packages/next/src/lib/metadata/generate/alternate.tsx index 8ccc816ba509d..cb4377b591036 100644 --- a/packages/next/src/lib/metadata/generate/alternate.tsx +++ b/packages/next/src/lib/metadata/generate/alternate.tsx @@ -1,7 +1,7 @@ import type { ResolvedMetadata } from '../types/metadata-interface' +import type { AlternateLinkDescriptor } from '../types/alternative-urls-types' import React from 'react' -import type { AlternateLinkDescriptor } from '../types/alternative-urls-types' import { MetaFilter } from './meta' function AlternateLink({ diff --git a/packages/next/src/lib/metadata/generate/basic.tsx b/packages/next/src/lib/metadata/generate/basic.tsx index 78c3df8e00676..5f52cd3d84562 100644 --- a/packages/next/src/lib/metadata/generate/basic.tsx +++ b/packages/next/src/lib/metadata/generate/basic.tsx @@ -87,12 +87,15 @@ export function BasicMeta({ metadata }: { metadata: ResolvedMetadata }) { Meta({ name: 'category', content: metadata.category }), Meta({ name: 'classification', content: metadata.classification }), ...(metadata.other - ? Object.entries(metadata.other).map(([name, content]) => - Meta({ - name, - content: Array.isArray(content) ? content.join(',') : content, - }) - ) + ? Object.entries(metadata.other).map(([name, content]) => { + if (Array.isArray(content)) { + return content.map((contentItem) => + Meta({ name, content: contentItem }) + ) + } else { + return Meta({ name, content }) + } + }) : []), ]) } diff --git a/test/e2e/app-dir/metadata/metadata.test.ts b/test/e2e/app-dir/metadata/metadata.test.ts index 6f8ef4ddbe239..d489e4f0833bc 100644 --- a/test/e2e/app-dir/metadata/metadata.test.ts +++ b/test/e2e/app-dir/metadata/metadata.test.ts @@ -359,6 +359,7 @@ createNextDescribe( 'yandex-verification': 'yandex', me: ['my-email', 'my-link'], }) + expect($('meta[name="me"]').length).toBe(2) }) it('should support appLinks tags', async () => { From 156f7860e2fa69e7f20aaf45c7cc1d542c5a50b6 Mon Sep 17 00:00:00 2001 From: Will Binns-Smith Date: Thu, 30 Nov 2023 08:34:56 -0800 Subject: [PATCH 045/189] Turbopack: Align some "Module not found" errors with webpack (#58518) This: - Sends an hmr sync event so that errors that occur after the initial hmr connection are sent to the client - Aligns on `path/to/file.js:line:column` format across error overlay implementations in the cli and on the web - Adapts "Module not found" errors from Turbopack to include Next.js-relevant formatting and documentation links to align with webpack Test Plan: Passes 3 tests that were previously failing Closes PACK-1974 --------- Co-authored-by: Tobias Koppers Co-authored-by: Leah Co-authored-by: Zack Tanner --- .../components/Terminal/EditorLink.tsx | 2 +- .../next/src/server/dev/hot-reloader-types.ts | 2 +- .../lib/router-utils/setup-dev-bundler.ts | 175 ++++++++++-------- test/build-turbopack-tests-manifest.js | 3 - .../ReactRefreshLogBox-builtins.test.ts | 79 +++++--- .../acceptance-app/ReactRefreshLogBox.test.ts | 2 +- .../ReactRefreshLogBox-scss.test.ts.snap | 2 +- .../ReactRefreshLogBox.test.ts.snap | 4 +- .../ReactRefreshLogBox-builtins.test.ts | 34 +++- test/turbopack-tests-manifest.json | 49 ++--- 10 files changed, 206 insertions(+), 146 deletions(-) diff --git a/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/EditorLink.tsx b/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/EditorLink.tsx index f397001c8c460..518c29e4c7023 100644 --- a/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/EditorLink.tsx +++ b/packages/next/src/client/components/react-dev-overlay/internal/components/Terminal/EditorLink.tsx @@ -31,7 +31,7 @@ export function EditorLink({ file, isSourceFile, location }: EditorLinkProps) { title={'Click to open in your editor'} > {file} - {location ? ` (${location.line}:${location.column})` : null} + {location ? `:${location.line}:${location.column}` : null} diff --git a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts index 59d561927cee2..713b47ff9d8e0 100644 --- a/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts +++ b/packages/next/src/server/lib/router-utils/setup-dev-bundler.ts @@ -23,6 +23,7 @@ import type { HMR_ACTION_TYPES, NextJsHotReloaderInterface, ReloadPageAction, + SyncAction, TurbopackConnectedAction, } from '../../dev/hot-reloader-types' @@ -166,6 +167,8 @@ async function verifyTypeScript(opts: SetupOpts) { return usingTypeScript } +class ModuleBuildError extends Error {} + async function startWatcher(opts: SetupOpts) { const { nextConfig, appDir, pagesDir, dir } = opts const { useFileSystemPublicRoutes } = nextConfig @@ -285,20 +288,29 @@ async function startWatcher(opts: SetupOpts) { return [ issue.severity, issue.filePath, - issue.title, + JSON.stringify(issue.title), JSON.stringify(issue.description), ].join('-') } function formatIssue(issue: Issue) { - const { filePath, title, description, source, detail } = issue + const { filePath, title, description, source } = issue + let { documentationLink } = issue let formattedTitle = renderStyledStringToErrorAnsi(title).replace( /\n/g, '\n ' ) + // TODO: Use error codes to identify these + // TODO: Generalize adapting Turbopack errors to Next.js errors + if (formattedTitle.includes('Module not found')) { + // For compatiblity with webpack + // TODO: include columns in webpack errors. + documentationLink = 'https://nextjs.org/docs/messages/module-not-found' + } + let formattedFilePath = filePath - .replace('[project]/', '') + .replace('[project]/', './') .replaceAll('/./', '/') .replace('\\\\?\\', '') @@ -307,17 +319,18 @@ async function startWatcher(opts: SetupOpts) { if (source) { if (source.range) { const { start } = source.range - message = `${issue.severity} - ${formattedFilePath}:${ - start.line + 1 - }:${start.column} ${formattedTitle}` + message = `${formattedFilePath}:${start.line + 1}:${ + start.column + }\n${formattedTitle}` } else { - message = `${issue.severity} - ${formattedFilePath} ${formattedTitle}` + message = formattedFilePath } } else if (formattedFilePath) { - message = `${formattedFilePath} ${formattedTitle}` + message = `${formattedFilePath}\n${formattedTitle}` } else { message = formattedTitle } + message += '\n' if (source?.range && source.source.content) { const { start, end } = source.range @@ -326,70 +339,56 @@ async function startWatcher(opts: SetupOpts) { } = require('next/dist/compiled/babel/code-frame') message += - '\n\n' + codeFrameColumns( source.source.content, { - start: { line: start.line + 1, column: start.column + 1 }, - end: { line: end.line + 1, column: end.column + 1 }, + start: { + line: start.line + 1, + column: start.column + 1, + }, + end: { + line: end.line + 1, + column: end.column + 1, + }, }, { forceColor: true } - ) + ).trim() + '\n\n' } if (description) { - message += `\n${renderStyledStringToErrorAnsi(description).replace( - /\n/g, - '\n ' - )}` + message += renderStyledStringToErrorAnsi(description) + '\n\n' } - if (detail) { - message += `\n${renderStyledStringToErrorAnsi(detail).replace( - /\n/g, - '\n ' - )}` + // TODO: Include a trace from the issue. + + if (documentationLink) { + message += documentationLink + '\n\n' } return message } - class ModuleBuildError extends Error {} - function processIssues( - displayName: string, name: string, result: TurbopackResult, throwIssue = false ) { - const oldSet = issues.get(name) ?? new Map() - const newSet = new Map() - issues.set(name, newSet) + const newIssues = new Map() + issues.set(name, newIssues) const relevantIssues = new Set() for (const issue of result.issues) { - // TODO better formatting if (issue.severity !== 'error' && issue.severity !== 'fatal') continue const key = issueKey(issue) const formatted = formatIssue(issue) - if (!oldSet.has(key) && !newSet.has(key)) { - console.error(` ⚠ ${displayName} ${formatted}\n\n`) - } - newSet.set(key, issue) + newIssues.set(key, issue) // We show errors in node_modules to the console, but don't throw for them if (/(^|\/)node_modules(\/|$)/.test(issue.filePath)) continue relevantIssues.add(formatted) } - // TODO: Format these messages correctly. - // for (const issue of oldSet.keys()) { - // if (!newSet.has(issue)) { - // console.error(`✅ ${displayName} fixed ${issue}`) - // } - // } - if (relevantIssues.size && throwIssue) { throw new ModuleBuildError([...relevantIssues].join('\n\n')) } @@ -702,7 +701,7 @@ async function startWatcher(opts: SetupOpts) { const changed = await changedPromise for await (const change of changed) { - processIssues(key, page, change) + processIssues(page, change) const payload = await makePayload(page, change) if (payload) sendHmr('endpoint-change', key, payload) } @@ -1045,7 +1044,7 @@ async function startWatcher(opts: SetupOpts) { await subscription.next() for await (const data of subscription) { - processIssues('hmr', id, data) + processIssues(id, data) sendTurbopackMessage(data) } } catch (e) { @@ -1137,7 +1136,7 @@ async function startWatcher(opts: SetupOpts) { displayName, await instrumentation[prop].writeToDisk() ) - processIssues(displayName, name, writtenEndpoint) + processIssues(name, writtenEndpoint) } await processInstrumentation( 'instrumentation (node.js)', @@ -1170,7 +1169,7 @@ async function startWatcher(opts: SetupOpts) { 'middleware', await middleware.endpoint.writeToDisk() ) - processIssues('middleware', 'middleware', writtenEndpoint) + processIssues('middleware', writtenEndpoint) await loadMiddlewareManifest('middleware', 'middleware') serverFields.actualMiddlewareFile = 'middleware' serverFields.middleware = { @@ -1367,6 +1366,28 @@ async function startWatcher(opts: SetupOpts) { type: HMR_ACTIONS_SENT_TO_BROWSER.TURBOPACK_CONNECTED, } client.send(JSON.stringify(turbopackConnected)) + + const errors = [] + for (const pageIssues of issues.values()) { + for (const issue of pageIssues.values()) { + errors.push({ + message: formatIssue(issue), + }) + } + } + + const sync: SyncAction = { + action: HMR_ACTIONS_SENT_TO_BROWSER.SYNC, + errors, + warnings: [], + hash: '', + versionInfo: { + installed: '0.0.0', + staleness: 'unknown', + }, + } + + this.send(sync) }) }, @@ -1389,8 +1410,23 @@ async function startWatcher(opts: SetupOpts) { async stop() { // Not implemented yet. }, - async getCompilationErrors(_page) { - return [] + async getCompilationErrors(page) { + const thisPageIssues = issues.get(page) + if (thisPageIssues !== undefined && thisPageIssues.size > 0) { + // If there is an error related to the requesting page we display it instead of the first error + return [...thisPageIssues.values()].map( + (issue) => new Error(formatIssue(issue)) + ) + } + + // Otherwise, return all errors across pages + const errors = [] + for (const pageIssues of issues.values()) { + for (const issue of pageIssues.values()) { + errors.push(new Error(formatIssue(issue))) + } + } + return errors }, invalidate(/* Unused parameter: { reloadAfterInvalidation } */) { // Not implemented yet. @@ -1417,7 +1453,7 @@ async function startWatcher(opts: SetupOpts) { '_app', await globalEntries.app.writeToDisk() ) - processIssues('_app', '_app', writtenEndpoint) + processIssues('_app', writtenEndpoint) } await loadBuildManifest('_app') await loadPagesManifest('_app') @@ -1436,7 +1472,7 @@ async function startWatcher(opts: SetupOpts) { return { action: HMR_ACTIONS_SENT_TO_BROWSER.RELOAD_PAGE } } ) - processIssues('_document', '_document', writtenEndpoint) + processIssues('_document', writtenEndpoint) } await loadPagesManifest('_document') @@ -1445,7 +1481,7 @@ async function startWatcher(opts: SetupOpts) { '_error', await globalEntries.error.writeToDisk() ) - processIssues(page, page, writtenEndpoint) + processIssues(page, writtenEndpoint) } await loadBuildManifest('_error') await loadPagesManifest('_error') @@ -1481,25 +1517,6 @@ async function startWatcher(opts: SetupOpts) { throw new PageNotFoundError(`route not found ${page}`) } - let suffix - switch (route.type) { - case 'app-page': - suffix = 'page' - break - case 'app-route': - suffix = 'route' - break - case 'page': - case 'page-api': - suffix = '' - break - default: - throw new Error('Unexpected route type ' + route.type) - } - - const buildingKey = `${page}${ - !page.endsWith('/') && suffix.length > 0 ? '/' : '' - }${suffix}` let finishBuilding: (() => void) | undefined = undefined try { @@ -1511,14 +1528,14 @@ async function startWatcher(opts: SetupOpts) { ) } - finishBuilding = startBuilding(buildingKey, requestUrl) + finishBuilding = startBuilding(page, requestUrl) try { if (globalEntries.app) { const writtenEndpoint = await processResult( '_app', await globalEntries.app.writeToDisk() ) - processIssues('_app', '_app', writtenEndpoint) + processIssues('_app', writtenEndpoint) } await loadBuildManifest('_app') await loadPagesManifest('_app') @@ -1538,7 +1555,7 @@ async function startWatcher(opts: SetupOpts) { return { action: HMR_ACTIONS_SENT_TO_BROWSER.RELOAD_PAGE } } ) - processIssues('_document', '_document', writtenEndpoint) + processIssues('_document', writtenEndpoint) } await loadPagesManifest('_document') @@ -1564,7 +1581,7 @@ async function startWatcher(opts: SetupOpts) { await writeMiddlewareManifest() await writeLoadableManifest() - processIssues(page, page, writtenEndpoint) + processIssues(page, writtenEndpoint) } finally { changeSubscription( page, @@ -1599,7 +1616,7 @@ async function startWatcher(opts: SetupOpts) { // since this can happen when app pages make // api requests to page API routes. - finishBuilding = startBuilding(buildingKey, requestUrl) + finishBuilding = startBuilding(page, requestUrl) const writtenEndpoint = await processResult( page, await route.endpoint.writeToDisk() @@ -1619,12 +1636,12 @@ async function startWatcher(opts: SetupOpts) { await writeMiddlewareManifest() await writeLoadableManifest() - processIssues(page, page, writtenEndpoint) + processIssues(page, writtenEndpoint) break } case 'app-page': { - finishBuilding = startBuilding(buildingKey, requestUrl) + finishBuilding = startBuilding(page, requestUrl) const writtenEndpoint = await processResult( page, await route.htmlEndpoint.writeToDisk() @@ -1670,12 +1687,12 @@ async function startWatcher(opts: SetupOpts) { await writeActionManifest() await writeLoadableManifest() - processIssues(page, page, writtenEndpoint, true) + processIssues(page, writtenEndpoint, true) break } case 'app-route': { - finishBuilding = startBuilding(buildingKey, requestUrl) + finishBuilding = startBuilding(page, requestUrl) const writtenEndpoint = await processResult( page, await route.endpoint.writeToDisk() @@ -1696,7 +1713,7 @@ async function startWatcher(opts: SetupOpts) { await writeMiddlewareManifest() await writeLoadableManifest() - processIssues(page, page, writtenEndpoint, true) + processIssues(page, writtenEndpoint, true) break } @@ -2520,7 +2537,9 @@ async function startWatcher(opts: SetupOpts) { } if (!usedOriginalStack) { - if (type === 'warning') { + if (err instanceof ModuleBuildError) { + Log.error(err.message) + } else if (type === 'warning') { Log.warn(err) } else if (type === 'app-dir') { logAppDirError(err) diff --git a/test/build-turbopack-tests-manifest.js b/test/build-turbopack-tests-manifest.js index fbbc4b5d24b35..1230c4f8d4a2d 100644 --- a/test/build-turbopack-tests-manifest.js +++ b/test/build-turbopack-tests-manifest.js @@ -23,9 +23,6 @@ const INITIALIZING_TEST_CASES = [ // please make sure this is sorted alphabetically when making changes. const SKIPPED_TEST_SUITES = { - 'test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts': [ - 'ReactRefreshLogBox app turbo Module not found missing global CSS', - ], 'test/development/acceptance-app/ReactRefreshRegression.test.ts': [ 'ReactRefreshRegression app can fast refresh a page with dynamic rendering', 'ReactRefreshRegression app can fast refresh a page with config', diff --git a/test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts b/test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts index f021abbbfd4be..36278161698db 100644 --- a/test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts +++ b/test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts @@ -51,7 +51,7 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { ) expect(await session.hasRedbox(true)).toBe(true) expect(await session.getRedboxSource()).toMatchInlineSnapshot(` - "./node_modules/my-package/index.js (1:0) + "./node_modules/my-package/index.js:1:0 Module not found: Can't resolve 'dns' https://nextjs.org/docs/messages/module-not-found @@ -85,7 +85,7 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { const source = await session.getRedboxSource() expect(source).toMatchInlineSnapshot(` - "./index.js (1:0) + "./index.js:1:0 Module not found: Can't resolve 'b' > 1 | import Comp from 'b' 2 | export default function Oops() { @@ -122,17 +122,32 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { expect(await session.hasRedbox(true)).toBe(true) const source = await session.getRedboxSource() - expect(source).toMatchInlineSnapshot(` - "./app/page.js (2:0) - Module not found: Can't resolve 'b' - 1 | 'use client' - > 2 | import Comp from 'b' - 3 | export default function Oops() { - 4 | return ( - 5 |
- - https://nextjs.org/docs/messages/module-not-found" - `) + if (process.env.TURBOPACK) { + expect(source).toMatchInlineSnapshot(` + "./app/page.js:2:0 + Module not found: Can't resolve 'b' + 1 | 'use client' + > 2 | import Comp from 'b' + | ^^^^^^^^^^^^^^^^^^^^ + 3 | export default function Oops() { + 4 | return ( + 5 |
+ + https://nextjs.org/docs/messages/module-not-found" + `) + } else { + expect(source).toMatchInlineSnapshot(` + "./app/page.js:2:0 + Module not found: Can't resolve 'b' + 1 | 'use client' + > 2 | import Comp from 'b' + 3 | export default function Oops() { + 4 | return ( + 5 |
+ + https://nextjs.org/docs/messages/module-not-found" + `) + } await cleanup() }) @@ -156,18 +171,32 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { expect(await session.hasRedbox(true)).toBe(true) const source = await session.getRedboxSource() - expect(source).toMatchInlineSnapshot(` - "./app/page.js:2:0 - Module not found: Can't resolve './non-existent.css' - 1 | 'use client' - > 2 | import './non-existent.css' - 3 | export default function Page(props) { - 4 | return

index page

- 5 | } - - https://nextjs.org/docs/messages/module-not-found" - `) - + if (process.env.TURBOPACK) { + expect(source).toMatchInlineSnapshot(` + "./app/page.js:2:0 + Module not found: Can't resolve './non-existent.css' + 1 | 'use client' + > 2 | import './non-existent.css' + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + 3 | export default function Page(props) { + 4 | return

index page

+ 5 | } + + https://nextjs.org/docs/messages/module-not-found" + `) + } else { + expect(source).toMatchInlineSnapshot(` + "./app/page.js:2:0 + Module not found: Can't resolve './non-existent.css' + 1 | 'use client' + > 2 | import './non-existent.css' + 3 | export default function Page(props) { + 4 | return

index page

+ 5 | } + + https://nextjs.org/docs/messages/module-not-found" + `) + } await session.patch( 'app/page.js', outdent` diff --git a/test/development/acceptance-app/ReactRefreshLogBox.test.ts b/test/development/acceptance-app/ReactRefreshLogBox.test.ts index bd75f6f16c923..ee98f29cc5e5b 100644 --- a/test/development/acceptance-app/ReactRefreshLogBox.test.ts +++ b/test/development/acceptance-app/ReactRefreshLogBox.test.ts @@ -344,7 +344,7 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox app %s', () => { await session.patch('index.module.css', `.button {`) expect(await session.hasRedbox(true)).toBe(true) const source = await session.getRedboxSource() - expect(source).toMatch('./index.module.css (1:1)') + expect(source).toMatch('./index.module.css:1:1') expect(source).toMatch('Syntax error: ') expect(source).toMatch('Unclosed block') expect(source).toMatch('> 1 | .button {') diff --git a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-scss.test.ts.snap b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-scss.test.ts.snap index 4aabd710b78bc..5e5ca86ac1578 100644 --- a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-scss.test.ts.snap +++ b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox-scss.test.ts.snap @@ -16,7 +16,7 @@ Import trace for requested module: `; exports[`ReactRefreshLogBox app scss syntax errors 2`] = ` -"./index.module.scss (1:1) +"./index.module.scss:1:1 Syntax error: Selector "button" is not pure (pure selectors must contain at least one local class or id) > 1 | button { font-size: 5px; } diff --git a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap index e6abc90aa8daf..64be47456117e 100644 --- a/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap +++ b/test/development/acceptance-app/__snapshots__/ReactRefreshLogBox.test.ts.snap @@ -11,7 +11,7 @@ Import trace for requested module: `; exports[`ReactRefreshLogBox app default Import trace when module not found in layout 1`] = ` -"./app/module.js (1:0) +"./app/module.js:1:0 Module not found: Can't resolve 'non-existing-module' > 1 | import "non-existing-module" @@ -52,7 +52,7 @@ exports[`ReactRefreshLogBox app default conversion to class component (1) 1`] = `; exports[`ReactRefreshLogBox app default css syntax errors 1`] = ` -"./index.module.css (1:1) +"./index.module.css:1:1 Syntax error: Selector "button" is not pure (pure selectors must contain at least one local class or id) > 1 | button {} diff --git a/test/development/acceptance/ReactRefreshLogBox-builtins.test.ts b/test/development/acceptance/ReactRefreshLogBox-builtins.test.ts index 3ae613fdca192..cba0c3fe12f6d 100644 --- a/test/development/acceptance/ReactRefreshLogBox-builtins.test.ts +++ b/test/development/acceptance/ReactRefreshLogBox-builtins.test.ts @@ -118,16 +118,30 @@ describe.each(['default', 'turbo'])('ReactRefreshLogBox %s', () => { expect(await session.hasRedbox(true)).toBe(true) const source = await session.getRedboxSource() - expect(source).toMatchInlineSnapshot(` - "./pages/index.js:1:0 - Module not found: Can't resolve 'b' - > 1 | import Comp from 'b' - 2 | - 3 | export default function Oops() { - 4 | return ( - - https://nextjs.org/docs/messages/module-not-found" - `) + if (process.env.TURBOPACK) { + expect(source).toMatchInlineSnapshot(` + "./pages/index.js:1:0 + Module not found: Can't resolve 'b' + > 1 | import Comp from 'b' + | ^^^^^^^^^^^^^^^^^^^^ + 2 | + 3 | export default function Oops() { + 4 | return ( + + https://nextjs.org/docs/messages/module-not-found" + `) + } else { + expect(source).toMatchInlineSnapshot(` + "./pages/index.js:1:0 + Module not found: Can't resolve 'b' + > 1 | import Comp from 'b' + 2 | + 3 | export default function Oops() { + 4 | return ( + + https://nextjs.org/docs/messages/module-not-found" + `) + } await cleanup() }) diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index b2cdc1c95a857..5a3fa8d053b95 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -875,10 +875,12 @@ "runtimeError": false }, "test/development/acceptance-app/ReactRefreshLogBox-builtins.test.ts": { - "passed": [], + "passed": [ + "ReactRefreshLogBox app turbo Module not found empty import trace", + "ReactRefreshLogBox app turbo Module not found missing global CSS" + ], "failed": [ "ReactRefreshLogBox app turbo Module not found", - "ReactRefreshLogBox app turbo Module not found empty import trace", "ReactRefreshLogBox app turbo Node.js builtins" ], "pending": [ @@ -887,9 +889,7 @@ "ReactRefreshLogBox app default Module not found missing global CSS", "ReactRefreshLogBox app default Node.js builtins" ], - "flakey": [ - "ReactRefreshLogBox app turbo Module not found missing global CSS" - ], + "flakey": [], "runtimeError": false }, "test/development/acceptance-app/ReactRefreshLogBox-scss.test.ts": { @@ -1211,10 +1211,11 @@ "runtimeError": false }, "test/development/acceptance/ReactRefreshLogBox-builtins.test.ts": { - "passed": [], + "passed": [ + "ReactRefreshLogBox turbo Module not found (empty import trace)" + ], "failed": [ "ReactRefreshLogBox turbo Module not found", - "ReactRefreshLogBox turbo Module not found (empty import trace)", "ReactRefreshLogBox turbo Module not found (missing global CSS)", "ReactRefreshLogBox turbo Node.js builtins" ], @@ -2074,15 +2075,15 @@ "test/development/tsconfig-path-reloading/index.test.ts": { "passed": [ "tsconfig-path-reloading tsconfig added after starting dev should load with initial paths config correctly", - "tsconfig-path-reloading tsconfig added after starting dev should recover from module not found when paths is updated", - "tsconfig-path-reloading tsconfig should load with initial paths config correctly", - "tsconfig-path-reloading tsconfig should recover from module not found when paths is updated" + "tsconfig-path-reloading tsconfig should load with initial paths config correctly" ], "failed": [], "pending": [], "flakey": [ "tsconfig-path-reloading tsconfig added after starting dev should automatically fast refresh content when path is added without error", - "tsconfig-path-reloading tsconfig should automatically fast refresh content when path is added without error" + "tsconfig-path-reloading tsconfig added after starting dev should recover from module not found when paths is updated", + "tsconfig-path-reloading tsconfig should automatically fast refresh content when path is added without error", + "tsconfig-path-reloading tsconfig should recover from module not found when paths is updated" ], "runtimeError": false }, @@ -5252,24 +5253,12 @@ }, "test/e2e/next-font/index.test.ts": { "passed": [ - "next/font app Fallback fontfaces google Fraunces", - "next/font app Fallback fontfaces local Fraunces", - "next/font app Fallback fontfaces local Indie flower", - "next/font app Fallback fontfaces local Roboto multiple weights and styles", - "next/font app Fallback fontfaces local Roboto multiple weights and styles - variable 1", - "next/font app Fallback fontfaces local Roboto multiple weights and styles - variable 2", "next/font app computed styles page using fallback fonts", "next/font app computed styles page using variables", "next/font app computed styles page with fonts", "next/font app import values Variable font without weight range", "next/font app import values page with font", "next/font app import values page with local fonts", - "next/font app-old Fallback fontfaces google Fraunces", - "next/font app-old Fallback fontfaces local Fraunces", - "next/font app-old Fallback fontfaces local Indie flower", - "next/font app-old Fallback fontfaces local Roboto multiple weights and styles", - "next/font app-old Fallback fontfaces local Roboto multiple weights and styles - variable 1", - "next/font app-old Fallback fontfaces local Roboto multiple weights and styles - variable 2", "next/font app-old computed styles page using fallback fonts", "next/font app-old computed styles page using variables", "next/font app-old computed styles page with fonts", @@ -5278,14 +5267,26 @@ "next/font app-old import values page with local fonts" ], "failed": [ + "next/font app Fallback fontfaces google Fraunces", "next/font app Fallback fontfaces google Indie flower", + "next/font app Fallback fontfaces local Fraunces", + "next/font app Fallback fontfaces local Indie flower", + "next/font app Fallback fontfaces local Roboto multiple weights and styles", + "next/font app Fallback fontfaces local Roboto multiple weights and styles - variable 1", + "next/font app Fallback fontfaces local Roboto multiple weights and styles - variable 2", "next/font app preload font without preloadable subsets", "next/font app preload font without size adjust", "next/font app preload google fonts with multiple weights/styles", "next/font app preload page with fonts", "next/font app preload page with local fonts", "next/font app preload page without fonts", + "next/font app-old Fallback fontfaces google Fraunces", "next/font app-old Fallback fontfaces google Indie flower", + "next/font app-old Fallback fontfaces local Fraunces", + "next/font app-old Fallback fontfaces local Indie flower", + "next/font app-old Fallback fontfaces local Roboto multiple weights and styles", + "next/font app-old Fallback fontfaces local Roboto multiple weights and styles - variable 1", + "next/font app-old Fallback fontfaces local Roboto multiple weights and styles - variable 2", "next/font app-old preload font without preloadable subsets", "next/font app-old preload font without size adjust", "next/font app-old preload google fonts with multiple weights/styles", @@ -7186,7 +7187,6 @@ }, "test/integration/css/test/css-modules.test.js": { "passed": [ - "CSS Modules Composes Ordering Development Mode should have correct color on index page (on load)", "Ordering with Global CSS and Modules (dev) should not execute scripts in any order" ], "failed": [ @@ -7194,6 +7194,7 @@ "Basic CSS Modules Ordering Development Mode should have correct color on index page (on load)", "Basic CSS Modules Ordering Development Mode should have correct color on index page (on nav)", "CSS Modules Composes Ordering Development Mode should have correct color on index page (on hover)", + "CSS Modules Composes Ordering Development Mode should have correct color on index page (on load)", "Ordering with Global CSS and Modules (dev) should have the correct color (css ordering)", "Ordering with Global CSS and Modules (dev) should have the correct color (css ordering) during hot reloads" ], From d5bc1f7f90f2cb2ad31d5c3ddaeaddf52ff466d1 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Thu, 30 Nov 2023 14:41:55 -0800 Subject: [PATCH 046/189] Fix dynamic usage errors logging unexpectedly (#59133) This ensures we don't spam build logs with dynamic usage errors or similar unexpectedly as they can be caught by this worker process listener but shouldn't be logged. Closes NEXT-1763 --- packages/next/src/export/worker.ts | 11 +++++++++-- .../src/server/app-render/create-error-handler.tsx | 13 ++----------- packages/next/taskfile.js | 10 ++++++++++ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/packages/next/src/export/worker.ts b/packages/next/src/export/worker.ts index 2ab330d52c8e4..a3541a4a1e5ce 100644 --- a/packages/next/src/export/worker.ts +++ b/packages/next/src/export/worker.ts @@ -34,6 +34,7 @@ import { getParams } from './helpers/get-params' import { createIncrementalCache } from './helpers/create-incremental-cache' import { isPostpone } from '../server/lib/router-utils/is-postpone' import { isMissingPostponeDataError } from '../server/app-render/is-missing-postpone-error' +import { isDynamicUsageError } from './helpers/is-dynamic-usage-error' const envConfig = require('../shared/lib/runtime-config.external') @@ -376,17 +377,23 @@ export default async function exportPage( } } -process.on('unhandledRejection', (err) => { +process.on('unhandledRejection', (err: unknown) => { // if it's a postpone error, it'll be handled later // when the postponed promise is actually awaited. if (isPostpone(err)) { return } + + // we don't want to log these errors + if (isDynamicUsageError(err)) { + return + } + console.error(err) }) process.on('rejectionHandled', () => { // It is ok to await a Promise late in Next.js as it allows for better - // prefetching patterns to avoid waterfalls. We ignore loggining these. + // prefetching patterns to avoid waterfalls. We ignore logging these. // We should've already errored in anyway unhandledRejection. }) diff --git a/packages/next/src/server/app-render/create-error-handler.tsx b/packages/next/src/server/app-render/create-error-handler.tsx index 636a7049aeebb..356411c06c6bc 100644 --- a/packages/next/src/server/app-render/create-error-handler.tsx +++ b/packages/next/src/server/app-render/create-error-handler.tsx @@ -1,11 +1,8 @@ -import { DYNAMIC_ERROR_CODE } from '../../client/components/hooks-server-context' import stringHash from 'next/dist/compiled/string-hash' import { formatServerError } from '../../lib/format-server-error' -import { isNotFoundError } from '../../client/components/not-found' -import { isRedirectError } from '../../client/components/redirect' -import { NEXT_DYNAMIC_NO_SSR_CODE } from '../../shared/lib/lazy-dynamic/no-ssr-error' import { SpanStatusCode, getTracer } from '../lib/trace/tracer' import { isAbortError } from '../pipe-readable' +import { isDynamicUsageError } from '../../export/helpers/is-dynamic-usage-error' export type ErrorHandler = (err: any) => string | undefined @@ -37,13 +34,7 @@ export function createErrorHandler({ return (err) => { if (allCapturedErrors) allCapturedErrors.push(err) - if ( - err && - (err.digest === DYNAMIC_ERROR_CODE || - isNotFoundError(err) || - err.digest === NEXT_DYNAMIC_NO_SSR_CODE || - isRedirectError(err)) - ) { + if (isDynamicUsageError(err)) { return err.digest } diff --git a/packages/next/taskfile.js b/packages/next/taskfile.js index 62d73669c09b2..5fb652bd4d080 100644 --- a/packages/next/taskfile.js +++ b/packages/next/taskfile.js @@ -2375,6 +2375,7 @@ export async function next_compile(task, opts) { 'nextbuild', 'nextbuildjest', 'nextbuildstatic', + 'nextbuildstatic_esm', 'nextbuild_esm', 'pages', 'pages_esm', @@ -2522,6 +2523,14 @@ export async function nextbuildstatic(task, opts) { .target('dist/export') } +// export is a reserved keyword for functions +export async function nextbuildstatic_esm(task, opts) { + await task + .source('src/export/**/!(*.test).+(js|ts|tsx)') + .swc('server', { dev: opts.dev, esm: true }) + .target('dist/esm/export') +} + export async function pages_app(task, opts) { await task .source('src/pages/_app.tsx') @@ -2641,6 +2650,7 @@ export default async function (task) { opts ) await task.watch('src/export', 'nextbuildstatic', opts) + await task.watch('src/export', 'nextbuildstatic_esm', opts) await task.watch('src/client', 'client', opts) await task.watch('src/client', 'client_esm', opts) await task.watch('src/lib', 'lib', opts) From c5834ab48db1f351b35422f5cc3664d21c7824c2 Mon Sep 17 00:00:00 2001 From: Meril Date: Thu, 30 Nov 2023 22:52:44 +0000 Subject: [PATCH 047/189] Fix: remove deprecated option from standalone server (#59036) Remove deprecated option passed to nextjs server when running in standalone mode. Co-authored-by: JJ Kasper --- packages/next/src/build/utils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index 3dfce139d23cb..643ca58b94036 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -2029,7 +2029,6 @@ startServer({ port: currentPort, allowRetry: false, keepAliveTimeout, - useWorkers: true, }).catch((err) => { console.error(err); process.exit(1); From 73d4ca577516602eb5492a5264b412d806bed06d Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 30 Nov 2023 22:56:34 +0000 Subject: [PATCH 048/189] v14.0.4-canary.29 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 8273886632ca5..a3bd105416226 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.28" + "version": "14.0.4-canary.29" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 43bfd6c638c26..c867915eccef7 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 5b6833a2f19e7..4ef83fad6f6ee 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.28", + "@next/eslint-plugin-next": "14.0.4-canary.29", "@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 491e33ed3f5b8..c7702fcf5898f 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 3bdcb4b9931ad..1317d9f225f0f 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "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 16663e746f3cb..6633094f73b1f 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index fdf85f9a75812..603fb2e7db25c 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index b393af8e0dadc..10707b34a9631 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index c91d75144c59e..002e22c00802a 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 9f834f812b0db..64be9c56aa697 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "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 b153602bf8423..cf2098c6940a4 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "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 70cc83594274e..d816cecc38995 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index ff864cd1215ea..03b7e78a33f7a 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 2e2b949d755a1..7f274f0019578 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.28", + "@next/env": "14.0.4-canary.29", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.28", - "@next/polyfill-nomodule": "14.0.4-canary.28", - "@next/react-dev-overlay": "14.0.4-canary.28", - "@next/react-refresh-utils": "14.0.4-canary.28", - "@next/swc": "14.0.4-canary.28", + "@next/polyfill-module": "14.0.4-canary.29", + "@next/polyfill-nomodule": "14.0.4-canary.29", + "@next/react-dev-overlay": "14.0.4-canary.29", + "@next/react-refresh-utils": "14.0.4-canary.29", + "@next/swc": "14.0.4-canary.29", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 80995b9c7458d..71e78fc03cacc 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": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index c9d8745071fb3..d248388ad3f63 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "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 41e5febcdce60..03c719ec74b40 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.28", + "version": "14.0.4-canary.29", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.28", + "next": "14.0.4-canary.29", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c066f462f8b52..993494735b96b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.28 + specifier: 14.0.4-canary.29 version: link:../next outdent: specifier: 0.8.0 From f241f44b3888bc9d537610e620fa3c087e0a7120 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Thu, 30 Nov 2023 15:07:05 -0800 Subject: [PATCH 049/189] skip release if no new commits (#59134) Prevents publishing canaries if there are no changes Closes NEXT-1748 --- .github/workflows/trigger_release.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index cac8403d282a7..03e31b1bf1d6a 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -51,7 +51,18 @@ jobs: - run: git clone https://github.com/vercel/next.js.git --depth=25 . - - run: git describe || echo 'failed to get tag' + - name: Get commit of the latest tag + run: echo "LATEST_TAG_COMMIT=$(git rev-list -n 1 $(git describe --tags --abbrev=0))" >> $GITHUB_ENV + + - name: Get latest commit + run: echo "LATEST_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + + - name: Check if new commits since last tag + run: | + if [ "$LATEST_TAG" = "$LATEST_COMMIT" ]; then + echo "No new commits. Exiting..." + exit 1 + fi # https://github.com/actions/virtual-environments/issues/1187 - name: tune linux network From 3159fa197bf851df07c867c57029ae9c0b217729 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 30 Nov 2023 23:10:37 +0000 Subject: [PATCH 050/189] v14.0.4-canary.30 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index a3bd105416226..613b5b0575fd5 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.29" + "version": "14.0.4-canary.30" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index c867915eccef7..46ab3663b7dda 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 4ef83fad6f6ee..415018a661538 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.29", + "@next/eslint-plugin-next": "14.0.4-canary.30", "@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 c7702fcf5898f..b1597c79091f6 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 1317d9f225f0f..7a2aa16c7e74e 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "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 6633094f73b1f..911b23aca8d9c 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 603fb2e7db25c..80878bcb65009 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 10707b34a9631..b875f6149bedf 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 002e22c00802a..139b5a4956e26 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 64be9c56aa697..2ce968de008a3 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "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 cf2098c6940a4..eaf8e01607be4 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "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 d816cecc38995..13e9cfe8a85ef 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 03b7e78a33f7a..415765b214077 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 7f274f0019578..12d4de8de2c3d 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.29", + "@next/env": "14.0.4-canary.30", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.29", - "@next/polyfill-nomodule": "14.0.4-canary.29", - "@next/react-dev-overlay": "14.0.4-canary.29", - "@next/react-refresh-utils": "14.0.4-canary.29", - "@next/swc": "14.0.4-canary.29", + "@next/polyfill-module": "14.0.4-canary.30", + "@next/polyfill-nomodule": "14.0.4-canary.30", + "@next/react-dev-overlay": "14.0.4-canary.30", + "@next/react-refresh-utils": "14.0.4-canary.30", + "@next/swc": "14.0.4-canary.30", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 71e78fc03cacc..cd0615a61711c 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": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index d248388ad3f63..1b1dc1be3740c 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "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 03c719ec74b40..62b36c002aad5 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.29", + "version": "14.0.4-canary.30", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.29", + "next": "14.0.4-canary.30", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 993494735b96b..0a51b52456b2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.29 + specifier: 14.0.4-canary.30 version: link:../next outdent: specifier: 0.8.0 From 511867ceec25441cec83e89ab93d83257658549c Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Thu, 30 Nov 2023 15:19:46 -0800 Subject: [PATCH 051/189] fix variable name in release workflow (#59135) Follow up to https://github.com/vercel/next.js/pull/59134 --- .github/workflows/trigger_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index 03e31b1bf1d6a..286b896da6ff6 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -59,7 +59,7 @@ jobs: - name: Check if new commits since last tag run: | - if [ "$LATEST_TAG" = "$LATEST_COMMIT" ]; then + if [ "$LATEST_TAG_COMMIT" = "$LATEST_COMMIT" ]; then echo "No new commits. Exiting..." exit 1 fi From 1b08dfe040c95f83134a1002519091655c1cf7db Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 30 Nov 2023 23:22:21 +0000 Subject: [PATCH 052/189] v14.0.4-canary.31 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 613b5b0575fd5..ca249a31ba439 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.30" + "version": "14.0.4-canary.31" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 46ab3663b7dda..0778bc11aafbf 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 415018a661538..5f8d493c22e41 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.30", + "@next/eslint-plugin-next": "14.0.4-canary.31", "@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 b1597c79091f6..0dcd727c8eeb3 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 7a2aa16c7e74e..f6c60f89f6bd4 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "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 911b23aca8d9c..bff6a17c3350c 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 80878bcb65009..d398f07d74eea 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index b875f6149bedf..2fc7f1503109d 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 139b5a4956e26..87bee0c0020c3 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 2ce968de008a3..9736c9fcf640f 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "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 eaf8e01607be4..04efb1517d1e4 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "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 13e9cfe8a85ef..14e7d73cb8a2f 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 415765b214077..557ee400d7ddc 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 12d4de8de2c3d..9704d00d85117 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.30", + "@next/env": "14.0.4-canary.31", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.30", - "@next/polyfill-nomodule": "14.0.4-canary.30", - "@next/react-dev-overlay": "14.0.4-canary.30", - "@next/react-refresh-utils": "14.0.4-canary.30", - "@next/swc": "14.0.4-canary.30", + "@next/polyfill-module": "14.0.4-canary.31", + "@next/polyfill-nomodule": "14.0.4-canary.31", + "@next/react-dev-overlay": "14.0.4-canary.31", + "@next/react-refresh-utils": "14.0.4-canary.31", + "@next/swc": "14.0.4-canary.31", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index cd0615a61711c..7e9b084dff371 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": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 1b1dc1be3740c..b6660b9be0894 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "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 62b36c002aad5..5dcf2bece864e 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.30", + "version": "14.0.4-canary.31", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.30", + "next": "14.0.4-canary.31", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0a51b52456b2d..e5683fcda124e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.30 + specifier: 14.0.4-canary.31 version: link:../next outdent: specifier: 0.8.0 From 1c61153d779da0699d2542842a7d87f8d2cd4d65 Mon Sep 17 00:00:00 2001 From: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com> Date: Thu, 30 Nov 2023 20:20:22 -0500 Subject: [PATCH 053/189] Update font data (#59138) This auto-generated PR updates font data with latest available --- packages/font/src/google/font-data.json | 27 ++++++++++++++++++++++++- packages/font/src/google/index.ts | 6 ++++-- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/packages/font/src/google/font-data.json b/packages/font/src/google/font-data.json index 7a05dc31961a1..7ad4f398d1714 100644 --- a/packages/font/src/google/font-data.json +++ b/packages/font/src/google/font-data.json @@ -7348,8 +7348,33 @@ "subsets": ["hebrew", "latin", "latin-ext"] }, "Noto Sans": { - "weights": ["100", "200", "300", "400", "500", "600", "700", "800", "900"], + "weights": [ + "100", + "200", + "300", + "400", + "500", + "600", + "700", + "800", + "900", + "variable" + ], "styles": ["normal", "italic"], + "axes": [ + { + "tag": "wdth", + "min": 62.5, + "max": 100, + "defaultValue": 100 + }, + { + "tag": "wght", + "min": 100, + "max": 900, + "defaultValue": 400 + } + ], "subsets": [ "cyrillic", "cyrillic-ext", diff --git a/packages/font/src/google/index.ts b/packages/font/src/google/index.ts index c6b9cd987f496..c32c3f54b8745 100644 --- a/packages/font/src/google/index.ts +++ b/packages/font/src/google/index.ts @@ -13376,8 +13376,8 @@ export declare function Noto_Rashi_Hebrew< }): T extends undefined ? NextFont : NextFontWithVariable export declare function Noto_Sans< T extends CssVariable | undefined = undefined ->(options: { - weight: +>(options?: { + weight?: | '100' | '200' | '300' @@ -13387,6 +13387,7 @@ export declare function Noto_Sans< | '700' | '800' | '900' + | 'variable' | Array< '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900' > @@ -13406,6 +13407,7 @@ export declare function Noto_Sans< | 'latin-ext' | 'vietnamese' > + axes?: 'wdth'[] }): T extends undefined ? NextFont : NextFontWithVariable export declare function Noto_Sans_Adlam< T extends CssVariable | undefined = undefined From a5e60f179b9589fc64f8c11d42940a7a5628d0e5 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Thu, 30 Nov 2023 18:25:08 -0800 Subject: [PATCH 054/189] fix typedRoutes when used with webpackBuildWorker (#59140) When using `experimental.typedRoutes` in conjunction with `experimental.webpackBuildWorker`, type errors would be erroneously thrown during build. This is because the build workers are parallelized between multiple runtimes (edge, server, client), but the `typedRoutes` is unique to each `webpackBuild`. The state needs to shared between the different compile steps for each instance of the types plugin. This leverages plugin state to keep share the `typedRoutes` state amongst the different workers. Closes NEXT-1734 Fixes #58369 --- .../plugins/next-types-plugin/index.ts | 52 ++++++++++--------- packages/next/src/server/config-shared.ts | 1 + .../bad-routes/app/api/hello/route.ts | 7 +++ .../bad-routes/app/layout.tsx | 11 ++++ .../bad-routes/app/page.tsx | 9 ++++ .../bad-routes/next.config.js | 7 +++ .../good-routes/app/api/hello/route.ts | 7 +++ .../good-routes/app/layout.tsx | 11 ++++ .../good-routes/app/page.tsx | 9 ++++ .../good-routes/next.config.js | 7 +++ .../typed-routes-with-webpack-worker.test.ts | 40 ++++++++++++++ 11 files changed, 136 insertions(+), 25 deletions(-) create mode 100755 test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/api/hello/route.ts create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/layout.tsx create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/page.tsx create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/next.config.js create mode 100755 test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/api/hello/route.ts create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/layout.tsx create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/page.tsx create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/good-routes/next.config.js create mode 100644 test/production/app-dir/typed-routes-with-webpack-worker/typed-routes-with-webpack-worker.test.ts 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 caee8b07de407..30ab132edcb09 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 @@ -15,6 +15,7 @@ import { isDynamicRoute } from '../../../../shared/lib/router/utils' import { normalizeAppPath } from '../../../../shared/lib/router/utils/app-paths' import { getPageFromPath } from '../../../entries' import { devPageFiles } from './shared' +import { getProxiedPluginState } from '../../../build-context' const PLUGIN_NAME = 'NextTypesPlugin' @@ -221,23 +222,23 @@ async function collectNamedSlots(layoutPath: string) { // By exposing the static route types separately as string literals, // editors can provide autocompletion for them. However it's currently not // possible to provide the same experience for dynamic routes. -const routeTypes: Record< - 'edge' | 'node' | 'extra', - Record<'static' | 'dynamic', string> -> = { - edge: { - static: '', - dynamic: '', - }, - node: { - static: '', - dynamic: '', - }, - extra: { - static: '', - dynamic: '', - }, -} + +const pluginState = getProxiedPluginState({ + routeTypes: { + edge: { + static: '', + dynamic: '', + }, + node: { + static: '', + dynamic: '', + }, + extra: { + static: '', + dynamic: '', + }, + } as Record<'edge' | 'node' | 'extra', Record<'static' | 'dynamic', string>>, +}) function formatRouteToRouteType(route: string) { const isDynamic = isDynamicRoute(route) @@ -341,7 +342,8 @@ function addRedirectsRewritesRouteTypes( for (const normalizedRoute of possibleNormalizedRoutes) { const { isDynamic, routeType } = formatRouteToRouteType(normalizedRoute) - routeTypes.extra[isDynamic ? 'dynamic' : 'static'] += routeType + pluginState.routeTypes.extra[isDynamic ? 'dynamic' : 'static'] += + routeType } } } @@ -374,8 +376,8 @@ function createRouteDefinitions() { let dynamicRouteTypes = '' for (const type of ['edge', 'node', 'extra'] as const) { - staticRouteTypes += routeTypes[type].static - dynamicRouteTypes += routeTypes[type].dynamic + staticRouteTypes += pluginState.routeTypes[type].static + dynamicRouteTypes += pluginState.routeTypes[type].dynamic } // If both StaticRoutes and DynamicRoutes are empty, fallback to type 'string'. @@ -578,7 +580,7 @@ export class NextTypesPlugin { const { isDynamic, routeType } = formatRouteToRouteType(route) - routeTypes[this.isEdgeServer ? 'edge' : 'node'][ + pluginState.routeTypes[this.isEdgeServer ? 'edge' : 'node'][ isDynamic ? 'dynamic' : 'static' ] += routeType } @@ -667,11 +669,11 @@ export class NextTypesPlugin { // Clear routes if (this.isEdgeServer) { - routeTypes.edge.dynamic = '' - routeTypes.edge.static = '' + pluginState.routeTypes.edge.dynamic = '' + pluginState.routeTypes.edge.static = '' } else { - routeTypes.node.dynamic = '' - routeTypes.node.static = '' + pluginState.routeTypes.node.dynamic = '' + pluginState.routeTypes.node.static = '' } compilation.chunkGroups.forEach((chunkGroup) => { diff --git a/packages/next/src/server/config-shared.ts b/packages/next/src/server/config-shared.ts index d2dda84b82f4b..7ba9a6ad3bb7c 100644 --- a/packages/next/src/server/config-shared.ts +++ b/packages/next/src/server/config-shared.ts @@ -806,6 +806,7 @@ export const defaultConfig: NextConfig = { process.env.__NEXT_EXPERIMENTAL_PPR === 'true' ? true : false, + webpackBuildWorker: false, }, } diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/api/hello/route.ts b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/api/hello/route.ts new file mode 100755 index 0000000000000..b72d3b2cc4faa --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/api/hello/route.ts @@ -0,0 +1,7 @@ +import { NextRequest, NextResponse } from 'next/server' + +export const runtime = 'edge' + +export async function GET(request: NextRequest) { + return NextResponse.json({ hello: 'world' }) +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/layout.tsx b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/layout.tsx new file mode 100644 index 0000000000000..ce81757e7c107 --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/layout.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +export const dynamic = 'force-dynamic' + +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/page.tsx b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/page.tsx new file mode 100644 index 0000000000000..f30de2d088aa2 --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/app/page.tsx @@ -0,0 +1,9 @@ +import Link from 'next/link' + +export default function Home() { + return ( +
+ Hello, world! +
+ ) +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/next.config.js b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/next.config.js new file mode 100644 index 0000000000000..ed7707d2a91a3 --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/bad-routes/next.config.js @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +module.exports = { + experimental: { + typedRoutes: true, + webpackBuildWorker: true, + }, +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/api/hello/route.ts b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/api/hello/route.ts new file mode 100755 index 0000000000000..b72d3b2cc4faa --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/api/hello/route.ts @@ -0,0 +1,7 @@ +import { NextRequest, NextResponse } from 'next/server' + +export const runtime = 'edge' + +export async function GET(request: NextRequest) { + return NextResponse.json({ hello: 'world' }) +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/layout.tsx b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/layout.tsx new file mode 100644 index 0000000000000..ce81757e7c107 --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/layout.tsx @@ -0,0 +1,11 @@ +import React from 'react' + +export const dynamic = 'force-dynamic' + +export default function Root({ children }: { children: React.ReactNode }) { + return ( + + {children} + + ) +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/page.tsx b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/page.tsx new file mode 100644 index 0000000000000..556d2ef63ad5d --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/app/page.tsx @@ -0,0 +1,9 @@ +import Link from 'next/link' + +export default function Home() { + return ( +
+ Hello, world! +
+ ) +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/next.config.js b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/next.config.js new file mode 100644 index 0000000000000..ed7707d2a91a3 --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/good-routes/next.config.js @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +module.exports = { + experimental: { + typedRoutes: true, + webpackBuildWorker: true, + }, +} diff --git a/test/production/app-dir/typed-routes-with-webpack-worker/typed-routes-with-webpack-worker.test.ts b/test/production/app-dir/typed-routes-with-webpack-worker/typed-routes-with-webpack-worker.test.ts new file mode 100644 index 0000000000000..a2d5880ba26d9 --- /dev/null +++ b/test/production/app-dir/typed-routes-with-webpack-worker/typed-routes-with-webpack-worker.test.ts @@ -0,0 +1,40 @@ +import { nextBuild } from 'next-test-utils' +import path from 'path' + +describe('app dir - typed-routes-with-webpack-worker', () => { + it('builds successfully without errors', async () => { + const output = await nextBuild( + path.join(__dirname, 'good-routes'), + undefined, + { + stdout: true, + stderr: true, + } + ) + + // check for the experimental flag warning + expect(output.stdout).toContain('webpackBuildWorker') + // should have a successful build + expect(output.code).toBe(0) + // with no errors + expect(output.stderr).not.toContain(`"/" is not an existing route.`) + }) + + it('builds with valid errors', async () => { + const output = await nextBuild( + path.join(__dirname, 'bad-routes'), + undefined, + { + stdout: true, + stderr: true, + } + ) + + // check for the experimental flag warning + expect(output.stdout).toContain('webpackBuildWorker') + // should have a failed build + expect(output.code).toBe(1) + // with correct error + expect(output.stderr).toContain(`"/asdfasdfasdf" is not an existing route.`) + }) +}) From cdff6df0980b854b7c0ce06ada82bc58ab545d2a Mon Sep 17 00:00:00 2001 From: Michael Diodone <8616698+mdio@users.noreply.github.com> Date: Fri, 1 Dec 2023 04:05:20 +0100 Subject: [PATCH 055/189] Add NEXT_MANUAL_SIG_HANDLE handling to start-server.ts (#59117) If a manual signal handler is registered, SIGINT and SIGTERM should not be handled by Next.js. This was already the case in the standalone server.js but was missing here, rendering the env flag useless. With this fix, the example given in https://nextjs.org/docs/pages/building-your-application/deploying#manual-graceful-shutdowns is working (again). Fixes #56810. Co-authored-by: Zack Tanner --- packages/next/src/server/lib/start-server.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/next/src/server/lib/start-server.ts b/packages/next/src/server/lib/start-server.ts index fd501c6ab8ad0..84610325b0632 100644 --- a/packages/next/src/server/lib/start-server.ts +++ b/packages/next/src/server/lib/start-server.ts @@ -280,9 +280,11 @@ export async function startServer( console.error(err) } process.on('exit', (code) => cleanup(code)) - // callback value is signal string, exit with 0 - process.on('SIGINT', () => cleanup(0)) - process.on('SIGTERM', () => cleanup(0)) + if (!process.env.NEXT_MANUAL_SIG_HANDLE) { + // callback value is signal string, exit with 0 + process.on('SIGINT', () => cleanup(0)) + process.on('SIGTERM', () => cleanup(0)) + } process.on('rejectionHandled', () => { // It is ok to await a Promise late in Next.js as it allows for better // prefetching patterns to avoid waterfalls. We ignore loggining these. From 7458ffa042c2141bd18b119d93d064acaba42315 Mon Sep 17 00:00:00 2001 From: Christian Vuerings Date: Thu, 30 Nov 2023 19:40:57 -0800 Subject: [PATCH 056/189] Support adding CSP nonce with `content-security-policy-report-only` header (#59071) **Note**: this is a 1-to-1 copy of #48969 by @danieltott with all the merge conflicts fixed. ## Checklist * Fixes https://github.com/vercel/next.js/issues/48966 * Tests added to `test/production/app-dir/subresource-integrity/subresource-integrity.test.ts` ## Description Currently `renderToHTMLOrFlight` in app-render pulls out a nonce value from a `content-security-policy` header for use in generating script tags: https://github.com/vercel/next.js/blob/e7c9d3c051e6027cf187e0d70565417d6037e37c/packages/next/src/server/app-render/app-render.tsx#L1204 That misses the ability to use a [content-security-policy-report-only header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy-Report-Only). Many times this is a required step to enabling a CSP - by shipping a CSP with report-only and collecting reports before actually blocking resources. ## Changes * Added ability to check `content-security-policy-report-only` header in `renderToHTMLOrFlight()` * Added test to verify `nonce` is correctly applied when `content-security-policy-report-only` header exists Co-authored-by: Dan Ott Co-authored-by: Zack Tanner --- .../next/src/server/app-render/app-render.tsx | 4 +- .../subresource-integrity.test.ts | 44 +++++++++++++++++-- 2 files changed, 43 insertions(+), 5 deletions(-) diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 53664456c2119..407b66af3adeb 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -658,7 +658,9 @@ async function renderToHTMLOrFlightImpl( : null // Get the nonce from the incoming request if it has one. - const csp = req.headers['content-security-policy'] + const csp = + req.headers['content-security-policy'] || + req.headers['content-security-policy-report-only'] let nonce: string | undefined if (csp && typeof csp === 'string') { nonce = getScriptNonceFromHeader(csp) diff --git a/test/production/app-dir/subresource-integrity/subresource-integrity.test.ts b/test/production/app-dir/subresource-integrity/subresource-integrity.test.ts index 7664abf7fd129..61cd9be169a1c 100644 --- a/test/production/app-dir/subresource-integrity/subresource-integrity.test.ts +++ b/test/production/app-dir/subresource-integrity/subresource-integrity.test.ts @@ -9,18 +9,24 @@ createNextDescribe( files: path.join(__dirname, 'fixture'), }, ({ next }) => { - function fetchWithPolicy(policy: string | null) { + function fetchWithPolicy(policy: string | null, reportOnly?: boolean) { + const cspKey = reportOnly + ? 'Content-Security-Policy-Report-Only' + : 'Content-Security-Policy' return next.fetch('/dashboard', { headers: policy ? { - 'Content-Security-Policy': policy, + [cspKey]: policy, } : {}, }) } - async function renderWithPolicy(policy: string | null) { - const res = await fetchWithPolicy(policy) + async function renderWithPolicy( + policy: string | null, + reportOnly?: boolean + ) { + const res = await fetchWithPolicy(policy, reportOnly) expect(res.ok).toBe(true) @@ -78,6 +84,36 @@ createNextDescribe( } }) + it('includes a nonce value with inline scripts when Content-Security-Policy-Report-Only header is defined', async () => { + // A random nonce value, base64 encoded. + const nonce = 'cmFuZG9tCg==' + + // Validate all the cases where we could parse the nonce. + const policies = [ + `script-src 'nonce-${nonce}'`, // base case + ` script-src 'nonce-${nonce}' `, // extra space added around sources and directive + `style-src 'self'; script-src 'nonce-${nonce}'`, // extra directives + `script-src 'self' 'nonce-${nonce}' 'nonce-othernonce'`, // extra nonces + `default-src 'nonce-othernonce'; script-src 'nonce-${nonce}';`, // script and then fallback case + `default-src 'nonce-${nonce}'`, // fallback case + ] + + for (const policy of policies) { + const $ = await renderWithPolicy(policy, true) + + // Find all the script tags without src attributes. + const elements = $('script:not([src])') + + // Expect there to be at least 1 script tag without a src attribute. + expect(elements.length).toBeGreaterThan(0) + + // Expect all inline scripts to have the nonce value. + elements.each((i, el) => { + expect(el.attribs['nonce']).toBe(nonce) + }) + } + }) + it('includes a nonce value with bootstrap scripts when Content-Security-Policy header is defined', async () => { // A random nonce value, base64 encoded. const nonce = 'cmFuZG9tCg==' From fa9cd3efc4b310557aeb0ca2a008a4d5bda34046 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Fri, 1 Dec 2023 04:31:03 +0000 Subject: [PATCH 057/189] v14.0.4-canary.32 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index ca249a31ba439..9dc50ac12635a 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.31" + "version": "14.0.4-canary.32" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 0778bc11aafbf..ed9d905cdda11 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 5f8d493c22e41..783563105fdf1 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.31", + "@next/eslint-plugin-next": "14.0.4-canary.32", "@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 0dcd727c8eeb3..9eb41bf8a28fd 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index f6c60f89f6bd4..b4b2b0ede045c 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "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 bff6a17c3350c..2a8920dcfa71b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index d398f07d74eea..5085450317c45 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 2fc7f1503109d..7638b48733614 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 87bee0c0020c3..8e6c50d2bf49c 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 9736c9fcf640f..9a65f5a7365b9 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "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 04efb1517d1e4..95861675a41c1 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "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 14e7d73cb8a2f..93496f85776cb 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 557ee400d7ddc..ae92bdba6c1de 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 9704d00d85117..4dd3e435abd7f 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.31", + "@next/env": "14.0.4-canary.32", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.31", - "@next/polyfill-nomodule": "14.0.4-canary.31", - "@next/react-dev-overlay": "14.0.4-canary.31", - "@next/react-refresh-utils": "14.0.4-canary.31", - "@next/swc": "14.0.4-canary.31", + "@next/polyfill-module": "14.0.4-canary.32", + "@next/polyfill-nomodule": "14.0.4-canary.32", + "@next/react-dev-overlay": "14.0.4-canary.32", + "@next/react-refresh-utils": "14.0.4-canary.32", + "@next/swc": "14.0.4-canary.32", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 7e9b084dff371..dd02ce6438b66 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": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index b6660b9be0894..a28de74e82edc 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "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 5dcf2bece864e..b37c7c31872b4 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.31", + "version": "14.0.4-canary.32", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.31", + "next": "14.0.4-canary.32", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5683fcda124e..39fa286d13e51 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.31 + specifier: 14.0.4-canary.32 version: link:../next outdent: specifier: 0.8.0 From 89f6322cda88b4972a7e11651327e53144b0ea10 Mon Sep 17 00:00:00 2001 From: Ahmed Abdelbaset Date: Fri, 1 Dec 2023 10:53:02 +0200 Subject: [PATCH 058/189] chore: fix typo in jsDoc (#58224) --- packages/next/types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index e22cdbc21efb2..062e333c2f217 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -87,7 +87,7 @@ export type Redirect = } /** - * `Page` type, use it as a guide to create `pages`. + * `NextPage` type, use it as a guide to create `pages`. */ export type NextPage = NextComponentType< NextPageContext, From b02a10e331dcc6e484cecd6954ec4e07dea96fda Mon Sep 17 00:00:00 2001 From: Karl Horky Date: Fri, 1 Dec 2023 09:57:57 +0100 Subject: [PATCH 059/189] Enable typechecking on config (#57892) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lee Robinson Co-authored-by: Balázs Orbán --- examples/reproduction-template-pages/next.config.js | 4 +++- examples/reproduction-template/next.config.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/examples/reproduction-template-pages/next.config.js b/examples/reproduction-template-pages/next.config.js index 0e5c476c943b1..4e2b4c73287b4 100644 --- a/examples/reproduction-template-pages/next.config.js +++ b/examples/reproduction-template-pages/next.config.js @@ -1,4 +1,6 @@ /** @type {import("next").NextConfig} */ -module.exports = { +const nextConfig = { reactStrictMode: true, } + +module.exports = nextConfig diff --git a/examples/reproduction-template/next.config.js b/examples/reproduction-template/next.config.js index 0e5c476c943b1..4e2b4c73287b4 100644 --- a/examples/reproduction-template/next.config.js +++ b/examples/reproduction-template/next.config.js @@ -1,4 +1,6 @@ /** @type {import("next").NextConfig} */ -module.exports = { +const nextConfig = { reactStrictMode: true, } + +module.exports = nextConfig From f47640375ad894cdc9cc5a9fef7d0efe5fbbe22c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20H=C3=A4nisch?= Date: Fri, 1 Dec 2023 10:58:02 +0100 Subject: [PATCH 060/189] fix: add `maxDuration` to `PageConfig` type (#55918) --- packages/next/types/index.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/next/types/index.d.ts b/packages/next/types/index.d.ts index 062e333c2f217..bda45bbd50066 100644 --- a/packages/next/types/index.d.ts +++ b/packages/next/types/index.d.ts @@ -140,6 +140,11 @@ export type PageConfig = { externalResolver?: true } env?: Array + /** + * Configures the longest time in seconds a serverless function can process an HTTP + * request before responding. + */ + maxDuration?: number runtime?: ServerRuntime unstable_runtimeJS?: false unstable_JsPreload?: false From cc42e437ea54e3705eb6efd9f94b8908db77820c Mon Sep 17 00:00:00 2001 From: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com> Date: Fri, 1 Dec 2023 05:16:28 -0500 Subject: [PATCH 061/189] Update Turbopack test manifest (#59109) This auto-generated PR updates the integration test manifest used when testing Turbopack. --------- Co-authored-by: Tobias Koppers --- test/build-turbopack-tests-manifest.js | 53 +++- test/turbopack-tests-manifest.json | 372 ++++++++++++++++++------- 2 files changed, 320 insertions(+), 105 deletions(-) diff --git a/test/build-turbopack-tests-manifest.js b/test/build-turbopack-tests-manifest.js index 1230c4f8d4a2d..a49c01bae27ad 100644 --- a/test/build-turbopack-tests-manifest.js +++ b/test/build-turbopack-tests-manifest.js @@ -24,21 +24,21 @@ const INITIALIZING_TEST_CASES = [ // please make sure this is sorted alphabetically when making changes. const SKIPPED_TEST_SUITES = { 'test/development/acceptance-app/ReactRefreshRegression.test.ts': [ - 'ReactRefreshRegression app can fast refresh a page with dynamic rendering', 'ReactRefreshRegression app can fast refresh a page with config', + 'ReactRefreshRegression app can fast refresh a page with dynamic rendering', ], 'test/development/acceptance-app/ReactRefreshRequire.test.ts': [ - 'ReactRefreshRequire app re-runs accepted modules', 'ReactRefreshRequire app propagates a hot update to closest accepted module', 'ReactRefreshRequire app propagates hot update to all inverse dependencies', + 'ReactRefreshRequire app re-runs accepted modules', ], 'test/development/acceptance/ReactRefreshLogBox.test.ts': [ 'ReactRefreshLogBox turbo conversion to class component (1)', ], 'test/development/acceptance/ReactRefreshRequire.test.ts': [ - 'ReactRefreshRequire re-runs accepted modules', 'ReactRefreshRequire propagates a hot update to closest accepted module', 'ReactRefreshRequire propagates hot update to all inverse dependencies', + 'ReactRefreshRequire re-runs accepted modules', ], 'test/development/basic/hmr.test.ts': [ 'basic HMR, basePath: "/docs" Error Recovery should show the error on all pages', @@ -47,8 +47,16 @@ const SKIPPED_TEST_SUITES = { /should automatically fast refresh content when path is added without error/, /should recover from module not found when paths is updated/, ], + 'test/development/middleware-errors/index.test.ts': [ + 'middleware - development errors when there is a compilation error after boot logs the error correctly', + 'middleware - development errors when there is a compilation error from boot logs the error correctly', + ], 'test/development/tsconfig-path-reloading/index.test.ts': [ /should automatically fast refresh content when path is added without error/, + 'tsconfig-path-reloading tsconfig added after starting dev should load with initial paths config correctly', + ], + 'test/e2e/app-dir/app-compilation/index.test.ts': [ + 'app dir HMR should not cause error when removing loading.js', ], 'test/e2e/app-dir/app-css/index.test.ts': [ 'app dir - css css support server layouts should support external css imports', @@ -68,6 +76,9 @@ const SKIPPED_TEST_SUITES = { 'basePath should 404 when manually adding basePath with router.push', 'basePath should 404 when manually adding basePath with router.replace', ], + 'test/e2e/conflicting-app-page-error/index.test.ts': [ + 'Conflict between app file and pages file should not show error overlay for non conflict pages under app or pages dir', + ], 'test/e2e/middleware-rewrites/test/index.test.ts': [ 'Middleware Rewrite should have props for afterFiles rewrite to SSG page', ], @@ -82,8 +93,8 @@ const SKIPPED_TEST_SUITES = { 'Document and App Client side should detect the changes to pages/_document.js and display it', ], 'test/integration/css/test/css-modules.test.js': [ - 'CSS Modules Composes Ordering Development Mode should have correct color on index page (on nav from other)', 'CSS Modules Composes Ordering Development Mode should have correct color on index page (on nav from index)', + 'CSS Modules Composes Ordering Development Mode should have correct color on index page (on nav from other)', ], 'test/integration/custom-error/test/index.test.js': [/Custom _error/], 'test/integration/dynamic-routing/test/index.test.js': [ @@ -96,13 +107,41 @@ const SKIPPED_TEST_SUITES = { 'Dynamic Routing production mode should output a routes-manifest correctly', ], 'test/integration/env-config/test/index.test.js': [ - 'Env Config dev mode with hot reload should provide env for SSG', - 'Env Config dev mode with hot reload should provide env correctly for SSR', 'Env Config dev mode with hot reload should provide env correctly for API routes', + 'Env Config dev mode with hot reload should provide env correctly for SSR', + 'Env Config dev mode with hot reload should provide env for SSG', ], 'test/integration/import-assertion/test/index.test.js': [ /should handle json assertions/, ], + 'test/integration/next-image-legacy/unicode/test/index.test.ts': [ + /Image Component Unicode Image URL/, + ], + 'test/integration/next-image-new/unicode/test/index.test.ts': [ + /Image Component Unicode Image URL/, + ], +} + +function checkSorted(arr, name) { + const sorted = [...arr].sort() + if (JSON.stringify(arr) !== JSON.stringify(sorted)) { + console.log(`Expected order of ${name}:`) + for (let i = 0; i < arr.length; i++) { + if (arr[i] === sorted[i]) { + console.log(` ${arr[i]}`) + } else { + console.log(bold().red(`- ${arr[i]}`)) + console.log(bold().green(`+ ${sorted[i]}`)) + } + } + throw new Error(`${name} is not sorted`) + } +} + +checkSorted(Object.keys(SKIPPED_TEST_SUITES), 'SKIPPED_TEST_SUITES') + +for (const [key, value] of Object.entries(SKIPPED_TEST_SUITES)) { + checkSorted(value, `SKIPPED_TEST_SUITES['${key}']`) } /** @@ -234,7 +273,7 @@ async function updatePassingTests() { if (skippedPassingNames.length > 0) { console.log( - `${bold().red(filepath)} has ${ + `${bold().yellow(filepath)} has ${ skippedPassingNames.length } passing tests that are marked as skipped:\n${skippedPassingNames .map((name) => ` - ${name}`) diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index 5a3fa8d053b95..3e09257874799 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -204,23 +204,6 @@ "flakey": [], "runtimeError": false }, - "packages/next/src/client/components/router-reducer/create-optimistic-tree.test.ts": { - "passed": ["createOptimisticTree should create an optimistic tree"], - "failed": [], - "pending": [], - "flakey": [], - "runtimeError": false - }, - "packages/next/src/client/components/router-reducer/create-record-from-thenable.test.ts": { - "passed": [ - "createRecordFromThenable rejecting promise", - "createRecordFromThenable successful promise" - ], - "failed": [], - "pending": [], - "flakey": [], - "runtimeError": false - }, "packages/next/src/client/components/router-reducer/create-router-cache-key.test.ts": { "passed": [ "createRouterCacheKey should support catch all segment", @@ -462,6 +445,16 @@ "flakey": [], "runtimeError": false }, + "packages/next/src/server/config.test.ts": { + "passed": [ + "loadConfig nextConfig.images defaults should assign a `images.remotePatterns` when using assetPrefix", + "loadConfig nextConfig.images defaults should not assign a duplicate `images.remotePatterns` value when using assetPrefix" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "packages/next/src/server/dev/parse-version-info.test.ts": { "passed": [ "parse version info installed: 12.0.0, latest: 13.1.1, canary: 13.0.1-canary.0 yields stale-major", @@ -1401,6 +1394,13 @@ "flakey": [], "runtimeError": false }, + "test/development/app-dir/experimental-lightningcss/experimental-lightningcss.test.ts": { + "passed": ["experimental-lightningcss should support css modules"], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/development/app-dir/multiple-compiles-single-route/multiple-compiles-single-route.test.ts": { "passed": [ "multiple-compiles-single-route should not compile additional matching paths" @@ -1449,15 +1449,16 @@ "runtimeError": false }, "test/development/basic/barrel-optimization/barrel-optimization.test.ts": { - "passed": [], + "passed": [ + "optimizePackageImports should handle recursive wildcard exports", + "optimizePackageImports should not break \"use client\" directive in optimized packages", + "optimizePackageImports should support \"use client\" directive in barrel file" + ], "failed": [ "optimizePackageImports app - should optimize recursive wildcard export mapping", "optimizePackageImports app - should render the icons correctly without creating all the modules", "optimizePackageImports pages - should optimize recursive wildcard export mapping", "optimizePackageImports pages - should render the icons correctly without creating all the modules", - "optimizePackageImports should handle recursive wildcard exports", - "optimizePackageImports should not break \"use client\" directive in optimized packages", - "optimizePackageImports should support \"use client\" directive in barrel file", "optimizePackageImports should support visx" ], "pending": [], @@ -1841,6 +1842,7 @@ "middleware - development errors when middleware throws synchronously renders the error correctly and recovers", "middleware - development errors when running invalid dynamic code with eval logs the error correctly", "middleware - development errors when there is a compilation error after boot renders the error correctly and recovers", + "middleware - development errors when there is a compilation error from boot renders the error correctly and recovers", "middleware - development errors when there is an unhandled rejection while loading a dependency does not render the error", "middleware - development errors when there is an unhandled rejection while loading a dependency logs the error correctly", "middleware - development errors when there is an unhandled rejection while loading the module does not render the error", @@ -1849,14 +1851,14 @@ "failed": [ "middleware - development errors when middleware throws synchronously logs the error correctly", "middleware - development errors when running invalid dynamic code with eval renders the error correctly and recovers", - "middleware - development errors when there is a compilation error after boot logs the error correctly", - "middleware - development errors when there is a compilation error from boot logs the error correctly", - "middleware - development errors when there is a compilation error from boot renders the error correctly and recovers", "middleware - development errors when throwing while loading the module logs the error correctly", "middleware - development errors when throwing while loading the module renders the error correctly and recovers" ], "pending": [], - "flakey": [], + "flakey": [ + "middleware - development errors when there is a compilation error after boot logs the error correctly", + "middleware - development errors when there is a compilation error from boot logs the error correctly" + ], "runtimeError": false }, "test/development/middleware-warnings/index.test.ts": { @@ -2074,16 +2076,17 @@ }, "test/development/tsconfig-path-reloading/index.test.ts": { "passed": [ - "tsconfig-path-reloading tsconfig added after starting dev should load with initial paths config correctly", "tsconfig-path-reloading tsconfig should load with initial paths config correctly" ], - "failed": [], + "failed": [ + "tsconfig-path-reloading tsconfig added after starting dev should recover from module not found when paths is updated", + "tsconfig-path-reloading tsconfig should recover from module not found when paths is updated" + ], "pending": [], "flakey": [ "tsconfig-path-reloading tsconfig added after starting dev should automatically fast refresh content when path is added without error", - "tsconfig-path-reloading tsconfig added after starting dev should recover from module not found when paths is updated", - "tsconfig-path-reloading tsconfig should automatically fast refresh content when path is added without error", - "tsconfig-path-reloading tsconfig should recover from module not found when paths is updated" + "tsconfig-path-reloading tsconfig added after starting dev should load with initial paths config correctly", + "tsconfig-path-reloading tsconfig should automatically fast refresh content when path is added without error" ], "runtimeError": false }, @@ -2131,7 +2134,7 @@ "failed": [], "pending": [], "flakey": [], - "runtimeError": true + "runtimeError": false }, "test/e2e/app-dir-legacy-edge-runtime-config/index.test.ts": { "passed": [], @@ -2241,8 +2244,15 @@ "app-dir action handling fetch actions should revalidate when cookies.set is called", "app-dir action handling fetch actions should revalidate when cookies.set is called in a client action", "app-dir action handling fetch actions should store revalidation data in the prefetch cache", + "app-dir action handling redirects redirects properly when server action handler redirects with a 307 status code", + "app-dir action handling redirects redirects properly when server action handler redirects with a 308 status code", + "app-dir action handling redirects redirects properly when server action handler uses `permanentRedirect`", + "app-dir action handling redirects redirects properly when server action handler uses `redirect`", + "app-dir action handling should 404 when POSTing an invalid server action", "app-dir action handling should bundle external libraries if they are on the action layer", + "app-dir action handling should handle actions executed in quick succession", "app-dir action handling should handle basic actions correctly", + "app-dir action handling should log a warning when a server action is not found but an id is provided", "app-dir action handling should not block navigation events while a server action is in flight", "app-dir action handling should only submit action once when resubmitting an action after navigation", "app-dir action handling should push new route when redirecting", @@ -2255,6 +2265,7 @@ "app-dir action handling should support importing actions in client components", "app-dir action handling should support importing the same action module instance in both server and action layers", "app-dir action handling should support next/dynamic with ssr: false", + "app-dir action handling should support next/dynamic with ssr: false (edge)", "app-dir action handling should support notFound", "app-dir action handling should support notFound (javascript disabled)", "app-dir action handling should support setting cookies in route handlers with the correct overrides", @@ -2312,10 +2323,10 @@ "runtimeError": false }, "test/e2e/app-dir/app-compilation/index.test.ts": { - "passed": ["app dir HMR should not cause error when removing loading.js"], + "passed": [], "failed": [], "pending": [], - "flakey": [], + "flakey": ["app dir HMR should not cause error when removing loading.js"], "runtimeError": false }, "test/e2e/app-dir/app-config-crossorigin/index.test.ts": { @@ -2420,6 +2431,7 @@ "passed": [ "app dir - external dependency react in external esm packages should use the same react in client app", "app dir - external dependency react in external esm packages should use the same react in edge server app", + "app dir - external dependency react in external esm packages should use the same react in pages", "app dir - external dependency react in external esm packages should use the same react in server app", "app dir - external dependency should correctly collect global css imports and mark them as side effects", "app dir - external dependency should export client module references in esm", @@ -2435,7 +2447,6 @@ "app dir - external dependency should use the same export type for packages in both ssr and client" ], "failed": [ - "app dir - external dependency react in external esm packages should use the same react in pages", "app dir - external dependency should be able to opt-out 3rd party packages being bundled in server components", "app dir - external dependency should have proper tree-shaking for known modules in CJS" ], @@ -2445,6 +2456,7 @@ }, "test/e2e/app-dir/app-fetch-deduping/app-fetch-deduping.test.ts": { "passed": [ + "app-fetch-deduping during next dev should dedupe pending revalidation requests", "app-fetch-deduping during next dev should dedupe requests called from the same component" ], "failed": [], @@ -2454,9 +2466,12 @@ }, "test/e2e/app-dir/app-middleware/app-middleware.test.ts": { "passed": [ - "app dir - middleware without pages dir Updates headers", "app dir - middleware with middleware in src dir works without crashing when using requestAsyncStorage", + "app dir - middleware without pages dir Updates headers", + "app-dir with middleware Mutate request headers for Edge Functions Adds new headers", + "app-dir with middleware Mutate request headers for Edge Functions Deletes headers", "app-dir with middleware Mutate request headers for Edge Functions Supports draft mode", + "app-dir with middleware Mutate request headers for Edge Functions Updates headers", "app-dir with middleware Mutate request headers for Serverless Functions Adds new headers", "app-dir with middleware Mutate request headers for Serverless Functions Deletes headers", "app-dir with middleware Mutate request headers for Serverless Functions Supports draft mode", @@ -2465,9 +2480,6 @@ "app-dir with middleware Mutate request headers for next/headers Deletes headers", "app-dir with middleware Mutate request headers for next/headers Supports draft mode", "app-dir with middleware Mutate request headers for next/headers Updates headers", - "app-dir with middleware Mutate request headers for Edge Functions Adds new headers", - "app-dir with middleware Mutate request headers for Edge Functions Deletes headers", - "app-dir with middleware Mutate request headers for Edge Functions Updates headers", "app-dir with middleware should filter correctly after middleware rewrite" ], "failed": [], @@ -2475,6 +2487,16 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/app-prefetch-false-loading/app-prefetch-false-loading.test.ts": { + "passed": [ + "app-prefetch-false-loading should not re-trigger loading state when navigating between pages that share a dynamic layout", + "app-prefetch-false-loading should render loading for the inital render" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/app-prefetch-false/app-prefetch-false.test.ts": { "passed": [], "failed": [], @@ -2568,6 +2590,7 @@ "app-custom-routes hooks notFound can respond correctly", "app-custom-routes hooks permanentRedirect can respond correctly", "app-custom-routes hooks redirect can respond correctly", + "app-custom-routes hooks req.cookies gets the correct values", "app-custom-routes invalid exports should print an error when exporting a default handler in dev", "app-custom-routes no response returned should print an error when no response is returned", "app-custom-routes works with api prefix correctly does not statically generate with dynamic usage", @@ -2632,6 +2655,7 @@ "app-custom-routes hooks notFound can respond correctly", "app-custom-routes hooks permanentRedirect can respond correctly", "app-custom-routes hooks redirect can respond correctly", + "app-custom-routes hooks req.cookies gets the correct values", "app-custom-routes invalid exports should print an error when exporting a default handler in dev", "app-custom-routes no response returned should print an error when no response is returned", "app-custom-routes works with api prefix correctly does not statically generate with dynamic usage", @@ -3088,6 +3112,8 @@ }, "test/e2e/app-dir/dynamic/dynamic.test.ts": { "passed": [ + "app dir - next/dynamic no SSR should not render client component imported through ssr: false in client components", + "app dir - next/dynamic no SSR should not render client component imported through ssr: false in client components in edge runtime", "app dir - next/dynamic should generate correct client manifest for dynamic chunks", "app dir - next/dynamic should handle next/dynamic in SSR correctly", "app dir - next/dynamic should handle next/dynamic in hydration correctly", @@ -3098,6 +3124,16 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/edge-route-rewrite/edge-route-rewrite.test.ts": { + "passed": [ + "edge-route-rewrite it should support a rewrite to a dynamic edge route", + "edge-route-rewrite it should support a rewrite to an edge route" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/edge-runtime-node-compatibility/edge-runtime-node-compatibility.test.ts": { "passed": [], "failed": [ @@ -3184,6 +3220,17 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/global-error/catch-all/index.test.ts": { + "passed": [ + "app dir - global error - with catch-all route should render catch-all route correctly" + ], + "failed": [ + "app dir - global error - with catch-all route should render 404 page correctly" + ], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/global-error/layout-error/index.test.ts": { "passed": [ "app dir - global error - layout error should render global error for error in server components" @@ -3271,6 +3318,7 @@ }, "test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts": { "passed": [ + "interception-middleware-rewrite should continue to work after using browser back button and following another intercepting route", "interception-middleware-rewrite should support intercepting routes with a middleware rewrite" ], "failed": [], @@ -3304,19 +3352,20 @@ "flakey": [], "runtimeError": false }, - "test/e2e/app-dir/logging/index.test.ts": { + "test/e2e/app-dir/logging/fetch-logging.test.ts": { "passed": [ + "app-dir - logging with default logging should not contain trailing word page for app router routes", "app-dir - logging with default logging should not log fetch requests at all" ], "failed": [ "app-dir - logging with default logging should not contain metadata internal segments for dynamic metadata routes", - "app-dir - logging with default logging should not contain trailing word page for app router routes", "app-dir - logging with verbose logging for edge runtime should not contain metadata internal segments for dynamic metadata routes", "app-dir - logging with verbose logging for edge runtime should not contain trailing word page for app router routes", "app-dir - logging with verbose logging for edge runtime should not log fetch requests at all", "app-dir - logging with verbose logging should log 'skip' cache status with a reason when cache: 'no-cache' is used", "app-dir - logging with verbose logging should log 'skip' cache status with a reason when revalidate: 0 is used", "app-dir - logging with verbose logging should log 'skip' cache status with a reason when the browser indicates caching should be ignored", + "app-dir - logging with verbose logging should log requests with correct indentation", "app-dir - logging with verbose logging should not contain metadata internal segments for dynamic metadata routes", "app-dir - logging with verbose logging should not contain trailing word page for app router routes", "app-dir - logging with verbose logging should only log requests in dev mode" @@ -3325,6 +3374,17 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/logging/fetch-warning.test.ts": { + "passed": [ + "app-dir - fetch warnings should log when request input is a Request instance", + "app-dir - fetch warnings should log when request input is a string", + "app-dir - fetch warnings should not log when overriding cache within the Request object" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/mdx/mdx.test.ts": { "passed": [ "mdx with-mdx-rs app directory should allow importing client components", @@ -3375,17 +3435,18 @@ "runtimeError": false }, "test/e2e/app-dir/metadata-edge/index.test.ts": { - "passed": [], - "failed": [ + "passed": [ "app dir - Metadata API on the Edge runtime should render OpenGraph image meta tag correctly" ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false }, "test/e2e/app-dir/metadata-missing-metadata-base/index.test.ts": { "passed": [ - "app dir - metadata missing metadataBase should fallback to localhost if metadataBase is missing for absolute urls resolving" + "app dir - metadata missing metadataBase should fallback to localhost if metadataBase is missing for absolute urls resolving", + "app dir - metadata missing metadataBase should warn for unsupported metadata properties" ], "failed": [], "pending": [], @@ -3455,6 +3516,23 @@ ], "runtimeError": false }, + "test/e2e/app-dir/mjs-as-extension/mjs-as-extension.test.ts": { + "passed": ["mjs as extension should render the page correctly"], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, + "test/e2e/app-dir/modularizeimports/modularizeimports.test.ts": { + "passed": [ + "modularizeImports should work", + "modularizeImports should work with MDX" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/navigation/navigation.test.ts": { "passed": [ "app dir - navigation SEO should contain default meta tags in error page", @@ -3479,6 +3557,7 @@ "app dir - navigation not-found should trigger not-found in a server component", "app dir - navigation not-found should trigger not-found while streaming", "app dir - navigation query string should handle unicode search params", + "app dir - navigation query string should not reset shallow url updates on prefetch", "app dir - navigation query string should set query correctly", "app dir - navigation query string useParams identity between renders should be stable in app", "app dir - navigation redirect components should redirect client-side", @@ -3522,12 +3601,14 @@ "app app dir - next-font computed styles should have correct styles at /client", "app app dir - next-font import values should have correct values at /", "app app dir - next-font import values should have correct values at /client", + "app app dir - next-font import values should transform code in node_modules", "app app dir - next-font navigation should not have duplicate preload tags on navigation", "app-old app dir - next-font Dev errors should recover on font loader error", "app-old app dir - next-font computed styles should have correct styles at /", "app-old app dir - next-font computed styles should have correct styles at /client", "app-old app dir - next-font import values should have correct values at /", "app-old app dir - next-font import values should have correct values at /client", + "app-old app dir - next-font import values should transform code in node_modules", "app-old app dir - next-font navigation should not have duplicate preload tags on navigation" ], "pending": [], @@ -3681,8 +3762,8 @@ "parallel-routes-and-interception route intercepting with dynamic routes should render intercepted route" ], "failed": [ - "parallel-routes-and-interception parallel routes should apply the catch-all route to the parallel route if no matching route is found", "parallel-routes-and-interception parallel routes Should match the catch-all routes of the more specific path, If there is more than one catch-all route", + "parallel-routes-and-interception parallel routes should apply the catch-all route to the parallel route if no matching route is found", "parallel-routes-and-interception parallel routes should throw an error when a route groups causes a conflict with a parallel segment" ], "pending": [], @@ -3699,11 +3780,11 @@ "runtimeError": false }, "test/e2e/app-dir/params-hooks-compat/index.test.ts": { - "passed": [], - "failed": [ + "passed": [ "app-dir - params hooks compat should only access path params with useParams", "app-dir - params hooks compat should only access search params with useSearchParams" ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -3723,6 +3804,28 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/ppr-full/ppr-full.test.ts": { + "passed": [ + "ppr-full dynamic pages should resume should resume /", + "ppr-full dynamic pages should resume should resume /loading/a", + "ppr-full dynamic pages should resume should resume /loading/b", + "ppr-full dynamic pages should resume should resume /loading/c", + "ppr-full dynamic pages should resume should resume /nested/a", + "ppr-full dynamic pages should resume should resume /nested/b", + "ppr-full dynamic pages should resume should resume /nested/c", + "ppr-full dynamic pages should resume should resume /no-suspense", + "ppr-full dynamic pages should resume should resume /no-suspense/nested/a", + "ppr-full dynamic pages should resume should resume /no-suspense/nested/b", + "ppr-full dynamic pages should resume should resume /no-suspense/nested/c", + "ppr-full dynamic pages should resume should resume /on-demand/a", + "ppr-full dynamic pages should resume should resume /on-demand/b", + "ppr-full dynamic pages should resume should resume /on-demand/c" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/ppr/ppr.test.ts": { "passed": [ "ppr /no-suspense/node/gsp/[slug] should serve the static & dynamic parts", @@ -3752,6 +3855,16 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/revalidate-dynamic/revalidate-dynamic.test.ts": { + "passed": [ + "app-dir revalidate-dynamic should revalidate the data with /api/revalidate-path", + "app-dir revalidate-dynamic should revalidate the data with /api/revalidate-tag" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/rewrites-redirects/rewrites-redirects.test.ts": { "passed": [ "redirects and rewrites navigation using button should redirect from middleware correctly", @@ -3925,14 +4038,35 @@ "test/e2e/app-dir/set-cookies/set-cookies.test.ts": { "passed": [ "set-cookies for edge runtime for /app should set two set-cookie headers", + "set-cookies for edge runtime for /pages should set two set-cookie headers", "set-cookies for experimental-edge runtime for /app should set two set-cookie headers", + "set-cookies for experimental-edge runtime for /pages should set two set-cookie headers", "set-cookies for node runtime for /app should set two set-cookie headers", "set-cookies for node runtime for /pages should set two set-cookie headers" ], - "failed": [ - "set-cookies for edge runtime for /pages should set two set-cookie headers", - "set-cookies for experimental-edge runtime for /pages should set two set-cookie headers" + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, + "test/e2e/app-dir/shallow-routing/shallow-routing.test.ts": { + "passed": [ + "shallow-routing back and forward client-side navigation should support setting a different pathname reflected on usePathname and then still support navigating back and forward", + "shallow-routing back and forward mpa navigation should support setting data and then still support navigating back and forward", + "shallow-routing pushState should support setting a different pathname reflected on usePathname", + "shallow-routing pushState should support setting a different searchParam reflected on useSearchParams", + "shallow-routing pushState should support setting a different url using a string", + "shallow-routing pushState should support setting data", + "shallow-routing pushState should work when given a null state value", + "shallow-routing replaceState should support setting a different pathname reflected on usePathname", + "shallow-routing replaceState should support setting a different searchParam reflected on useSearchParams", + "shallow-routing replaceState should support setting a different url using a string", + "shallow-routing replaceState should support setting data", + "shallow-routing replaceState should work when given a null state value", + "shallow-routing replaceState should work when given an undefined state value", + "shallow-routing should work when given an undefined state value" ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -4046,7 +4180,11 @@ "runtimeError": false }, "test/e2e/app-dir/x-forwarded-headers/x-forwarded-headers.test.ts": { - "passed": ["x-forwarded-headers should include x-forwarded-* headers"], + "passed": [ + "x-forwarded-headers already assigned should not override existing x-forwarded-* headers", + "x-forwarded-headers host header exists should include x-forwarded-* headers relative to host", + "x-forwarded-headers should include x-forwarded-* headers" + ], "failed": [], "pending": [], "flakey": [], @@ -4086,6 +4224,8 @@ "basePath should handle query/hash correctly during query updating #hello? $search", "basePath should handle query/hash correctly during query updating #hello?world $search", "basePath should have basePath field on Router", + "basePath should have correct href for a link", + "basePath should have correct href for a link to /", "basePath should have correct router paths on first load of /", "basePath should have correct router paths on first load of /hello", "basePath should navigate an absolute local url with basePath", @@ -4125,10 +4265,7 @@ "basePath should work with nested folder with same name as basePath", "basePath should work with normal dynamic page" ], - "failed": [ - "basePath should have correct href for a link", - "basePath should have correct href for a link to /" - ], + "failed": [], "pending": [ "basePath should navigate back to a non-basepath 404 that starts with basepath", "basePath should navigate to nested index page with getStaticProps" @@ -4215,21 +4352,22 @@ "passed": [], "failed": [ "Conflict between app file and pages file should error again when there is new conflict", - "Conflict between app file and pages file should not show error overlay for non conflict pages under app or pages dir", "Conflict between app file and pages file should show error overlay for /", "Conflict between app file and pages file should show error overlay for /another", "Conflict between app file and pages file should support hmr with conflicts" ], "pending": [], - "flakey": [], + "flakey": [ + "Conflict between app file and pages file should not show error overlay for non conflict pages under app or pages dir" + ], "runtimeError": false }, "test/e2e/custom-app-render/custom-app-render.test.ts": { - "passed": [], - "failed": [ + "passed": [ "custom-app-render should render /", "custom-app-render should render /render" ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -4723,23 +4861,21 @@ "runtimeError": false }, "test/e2e/instrumentation-hook-src/instrumentation-hook-src.test.ts": { - "passed": [], - "failed": [], - "pending": [ + "passed": [ "instrumentation-hook-rsc instrumentation should not overlap with a instrumentation page", - "instrumentation-hook-rsc instrumentation should reload the server when the instrumentation hook changes", "instrumentation-hook-rsc instrumentation should run the edge instrumentation compiled version with the edge runtime", "instrumentation-hook-rsc instrumentation should run the instrumentation hook" ], + "failed": [], + "pending": [ + "instrumentation-hook-rsc instrumentation should reload the server when the instrumentation hook changes" + ], "flakey": [], "runtimeError": false }, "test/e2e/instrumentation-hook/instrumentation-hook.test.ts": { - "passed": [], - "failed": [], - "pending": [ + "passed": [ "Instrumentation Hook general should not overlap with a instrumentation page", - "Instrumentation Hook general should reload the server when the instrumentation hook changes", "Instrumentation Hook with-async-edge-page with-async-edge-page should run the instrumentation hook", "Instrumentation Hook with-async-node-page with-async-node-page should run the instrumentation hook", "Instrumentation Hook with-edge-api with-edge-api should run the instrumentation hook", @@ -4748,6 +4884,10 @@ "Instrumentation Hook with-node-api with-node-api should run the instrumentation hook", "Instrumentation Hook with-node-page with-node-page should run the instrumentation hook" ], + "failed": [], + "pending": [ + "Instrumentation Hook general should reload the server when the instrumentation hook changes" + ], "flakey": [], "runtimeError": false }, @@ -5586,6 +5726,7 @@ "skip-trailing-slash-redirect pages dir should navigate client side correctly", "skip-trailing-slash-redirect pages dir should not apply trailing slash redirect (with slash)", "skip-trailing-slash-redirect pages dir should not apply trailing slash redirect (without slash)", + "skip-trailing-slash-redirect pages dir should preserve original trailing slashes to links on client", "skip-trailing-slash-redirect pages dir should respond to dynamic route correctly", "skip-trailing-slash-redirect pages dir should respond to index correctly", "skip-trailing-slash-redirect should allow response body from middleware with flag", @@ -5606,18 +5747,16 @@ "skip-trailing-slash-redirect should parse locale info for data request correctly", "skip-trailing-slash-redirect should provide original _next/data URL with skipMiddlewareUrlNormalize" ], - "failed": [ - "skip-trailing-slash-redirect pages dir should preserve original trailing slashes to links on client" - ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false }, "test/e2e/socket-io/index.test.js": { - "passed": [], - "failed": [ + "passed": [ "socket-io should support socket.io without falling back to polling" ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -6675,6 +6814,7 @@ "CLI Usage dev -h", "CLI Usage dev -p", "CLI Usage dev -p conflict", + "CLI Usage dev -p reserved", "CLI Usage dev NODE_OPTIONS='--inspect'", "CLI Usage dev PORT=0", "CLI Usage dev custom directory", @@ -6696,7 +6836,7 @@ "CLI Usage no command detects command typos", "CLI Usage no command invalid directory" ], - "failed": ["CLI Usage dev -p reserved"], + "failed": [], "pending": [ "CLI Usage production mode start --help", "CLI Usage production mode start --keepAliveTimeout Infinity", @@ -6939,6 +7079,7 @@ "should infer pnpm as the package manager with example", "should infer yarn as the package manager", "should infer yarn as the package manager with example", + "should use Bun as the package manager on supplying --use-bun", "should use Bun as the package manager on supplying --use-bun with example", "should use Yarn as the package manager on supplying --use-yarn", "should use Yarn as the package manager on supplying --use-yarn with example", @@ -6947,7 +7088,7 @@ "should use pnpm as the package manager on supplying --use-pnpm", "should use pnpm as the package manager on supplying --use-pnpm with example" ], - "failed": ["should use Bun as the package manager on supplying --use-bun"], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -7291,11 +7432,11 @@ "runtimeError": false }, "test/integration/custom-page-extension/test/index.test.js": { - "passed": [], - "failed": [ + "passed": [ "Custom page extension dev mode should work dynamic page", "Custom page extension dev mode should work with normal page" ], + "failed": [], "pending": [ "Custom page extension production mode should work dynamic page", "Custom page extension production mode should work with normal page" @@ -8267,11 +8408,12 @@ "runtimeError": false }, "test/integration/edge-runtime-module-errors/test/module-imports.test.js": { - "passed": [], + "passed": [ + "Edge runtime code with imports Edge API importing unused node.js module does not throw in dev at runtime" + ], "failed": [ "Edge runtime code with imports Edge API dynamically importing 3rd party module throws not-found module error in dev at runtime and highlights the faulty line", "Edge runtime code with imports Edge API importing unused 3rd party module throws not-found module error in dev at runtime and highlights the faulty line", - "Edge runtime code with imports Edge API importing unused node.js module does not throw in dev at runtime", "Edge runtime code with imports Edge API statically importing node.js module throws unsupported module error in dev at runtime and highlights the faulty line", "Edge runtime code with imports Middleware dynamically importing 3rd party module throws not-found module error in dev at runtime and highlights the faulty line", "Edge runtime code with imports Middleware importing unused 3rd party module throws not-found module error in dev at runtime and highlights the faulty line", @@ -11105,6 +11247,7 @@ "test/integration/image-optimizer/test/index.test.ts": { "passed": [ "Image Optimizer Server support for trailingSlash in next.config.js should return successful response for original loader", + "Image Optimizer config checks should error when assetPrefix is provided but is invalid", "Image Optimizer config checks should error when deviceSizes contains invalid widths", "Image Optimizer config checks should error when domains length exceeds 50", "Image Optimizer config checks should error when imageSizes contains invalid widths", @@ -11116,6 +11259,7 @@ "Image Optimizer config checks should error when images.loader is assigned but images.path is not", "Image Optimizer config checks should error when images.loaderFile does not exist", "Image Optimizer config checks should error when images.minimumCacheTTL is not valid", + "Image Optimizer config checks should error when images.remotePatterns is invalid", "Image Optimizer config checks should error when images.unoptimized is not a boolean", "Image Optimizer config checks should error when loader contains invalid value", "Image Optimizer config checks should error when remotePatterns has invalid prop", @@ -11983,6 +12127,38 @@ "flakey": [], "runtimeError": false }, + "test/integration/jsconfig-paths-wildcard/test/index.test.js": { + "passed": [], + "failed": [ + "jsconfig paths wildcard default behavior should resolve a wildcard alias", + "jsconfig paths without baseurl wildcard default behavior should resolve a wildcard alias" + ], + "pending": [], + "flakey": [], + "runtimeError": false + }, + "test/integration/jsconfig-paths/test/index.test.js": { + "passed": [ + "jsconfig paths default behavior should alias components", + "jsconfig paths default behavior should resolve a single matching alias", + "jsconfig paths default behavior should resolve the first item in the array first", + "jsconfig paths default behavior should resolve the second item as fallback", + "jsconfig paths without baseurl default behavior should alias components", + "jsconfig paths without baseurl default behavior should resolve a single matching alias", + "jsconfig paths without baseurl default behavior should resolve the first item in the array first", + "jsconfig paths without baseurl default behavior should resolve the second item as fallback" + ], + "failed": [ + "jsconfig paths default behavior should have correct module not found error", + "jsconfig paths without baseurl default behavior should have correct module not found error" + ], + "pending": [ + "jsconfig paths should build production mode should trace correctly", + "jsconfig paths without baseurl should build production mode should trace correctly" + ], + "flakey": [], + "runtimeError": false + }, "test/integration/jsconfig/test/index.test.js": { "passed": [], "failed": [], @@ -12505,21 +12681,20 @@ }, "test/integration/next-image-legacy/unicode/test/index.test.ts": { "passed": [], - "failed": [ + "failed": [], + "pending": [], + "flakey": [ "Image Component Unicode Image URL dev mode should load external image with space", "Image Component Unicode Image URL dev mode should load external unicode image", "Image Component Unicode Image URL dev mode should load internal image with space", "Image Component Unicode Image URL dev mode should load internal unicode image", - "Image Component Unicode Image URL dev mode should load static unicode image" - ], - "pending": [ + "Image Component Unicode Image URL dev mode should load static unicode image", "Image Component Unicode Image URL production mode should load external image with space", "Image Component Unicode Image URL production mode should load external unicode image", "Image Component Unicode Image URL production mode should load internal image with space", "Image Component Unicode Image URL production mode should load internal unicode image", "Image Component Unicode Image URL production mode should load static unicode image" ], - "flakey": [], "runtimeError": false }, "test/integration/next-image-legacy/unoptimized/test/index.test.ts": { @@ -12675,11 +12850,14 @@ "runtimeError": false }, "test/integration/next-image-new/asset-prefix/test/index.test.js": { - "passed": [], + "passed": [ + "Image Component assetPrefix Tests dev mode should not log a deprecation warning about using `images.domains`" + ], "failed": [ "Image Component assetPrefix Tests dev mode should include assetPrefix when placeholder=blur during next dev" ], "pending": [ + "Image Component assetPrefix Tests production mode should not log a deprecation warning about using `images.domains`", "Image Component assetPrefix Tests production mode should use base64 data url with placeholder=blur during next start" ], "flakey": [], @@ -13024,21 +13202,20 @@ }, "test/integration/next-image-new/unicode/test/index.test.ts": { "passed": [], - "failed": [ + "failed": [], + "pending": [], + "flakey": [ "Image Component Unicode Image URL dev mode should load external image with space", "Image Component Unicode Image URL dev mode should load external unicode image", "Image Component Unicode Image URL dev mode should load internal image with space", "Image Component Unicode Image URL dev mode should load internal unicode image", - "Image Component Unicode Image URL dev mode should load static unicode image" - ], - "pending": [ + "Image Component Unicode Image URL dev mode should load static unicode image", "Image Component Unicode Image URL production mode should load external image with space", "Image Component Unicode Image URL production mode should load external unicode image", "Image Component Unicode Image URL production mode should load internal image with space", "Image Component Unicode Image URL production mode should load internal unicode image", "Image Component Unicode Image URL production mode should load static unicode image" ], - "flakey": [], "runtimeError": false }, "test/integration/next-image-new/unoptimized/test/index.test.ts": { @@ -14251,10 +14428,10 @@ "runtimeError": false }, "test/integration/server-asset-modules/test/index.test.js": { - "passed": [], - "failed": [ + "passed": [ "serverside asset modules dev mode should enable reading local files in api routes" ], + "failed": [], "pending": [ "serverside asset modules production mode should enable reading local files in api routes" ], @@ -14263,13 +14440,13 @@ }, "test/integration/server-side-dev-errors/test/index.test.js": { "passed": [ + "server-side dev errors should show server-side error for api route correctly", + "server-side dev errors should show server-side error for dynamic api route correctly", "server-side dev errors should show server-side error for dynamic gssp page correctly", "server-side dev errors should show server-side error for gsp page correctly", "server-side dev errors should show server-side error for gssp page correctly" ], "failed": [ - "server-side dev errors should show server-side error for api route correctly", - "server-side dev errors should show server-side error for dynamic api route correctly", "server-side dev errors should show server-side error for uncaught empty exception correctly", "server-side dev errors should show server-side error for uncaught empty rejection correctly", "server-side dev errors should show server-side error for uncaught exception correctly", @@ -14431,11 +14608,10 @@ }, "test/integration/telemetry/test/page-features.test.js": { "passed": [ + "page features telemetry detects --turbo correctly for `next dev`", "page features telemetry detects --turbo correctly for `next dev` stopped" ], - "failed": [ - "page features telemetry detects --turbo correctly for `next dev`" - ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -14882,14 +15058,14 @@ }, "test/integration/url/test/index.test.js": { "passed": [ + "Handle new URL asset references in next dev should client-render the /ssg page", + "Handle new URL asset references in next dev should client-render the /ssr page", "Handle new URL asset references in next dev should client-render the /static page", "Handle new URL asset references in next dev should render the /ssg page", "Handle new URL asset references in next dev should render the /ssr page", "Handle new URL asset references in next dev should render the /static page", "Handle new URL asset references in next dev should respond on basename api", - "Handle new URL asset references in next dev should respond on size api", - "Handle new URL asset references in next dev should client-render the /ssg page", - "Handle new URL asset references in next dev should client-render the /ssr page" + "Handle new URL asset references in next dev should respond on size api" ], "failed": [], "pending": [ From 87e0b4495a2710a7851a14430738519f27b2ebe4 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Fri, 1 Dec 2023 15:23:43 +0100 Subject: [PATCH 062/189] Fix mixed module swc compilation for app router (#58967) --- packages/next/src/build/handle-externals.ts | 5 ++- packages/next/src/build/swc/options.ts | 21 +++++++++- .../src/build/webpack-config-rules/resolve.ts | 14 +++---- packages/next/src/build/webpack-config.ts | 41 +++++++++++-------- .../build/webpack/loaders/next-swc-loader.ts | 3 ++ .../app-dir/app-external/app-external.test.ts | 18 ++++++++ .../app-external/app/mixed/dynamic/page.js | 12 ++++++ .../app-external/app/mixed/import/client.js | 7 ++++ .../app/mixed/import/mixed-mod.mjs | 5 +++ .../app-external/app/mixed/import/page.js | 15 +++++++ .../mixed-syntax-esm/index.mjs | 14 +++++++ .../mixed-syntax-esm/package.json | 3 ++ .../e2e/app-dir/third-parties/app/gtm/page.js | 2 +- 13 files changed, 131 insertions(+), 29 deletions(-) create mode 100644 test/e2e/app-dir/app-external/app/mixed/dynamic/page.js create mode 100644 test/e2e/app-dir/app-external/app/mixed/import/client.js create mode 100644 test/e2e/app-dir/app-external/app/mixed/import/mixed-mod.mjs create mode 100644 test/e2e/app-dir/app-external/app/mixed/import/page.js create mode 100644 test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/index.mjs create mode 100644 test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/package.json diff --git a/packages/next/src/build/handle-externals.ts b/packages/next/src/build/handle-externals.ts index 9365b50d44282..8c7f4ccc55ce7 100644 --- a/packages/next/src/build/handle-externals.ts +++ b/packages/next/src/build/handle-externals.ts @@ -28,8 +28,9 @@ export function isResourceInPackages( resource: string, packageNames?: string[], packageDirMapping?: Map -) { - return packageNames?.some((p: string) => +): boolean { + if (!packageNames) return false + return packageNames.some((p: string) => packageDirMapping && packageDirMapping.has(p) ? resource.startsWith(packageDirMapping.get(p)! + path.sep) : resource.includes( diff --git a/packages/next/src/build/swc/options.ts b/packages/next/src/build/swc/options.ts index fb9cef6116440..da59be94ec2c3 100644 --- a/packages/next/src/build/swc/options.ts +++ b/packages/next/src/build/swc/options.ts @@ -209,6 +209,22 @@ function getStyledComponentsOptions( } } +/* +Output module type + +For app router where server components is enabled, we prefer to bundle es6 modules, +Use output module es6 to make sure: +- the esm module is present +- if the module is mixed syntax, the esm + cjs code are both present + +For pages router will remain untouched +*/ +function getModuleOptions( + esm: boolean | undefined = false +): { module: { type: 'es6' } } | {} { + return esm ? { module: { type: 'es6' } } : {} +} + function getEmotionOptions( emotionConfig: undefined | boolean | EmotionConfig, development: boolean @@ -319,6 +335,7 @@ export function getLoaderSWCOptions({ relativeFilePathFromRoot, serverComponents, isReactServerLayer, + esm, }: { filename: string development: boolean @@ -338,6 +355,7 @@ export function getLoaderSWCOptions({ supportedBrowsers: string[] | undefined swcCacheDir: string relativeFilePathFromRoot: string + esm?: boolean serverComponents?: boolean isReactServerLayer?: boolean }) { @@ -412,6 +430,7 @@ export function getLoaderSWCOptions({ node: process.versions.node, }, }, + ...getModuleOptions(esm), } } else { const options = { @@ -423,7 +442,7 @@ export function getLoaderSWCOptions({ type: 'commonjs', }, } - : {}), + : getModuleOptions(esm)), disableNextSsg: !isPageFile, isDevelopment: development, isServerCompiler: isServer, diff --git a/packages/next/src/build/webpack-config-rules/resolve.ts b/packages/next/src/build/webpack-config-rules/resolve.ts index f50f6c92ee629..35f9f56969ef4 100644 --- a/packages/next/src/build/webpack-config-rules/resolve.ts +++ b/packages/next/src/build/webpack-config-rules/resolve.ts @@ -12,20 +12,20 @@ export const edgeConditionNames = [ ] const mainFieldsPerCompiler: Record< - CompilerNameValues | 'app-router-server', + CompilerNameValues | 'server-esm', string[] > = { // For default case, prefer CJS over ESM on server side. e.g. pages dir SSR [COMPILER_NAMES.server]: ['main', 'module'], [COMPILER_NAMES.client]: ['browser', 'module', 'main'], [COMPILER_NAMES.edgeServer]: edgeConditionNames, - // For app router since everything is bundled, prefer ESM over CJS - 'app-router-server': ['module', 'main'], + // For bundling-all strategy, prefer ESM over CJS + 'server-esm': ['module', 'main'], } export function getMainField( - pageType: 'app' | 'pages', - compilerType: CompilerNameValues + compilerType: CompilerNameValues, + preferEsm: boolean ) { if (compilerType === COMPILER_NAMES.edgeServer) { return edgeConditionNames @@ -34,7 +34,7 @@ export function getMainField( } // Prefer module fields over main fields for isomorphic packages on server layer - return pageType === 'app' - ? mainFieldsPerCompiler['app-router-server'] + return preferEsm + ? mainFieldsPerCompiler['server-esm'] : mainFieldsPerCompiler[COMPILER_NAMES.server] } diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index a371aa27d1f87..cec79d499fcc9 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -437,17 +437,26 @@ export default async function getBaseWebpackConfig( } } + // RSC loaders, prefer ESM, set `esm` to true const swcServerLayerLoader = getSwcLoader({ serverComponents: true, isReactServerLayer: true, + esm: true, }) const swcClientLayerLoader = getSwcLoader({ serverComponents: true, isReactServerLayer: false, + esm: true, + }) + // Default swc loaders for pages doesn't prefer ESM. + const swcDefaultLoader = getSwcLoader({ + serverComponents: true, + isReactServerLayer: false, + esm: false, }) const defaultLoaders = { - babel: useSWCLoader ? swcClientLayerLoader : babelLoader!, + babel: useSWCLoader ? swcDefaultLoader : babelLoader!, } const swcLoaderForServerLayer = hasAppDir @@ -621,7 +630,7 @@ export default async function getBaseWebpackConfig( } : undefined), // default main fields use pages dir ones, and customize app router ones in loaders. - mainFields: getMainField('pages', compilerType), + mainFields: getMainField(compilerType, false), ...(isEdgeServer && { conditionNames: edgeConditionNames, }), @@ -736,8 +745,13 @@ export default async function getBaseWebpackConfig( const shouldIncludeExternalDirs = config.experimental.externalDir || !!config.transpilePackages - function createLoaderRuleExclude(skipNodeModules: boolean) { - return (excludePath: string) => { + const codeCondition = { + test: /\.(tsx|ts|js|cjs|mjs|jsx)$/, + ...(shouldIncludeExternalDirs + ? // Allowing importing TS/TSX files from outside of the root dir. + {} + : { include: [dir, ...babelIncludeRegexes] }), + exclude: (excludePath: string) => { if (babelIncludeRegexes.some((r) => r.test(excludePath))) { return false } @@ -748,17 +762,8 @@ export default async function getBaseWebpackConfig( ) if (shouldBeBundled) return false - return skipNodeModules && excludePath.includes('node_modules') - } - } - - const codeCondition = { - test: /\.(tsx|ts|js|cjs|mjs|jsx)$/, - ...(shouldIncludeExternalDirs - ? // Allowing importing TS/TSX files from outside of the root dir. - {} - : { include: [dir, ...babelIncludeRegexes] }), - exclude: createLoaderRuleExclude(true), + return excludePath.includes('node_modules') + }, } let webpackConfig: webpack.Configuration = { @@ -1281,7 +1286,7 @@ export default async function getBaseWebpackConfig( ], }, resolve: { - mainFields: getMainField('app', compilerType), + mainFields: getMainField(compilerType, true), conditionNames: reactServerCondition, // If missing the alias override here, the default alias will be used which aliases // react to the direct file path, not the package name. In that case the condition @@ -1416,7 +1421,7 @@ export default async function getBaseWebpackConfig( issuerLayer: [WEBPACK_LAYERS.appPagesBrowser], use: swcLoaderForClientLayer, resolve: { - mainFields: getMainField('app', compilerType), + mainFields: getMainField(compilerType, true), }, }, { @@ -1424,7 +1429,7 @@ export default async function getBaseWebpackConfig( issuerLayer: [WEBPACK_LAYERS.serverSideRendering], use: swcLoaderForClientLayer, resolve: { - mainFields: getMainField('app', compilerType), + mainFields: getMainField(compilerType, true), }, }, ] diff --git a/packages/next/src/build/webpack/loaders/next-swc-loader.ts b/packages/next/src/build/webpack/loaders/next-swc-loader.ts index 511c0773fd63b..aff07d2700b61 100644 --- a/packages/next/src/build/webpack/loaders/next-swc-loader.ts +++ b/packages/next/src/build/webpack/loaders/next-swc-loader.ts @@ -44,6 +44,7 @@ export interface SWCLoaderOptions { swcCacheDir: string serverComponents?: boolean isReactServerLayer?: boolean + esm?: boolean } async function loaderTransform( @@ -69,6 +70,7 @@ async function loaderTransform( swcCacheDir, serverComponents, isReactServerLayer, + esm, } = loaderOptions const isPageFile = filename.startsWith(pagesDir) const relativeFilePathFromRoot = path.relative(rootDir, filename) @@ -92,6 +94,7 @@ async function loaderTransform( relativeFilePathFromRoot, serverComponents, isReactServerLayer, + esm, }) const programmaticOptions = { diff --git a/test/e2e/app-dir/app-external/app-external.test.ts b/test/e2e/app-dir/app-external/app-external.test.ts index dbf044d7324cc..c458ab3397da9 100644 --- a/test/e2e/app-dir/app-external/app-external.test.ts +++ b/test/e2e/app-dir/app-external/app-external.test.ts @@ -210,6 +210,24 @@ createNextDescribe( }) }) + describe('mixed syntax external modules', () => { + it('should handle mixed module with next/dynamic', async () => { + const browser = await next.browser('/mixed/dynamic') + expect(await browser.elementByCss('#component').text()).toContain( + 'mixed-syntax-esm' + ) + }) + + it('should handle mixed module in server and client components', async () => { + const $ = await next.render$('/mixed/import') + expect(await $('#server').text()).toContain('server:mixed-syntax-esm') + expect(await $('#client').text()).toContain('client:mixed-syntax-esm') + expect(await $('#relative-mixed').text()).toContain( + 'relative-mixed-syntax-esm' + ) + }) + }) + it('should export client module references in esm', async () => { const html = await next.render('/esm-client-ref') expect(html).toContain('hello') diff --git a/test/e2e/app-dir/app-external/app/mixed/dynamic/page.js b/test/e2e/app-dir/app-external/app/mixed/dynamic/page.js new file mode 100644 index 0000000000000..65c82ecbb6560 --- /dev/null +++ b/test/e2e/app-dir/app-external/app/mixed/dynamic/page.js @@ -0,0 +1,12 @@ +'use client' + +import dynamic from 'next/dynamic' + +const Dynamic = dynamic( + () => import('mixed-syntax-esm').then((mod) => mod.Component), + { ssr: false } +) + +export default function Page() { + return +} diff --git a/test/e2e/app-dir/app-external/app/mixed/import/client.js b/test/e2e/app-dir/app-external/app/mixed/import/client.js new file mode 100644 index 0000000000000..c5f9320ac7a13 --- /dev/null +++ b/test/e2e/app-dir/app-external/app/mixed/import/client.js @@ -0,0 +1,7 @@ +'use client' + +import { value } from 'mixed-syntax-esm' + +export function Client() { + return 'client:' + value +} diff --git a/test/e2e/app-dir/app-external/app/mixed/import/mixed-mod.mjs b/test/e2e/app-dir/app-external/app/mixed/import/mixed-mod.mjs new file mode 100644 index 0000000000000..327be28b64f12 --- /dev/null +++ b/test/e2e/app-dir/app-external/app/mixed/import/mixed-mod.mjs @@ -0,0 +1,5 @@ +;(module) => { + module.exports = {} +} + +export const value = 'relative-mixed-syntax-esm' diff --git a/test/e2e/app-dir/app-external/app/mixed/import/page.js b/test/e2e/app-dir/app-external/app/mixed/import/page.js new file mode 100644 index 0000000000000..67ce376201f32 --- /dev/null +++ b/test/e2e/app-dir/app-external/app/mixed/import/page.js @@ -0,0 +1,15 @@ +import { value } from 'mixed-syntax-esm' +import { Client } from './client' +import { value as relativeMixedValue } from './mixed-mod.mjs' + +export default function Page() { + return ( + <> +

{'server:' + value}

+

+ +

+

{relativeMixedValue}

+ + ) +} diff --git a/test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/index.mjs b/test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/index.mjs new file mode 100644 index 0000000000000..ca05246cd1486 --- /dev/null +++ b/test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/index.mjs @@ -0,0 +1,14 @@ +import React from 'react' +;(module) => { + module.exports = {} +} + +export const value = 'mixed-syntax-esm' + +export function Component() { + return /*#__PURE__*/ React.createElement( + 'p', + { id: 'component' }, + 'mixed-syntax-esm' + ) +} diff --git a/test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/package.json b/test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/package.json new file mode 100644 index 0000000000000..b6629e247888a --- /dev/null +++ b/test/e2e/app-dir/app-external/node_modules_bak/mixed-syntax-esm/package.json @@ -0,0 +1,3 @@ +{ + "exports": "./index.mjs" +} diff --git a/test/e2e/app-dir/third-parties/app/gtm/page.js b/test/e2e/app-dir/third-parties/app/gtm/page.js index 34d56d8508d59..3662bc2cf72e4 100644 --- a/test/e2e/app-dir/third-parties/app/gtm/page.js +++ b/test/e2e/app-dir/third-parties/app/gtm/page.js @@ -9,7 +9,7 @@ const Page = () => { } return ( -
+

GTM

+ + ) +} diff --git a/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/@modal/default.js b/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/@modal/default.js new file mode 100644 index 0000000000000..e9a7f8c6b8cfa --- /dev/null +++ b/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/@modal/default.js @@ -0,0 +1,3 @@ +export default function Empty() { + return null +} diff --git a/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/layout.js b/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/layout.js new file mode 100644 index 0000000000000..a97ec9e4afad1 --- /dev/null +++ b/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/layout.js @@ -0,0 +1,8 @@ +export default function Layout({ children, modal }) { + return ( + <> + +
{children}
+ + ) +} diff --git a/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/page.js b/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/page.js new file mode 100644 index 0000000000000..3360b339b70ea --- /dev/null +++ b/test/e2e/app-dir/actions/app/interception-routes/(with-modal)/page.js @@ -0,0 +1,5 @@ +import Link from 'next/link' + +export default function InterceptedPage() { + return Open modal +} diff --git a/test/e2e/app-dir/actions/app/interception-routes/test/page.js b/test/e2e/app-dir/actions/app/interception-routes/test/page.js new file mode 100644 index 0000000000000..4ab7d9943e044 --- /dev/null +++ b/test/e2e/app-dir/actions/app/interception-routes/test/page.js @@ -0,0 +1,16 @@ +export default function TestPage() { + async function action(data) { + 'use server' + + console.log('Action Submitted (Page)') + } + + return ( +
+ in "page" + +
+ ) +} From 7d8fab2f4d1eb6a530ad8754031eadadb5bb3775 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Fri, 1 Dec 2023 23:22:14 +0000 Subject: [PATCH 070/189] v14.0.4-canary.35 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index d0baf00e74ee9..1d18673adce94 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.34" + "version": "14.0.4-canary.35" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index d69837450096c..9420155d42a1b 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 8f33f64aec387..d1207e250002c 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.34", + "@next/eslint-plugin-next": "14.0.4-canary.35", "@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 2b1f2c0219b6c..2bd4e5a492d50 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index efd0dcfc015a0..fb52511b0799c 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "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 45f7e767d40c3..cd056c772d6c6 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index eb16810219954..5e75513dfa938 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 853953d1ec066..3d42f0deea926 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 4700f38f24286..ec84e79bb3434 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index d784a527b7a41..57a8fe651bb80 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "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 12b0a7d2fb665..923620bce11a2 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "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 708f43e88b6d8..31c1b091c7013 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index d6cef8f70bb67..26439bc8b8203 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index f0eebbea0789b..f20644d6eae29 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.34", + "@next/env": "14.0.4-canary.35", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.34", - "@next/polyfill-nomodule": "14.0.4-canary.34", - "@next/react-dev-overlay": "14.0.4-canary.34", - "@next/react-refresh-utils": "14.0.4-canary.34", - "@next/swc": "14.0.4-canary.34", + "@next/polyfill-module": "14.0.4-canary.35", + "@next/polyfill-nomodule": "14.0.4-canary.35", + "@next/react-dev-overlay": "14.0.4-canary.35", + "@next/react-refresh-utils": "14.0.4-canary.35", + "@next/swc": "14.0.4-canary.35", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 559c9f57093fa..74248f9cc8b3e 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": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 713b086afdc72..eaad28bb78b72 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "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 e7fcc52348180..1a79f45ab7346 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.34", + "version": "14.0.4-canary.35", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -23,7 +23,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.34", + "next": "14.0.4-canary.35", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 01d4c16ac39ad..a05a9f9d32421 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.34 + specifier: 14.0.4-canary.35 version: link:../next outdent: specifier: 0.8.0 From 43b076620cea3fa799c179e43a0a1666c940f158 Mon Sep 17 00:00:00 2001 From: JJ Kasper Date: Fri, 1 Dec 2023 17:23:50 -0800 Subject: [PATCH 071/189] Fix ssgCacheKey in minimal mode (#59181) This ensures we use the correct `srcPathname` in minimal mode so that we can normalize the URL and generate the correct `ssgCacheKey` which is used for request caching/de-duping. We aren't able to add a reliable test case for this as it is a race condition within a second of a previous request although this was verified against a stress test repro here https://overlapping-segments-h1455lwvk-vtest314-ijjk-testing.vercel.app/repro/tutorials/demo This behavior seems to have regressed in https://github.com/vercel/next.js/pull/45716 Closes NEXT-1777 --- packages/next/src/server/base-server.ts | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index bd8b872095bf2..8e49d9d1c52ee 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -1024,15 +1024,20 @@ export default abstract class Server { matchedPath = denormalizePagePath(matchedPath) let srcPathname = matchedPath - const match = await this.matchers.match(matchedPath, { - i18n: localeAnalysisResult, - }) + let pageIsDynamic = isDynamicRoute(srcPathname) - // Update the source pathname to the matched page's pathname. - if (match) srcPathname = match.definition.pathname + if (!pageIsDynamic) { + const match = await this.matchers.match(srcPathname, { + i18n: localeAnalysisResult, + }) - // The page is dynamic if the params are defined. - const pageIsDynamic = typeof match?.params !== 'undefined' + // Update the source pathname to the matched page's pathname. + if (match) { + srcPathname = match.definition.pathname + // The page is dynamic if the params are defined. + pageIsDynamic = typeof match.params !== 'undefined' + } + } // The rest of this function can't handle i18n properly, so ensure we // restore the pathname with the locale information stripped from it From e7589e05db7eb80cafb09ede74f9d3c8a5759bf8 Mon Sep 17 00:00:00 2001 From: Murat Ogulcan Sahin Date: Sat, 2 Dec 2023 03:35:22 -0500 Subject: [PATCH 072/189] docs:Add react hydration error case. (#59147) --- errors/react-hydration-error.mdx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/errors/react-hydration-error.mdx b/errors/react-hydration-error.mdx index e01b20d7042ae..3f301eeac4665 100644 --- a/errors/react-hydration-error.mdx +++ b/errors/react-hydration-error.mdx @@ -15,7 +15,8 @@ Hydration errors can occur from: 1. Incorrect nesting of HTML tags 1. `

` nested in another `

` tag 2. `

` nested in a `

` tag - 3. [Interactive Content](https://html.spec.whatwg.org/#interactive-content-2) cannot be nested (`` nested in a `` tag, ` +} diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index 4638dba61e735..5bc1830d28c67 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -1459,7 +1459,8 @@ "optimizePackageImports app - should render the icons correctly without creating all the modules", "optimizePackageImports pages - should optimize recursive wildcard export mapping", "optimizePackageImports pages - should render the icons correctly without creating all the modules", - "optimizePackageImports should support visx" + "optimizePackageImports should support visx", + "optimizePackageImports should support MUI" ], "pending": [], "flakey": [], From 2003f5f8489b1a5a12c1eb05d3dd595f6342fe5e Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 5 Dec 2023 16:33:54 +0000 Subject: [PATCH 113/189] v14.0.4-canary.42 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 14d9138d077f4..6cbd8611d3abc 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.41" + "version": "14.0.4-canary.42" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index eb526559abad2..c6e7dcecf3efe 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 9bed74002ddc3..d91c844240f40 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.41", + "@next/eslint-plugin-next": "14.0.4-canary.42", "@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 08127fa5bab24..6f59fb7c3fee5 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index b00bc90ea44a6..3f508b2cfd5d2 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "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 2727155e91b0e..0c49975c656a5 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 1196568eeec6d..c0e6d754584ae 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 3cb5caf7b2b15..a7fd1b8e0631a 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index d401fe692ddcc..493e0abce3d42 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 56c8a3b799a62..6518408bcc3ce 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "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 113392d5f973b..4d3e42c657383 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "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 c6da999132e4d..0b1fc481388f5 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index a083a1001c22f..41adddeaf10be 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 97b0b0358073f..f649dd4c343d9 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.41", + "@next/env": "14.0.4-canary.42", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.41", - "@next/polyfill-nomodule": "14.0.4-canary.41", - "@next/react-dev-overlay": "14.0.4-canary.41", - "@next/react-refresh-utils": "14.0.4-canary.41", - "@next/swc": "14.0.4-canary.41", + "@next/polyfill-module": "14.0.4-canary.42", + "@next/polyfill-nomodule": "14.0.4-canary.42", + "@next/react-dev-overlay": "14.0.4-canary.42", + "@next/react-refresh-utils": "14.0.4-canary.42", + "@next/swc": "14.0.4-canary.42", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 9715030b0ac32..0dc8d34cad62d 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": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index eb7bd749ea4dc..e5274626f30e8 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "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 a103db4e6c02b..52ce3baa0b33c 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.41", + "version": "14.0.4-canary.42", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.41", + "next": "14.0.4-canary.42", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7894bf69d71e6..fe006d2a4a1d0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.41 + specifier: 14.0.4-canary.42 version: link:../next outdent: specifier: 0.8.0 From 78a2eb0b9b031f49eed4867dbbcffe369be98baf Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 5 Dec 2023 08:47:40 -0800 Subject: [PATCH 114/189] fix interception routes with dynamic segments (#59273) ### What? Using an interception marker next to a dynamic segment does not behave properly when deployed to Vercel ### Why? The named route regex that gets created is not accounting for the interception marker, which is causing the non-intercepted route to match the intercepted serverless function. ### How? This factors in the interception marker when building the named route regex so that the non-intercepted route regex properly matches when loading the non-intercepted page. Deployment verified here: https://test-intercept-mu.vercel.app/ Closes NEXT-1786 Fixes #54650 --- .../lib/router/utils/route-regex.test.ts | 12 ++++++++++ .../shared/lib/router/utils/route-regex.ts | 18 ++++++++++++--- .../app/@modal/(.)[username]/[id]/page.tsx | 3 +++ .../app/@modal/default.tsx | 1 + .../app/[username]/[id]/page.tsx | 3 +++ .../app/default.tsx | 3 +++ .../app/layout.tsx | 13 +++++++++++ .../interception-dynamic-segment/app/page.tsx | 9 ++++++++ .../interception-dynamic-segment.test.ts | 23 +++++++++++++++++++ .../next.config.js | 6 +++++ 10 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 test/e2e/app-dir/interception-dynamic-segment/app/@modal/(.)[username]/[id]/page.tsx create mode 100644 test/e2e/app-dir/interception-dynamic-segment/app/@modal/default.tsx create mode 100644 test/e2e/app-dir/interception-dynamic-segment/app/[username]/[id]/page.tsx create mode 100644 test/e2e/app-dir/interception-dynamic-segment/app/default.tsx create mode 100644 test/e2e/app-dir/interception-dynamic-segment/app/layout.tsx create mode 100644 test/e2e/app-dir/interception-dynamic-segment/app/page.tsx create mode 100644 test/e2e/app-dir/interception-dynamic-segment/interception-dynamic-segment.test.ts create mode 100644 test/e2e/app-dir/interception-dynamic-segment/next.config.js diff --git a/packages/next/src/shared/lib/router/utils/route-regex.test.ts b/packages/next/src/shared/lib/router/utils/route-regex.test.ts index 858d750d75223..1b7eb4ae8e8c5 100644 --- a/packages/next/src/shared/lib/router/utils/route-regex.test.ts +++ b/packages/next/src/shared/lib/router/utils/route-regex.test.ts @@ -24,6 +24,18 @@ describe('getNamedRouteRegex', () => { expect(regex.re.test('/photos/(.)next/123')).toBe(true) }) + it('should match named routes correctly when interception markers are adjacent to dynamic segments', () => { + let regex = getNamedRouteRegex('/(.)[author]/[id]', true) + let namedRegexp = new RegExp(regex.namedRegex) + expect(namedRegexp.test('/[author]/[id]')).toBe(false) + expect(namedRegexp.test('/(.)[author]/[id]')).toBe(true) + + regex = getNamedRouteRegex('/(..)(..)[author]/[id]', true) + namedRegexp = new RegExp(regex.namedRegex) + expect(namedRegexp.test('/[author]/[id]')).toBe(false) + expect(namedRegexp.test('/(..)(..)[author]/[id]')).toBe(true) + }) + it('should handle multi-level interception markers', () => { const regex = getNamedRouteRegex('/photos/(..)(..)[author]/[id]', true) diff --git a/packages/next/src/shared/lib/router/utils/route-regex.ts b/packages/next/src/shared/lib/router/utils/route-regex.ts index caf003e99b758..5ec7668fd90f6 100644 --- a/packages/next/src/shared/lib/router/utils/route-regex.ts +++ b/packages/next/src/shared/lib/router/utils/route-regex.ts @@ -97,11 +97,13 @@ function buildGetSafeRouteKey() { } function getSafeKeyFromSegment({ + interceptionMarker, getSafeRouteKey, segment, routeKeys, keyPrefix, }: { + interceptionMarker?: string getSafeRouteKey: () => string segment: string routeKeys: Record @@ -137,11 +139,18 @@ function getSafeKeyFromSegment({ routeKeys[cleanedKey] = key } + // if the segment has an interception marker, make sure that's part of the regex pattern + // this is to ensure that the route with the interception marker doesn't incorrectly match + // the non-intercepted route (ie /app/(.)[username] should not match /app/[username]) + const interceptionPrefix = interceptionMarker + ? escapeStringRegexp(interceptionMarker) + : '' + return repeat ? optional - ? `(?:/(?<${cleanedKey}>.+?))?` - : `/(?<${cleanedKey}>.+?)` - : `/(?<${cleanedKey}>[^/]+?)` + ? `(?:/${interceptionPrefix}(?<${cleanedKey}>.+?))?` + : `/${interceptionPrefix}(?<${cleanedKey}>.+?)` + : `/${interceptionPrefix}(?<${cleanedKey}>[^/]+?)` } function getNamedParametrizedRoute(route: string, prefixRouteKeys: boolean) { @@ -157,8 +166,11 @@ function getNamedParametrizedRoute(route: string, prefixRouteKeys: boolean) { const paramMatches = segment.match(/\[((?:\[.*\])|.+)\]/) // Check for parameters if (hasInterceptionMarker && paramMatches) { + const [usedMarker] = segment.split(paramMatches[0]) + return getSafeKeyFromSegment({ getSafeRouteKey, + interceptionMarker: usedMarker, segment: paramMatches[1], routeKeys, keyPrefix: prefixRouteKeys diff --git a/test/e2e/app-dir/interception-dynamic-segment/app/@modal/(.)[username]/[id]/page.tsx b/test/e2e/app-dir/interception-dynamic-segment/app/@modal/(.)[username]/[id]/page.tsx new file mode 100644 index 0000000000000..7c48f6584136b --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/app/@modal/(.)[username]/[id]/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return 'intercepted' +} diff --git a/test/e2e/app-dir/interception-dynamic-segment/app/@modal/default.tsx b/test/e2e/app-dir/interception-dynamic-segment/app/@modal/default.tsx new file mode 100644 index 0000000000000..ad4e17b5767f9 --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/app/@modal/default.tsx @@ -0,0 +1 @@ +export default () => null diff --git a/test/e2e/app-dir/interception-dynamic-segment/app/[username]/[id]/page.tsx b/test/e2e/app-dir/interception-dynamic-segment/app/[username]/[id]/page.tsx new file mode 100644 index 0000000000000..cab6f9416b983 --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/app/[username]/[id]/page.tsx @@ -0,0 +1,3 @@ +export default function Page() { + return 'not intercepted' +} diff --git a/test/e2e/app-dir/interception-dynamic-segment/app/default.tsx b/test/e2e/app-dir/interception-dynamic-segment/app/default.tsx new file mode 100644 index 0000000000000..86b9e9a388129 --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/app/default.tsx @@ -0,0 +1,3 @@ +export default function Default() { + return null +} diff --git a/test/e2e/app-dir/interception-dynamic-segment/app/layout.tsx b/test/e2e/app-dir/interception-dynamic-segment/app/layout.tsx new file mode 100644 index 0000000000000..6a674f5ea764a --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/app/layout.tsx @@ -0,0 +1,13 @@ +export default function Layout(props: { + children: React.ReactNode + modal: React.ReactNode +}) { + return ( + + +

{props.children}
+ + + + ) +} diff --git a/test/e2e/app-dir/interception-dynamic-segment/app/page.tsx b/test/e2e/app-dir/interception-dynamic-segment/app/page.tsx new file mode 100644 index 0000000000000..9fd53376265da --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/app/page.tsx @@ -0,0 +1,9 @@ +import Link from 'next/link' + +export default function Page() { + return ( +
+ Foo Foo +
+ ) +} diff --git a/test/e2e/app-dir/interception-dynamic-segment/interception-dynamic-segment.test.ts b/test/e2e/app-dir/interception-dynamic-segment/interception-dynamic-segment.test.ts new file mode 100644 index 0000000000000..3eac834fbdc15 --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/interception-dynamic-segment.test.ts @@ -0,0 +1,23 @@ +import { createNextDescribe } from 'e2e-utils' +import { check } from 'next-test-utils' + +createNextDescribe( + 'interception-dynamic-segment', + { + files: __dirname, + }, + ({ next }) => { + it('should work when interception route is paired with a dynamic segment', async () => { + const browser = await next.browser('/') + + await browser.elementByCss('[href="/foo/1"]').click() + await check(() => browser.elementById('modal').text(), /intercepted/) + await browser.refresh() + await check(() => browser.elementById('modal').text(), '') + await check( + () => browser.elementById('children').text(), + /not intercepted/ + ) + }) + } +) diff --git a/test/e2e/app-dir/interception-dynamic-segment/next.config.js b/test/e2e/app-dir/interception-dynamic-segment/next.config.js new file mode 100644 index 0000000000000..807126e4cf0bf --- /dev/null +++ b/test/e2e/app-dir/interception-dynamic-segment/next.config.js @@ -0,0 +1,6 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = {} + +module.exports = nextConfig From 1436a3606e45a104c58d82364090e8340930a6c2 Mon Sep 17 00:00:00 2001 From: Shu Ding Date: Wed, 6 Dec 2023 00:49:51 +0800 Subject: [PATCH 115/189] Clean up builtin `modularizeImports` configs (#59294) Most of them can now be handled by `optimizePackageImports` as I manually tested them locally. The main benefit is that structural updates from these libs won't affect our internal configurations anymore, as they're automatic with the new approach. The little downside is that the automatic way is a bit slower than the `modularizeImports` config as it needs to do extra analyzation. But overall, this is a good direction. Depends on #59254. --- packages/next/src/server/config.ts | 45 +++++------------------------- 1 file changed, 7 insertions(+), 38 deletions(-) diff --git a/packages/next/src/server/config.ts b/packages/next/src/server/config.ts index 3968b19e60a7a..e97e764b3b65b 100644 --- a/packages/next/src/server/config.ts +++ b/packages/next/src/server/config.ts @@ -808,47 +808,9 @@ function assignDefaults( '@mui/icons-material': { transform: '@mui/icons-material/{{member}}', }, - 'date-fns': { - transform: 'date-fns/{{member}}', - }, lodash: { transform: 'lodash/{{member}}', }, - 'lodash-es': { - transform: 'lodash-es/{{member}}', - }, - ramda: { - transform: 'ramda/es/{{member}}', - }, - 'react-bootstrap': { - transform: { - useAccordionButton: - 'modularize-import-loader?name=useAccordionButton&from=named&as=default!react-bootstrap/AccordionButton', - '*': 'react-bootstrap/{{member}}', - }, - }, - antd: { - transform: 'antd/es/{{kebabCase member}}', - }, - ahooks: { - transform: { - createUpdateEffect: - 'modularize-import-loader?name=createUpdateEffect&from=named&as=default!ahooks/es/createUpdateEffect', - '*': 'ahooks/es/{{member}}', - }, - }, - '@ant-design/icons': { - transform: { - IconProvider: - 'modularize-import-loader?name=IconProvider&from=named&as=default!@ant-design/icons', - createFromIconfontCN: '@ant-design/icons/es/components/IconFont', - getTwoToneColor: - 'modularize-import-loader?name=getTwoToneColor&from=named&as=default!@ant-design/icons/es/components/twoTonePrimaryColor', - setTwoToneColor: - 'modularize-import-loader?name=setTwoToneColor&from=named&as=default!@ant-design/icons/es/components/twoTonePrimaryColor', - '*': '@ant-design/icons/lib/icons/{{member}}', - }, - }, 'next/server': { transform: 'next/dist/server/web/exports/{{ kebabCase member }}', }, @@ -863,6 +825,13 @@ function assignDefaults( ...new Set([ ...userProvidedOptimizePackageImports, 'lucide-react', + 'date-fns', + 'lodash-es', + 'ramda', + 'antd', + 'react-bootstrap', + 'ahooks', + '@ant-design/icons', '@headlessui/react', '@headlessui-float/react', '@heroicons/react/20/solid', From 6387c9cbcbaf53adb9fdba1306a5b8a3f76a8cd5 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Tue, 5 Dec 2023 23:22:24 +0000 Subject: [PATCH 116/189] v14.0.4-canary.43 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 6cbd8611d3abc..5e136c52b67bb 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.42" + "version": "14.0.4-canary.43" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index c6e7dcecf3efe..f2e42be16b65c 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index d91c844240f40..bd56c4f074b44 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.42", + "@next/eslint-plugin-next": "14.0.4-canary.43", "@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 6f59fb7c3fee5..a115145aab69c 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 3f508b2cfd5d2..ba174df65a3dd 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "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 0c49975c656a5..f4b871687d792 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index c0e6d754584ae..47764b7a10c52 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index a7fd1b8e0631a..f7535b5c80964 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 493e0abce3d42..93d3330593541 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 6518408bcc3ce..5cca06057f3d7 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "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 4d3e42c657383..204c4a38832b3 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "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 0b1fc481388f5..212b0ac961f37 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 41adddeaf10be..648665cdf944d 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index f649dd4c343d9..41d7aa76bec0b 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.42", + "@next/env": "14.0.4-canary.43", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.42", - "@next/polyfill-nomodule": "14.0.4-canary.42", - "@next/react-dev-overlay": "14.0.4-canary.42", - "@next/react-refresh-utils": "14.0.4-canary.42", - "@next/swc": "14.0.4-canary.42", + "@next/polyfill-module": "14.0.4-canary.43", + "@next/polyfill-nomodule": "14.0.4-canary.43", + "@next/react-dev-overlay": "14.0.4-canary.43", + "@next/react-refresh-utils": "14.0.4-canary.43", + "@next/swc": "14.0.4-canary.43", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 0dc8d34cad62d..94b480d735c1b 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": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index e5274626f30e8..5909160ebaa1d 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "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 52ce3baa0b33c..1c38eb47ab223 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.42", + "version": "14.0.4-canary.43", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.42", + "next": "14.0.4-canary.43", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fe006d2a4a1d0..513a8290d8328 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.42 + specifier: 14.0.4-canary.43 version: link:../next outdent: specifier: 0.8.0 From eab1fe83976f1a5b49f6fc65eef8be8d5f20929f Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 5 Dec 2023 18:10:00 -0700 Subject: [PATCH 117/189] Enable PPR for `dynamic = "force-dynamic"` (#58779) This makes some critical modifications to the app render pipeline when PPR has been enabled for pages with segments defining: ```js export const dynamic = "force-dynamic" ``` Importantly, it no longer modifies the revalidation time to zero for those pages, and now falls back to the provided default revalidation time. When static render occurs, if the page being rendered has a segment config defining `dynamic === "force-dynamic"`, then it will postpone at the root of the component tree. This ensures that no render code is executed for the page, as the entirety of the tree will have postponed. This fixes the bug where the flight prefetch wasn't generated correctly as well. --- .github/workflows/build_and_test.yml | 44 ++++++----- packages/next/src/build/utils.ts | 5 +- .../src/client/components/maybe-postpone.ts | 30 -------- ...tatic-generation-async-storage.external.ts | 12 +-- .../components/static-generation-bailout.ts | 4 +- .../next/src/server/app-render/app-render.tsx | 2 +- .../app-render/create-component-tree.tsx | 73 ++++++++++++++----- ...static-generation-async-storage-wrapper.ts | 18 ++++- packages/next/src/server/base-server.ts | 56 +++++++------- packages/next/src/server/lib/patch-fetch.ts | 27 ++++--- packages/next/src/server/render-result.ts | 38 +++++++--- .../web/spec-extension/unstable-cache.ts | 10 +-- .../e2e/app-dir/app-static/app-static.test.ts | 41 ++++++----- .../[slug]/page.js | 15 +--- .../app/gen-params-dynamic/[slug]/page.js | 15 +--- .../post-method/page.js | 15 +--- .../headers-instance/page.js | 13 +--- .../variable-revalidate/post-method/page.js | 13 +--- .../variable-revalidate/status-code/page.js | 15 +--- .../e2e/app-dir/app-static/lib/fetch-retry.js | 22 ++++++ test/ppr-tests-manifest.json | 30 ++++++-- 21 files changed, 269 insertions(+), 229 deletions(-) delete mode 100644 packages/next/src/client/components/maybe-postpone.ts create mode 100644 test/e2e/app-dir/app-static/lib/fetch-retry.js diff --git a/.github/workflows/build_and_test.yml b/.github/workflows/build_and_test.yml index 9a361911cf58c..375510c625013 100644 --- a/.github/workflows/build_and_test.yml +++ b/.github/workflows/build_and_test.yml @@ -163,10 +163,10 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3, 4, 5] + group: [1/5, 2/5, 3/5, 4/5, 5/5] uses: ./.github/workflows/build_reusable.yml with: - afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 NEXT_E2E_TEST_TIMEOUT=240000 NEXT_TEST_MODE=dev node run-tests.js --test-pattern '^(test\/(development|e2e))/.*\.test\.(js|jsx|ts|tsx)$' --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} + afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 NEXT_E2E_TEST_TIMEOUT=240000 NEXT_TEST_MODE=dev node run-tests.js --test-pattern '^(test\/(development|e2e))/.*\.test\.(js|jsx|ts|tsx)$' --timings -g ${{ matrix.group }} -c ${TEST_CONCURRENCY} secrets: inherit test-turbopack-integration: @@ -177,11 +177,11 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3, 4, 5] + group: [1/5, 2/5, 3/5, 4/5, 5/5] uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 - afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 node run-tests.js --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} --type integration + afterBuild: RUST_BACKTRACE=0 NEXT_EXTERNAL_TESTS_FILTERS="$(pwd)/test/turbopack-tests-manifest.json" TURBOPACK=1 node run-tests.js --timings -g ${{ matrix.group }} -c ${TEST_CONCURRENCY} --type integration secrets: inherit test-next-swc-wasm: @@ -219,10 +219,10 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3] + group: [1/4, 2/4, 3/4, 4/4] uses: ./.github/workflows/build_reusable.yml with: - afterBuild: NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type development + afterBuild: NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }} -c ${TEST_CONCURRENCY} --type development secrets: inherit test-prod: @@ -233,10 +233,10 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3, 4, 5] + group: [1/5, 2/5, 3/5, 4/5, 5/5] uses: ./.github/workflows/build_reusable.yml with: - afterBuild: NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }}/5 -c ${TEST_CONCURRENCY} --type production + afterBuild: NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }} -c ${TEST_CONCURRENCY} --type production secrets: inherit test-integration: @@ -247,11 +247,23 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + group: + - 1/12 + - 2/12 + - 3/12 + - 4/12 + - 5/12 + - 6/12 + - 7/12 + - 8/12 + - 9/12 + - 10/12 + - 11/12 + - 12/12 uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 - afterBuild: node run-tests.js --timings -g ${{ matrix.group }}/12 -c ${TEST_CONCURRENCY} --type integration + afterBuild: node run-tests.js --timings -g ${{ matrix.group }}2 -c ${TEST_CONCURRENCY} --type integration secrets: inherit test-firefox-safari: @@ -273,12 +285,10 @@ jobs: strategy: fail-fast: false - matrix: - group: [1, 2, 3] uses: ./.github/workflows/build_reusable.yml with: nodeVersion: 18.17.0 - afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type integration + afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" node run-tests.js --timings -c ${TEST_CONCURRENCY} --type integration secrets: inherit test-ppr-dev: @@ -289,10 +299,10 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3] + group: [1/4, 2/4, 3/4, 4/4] uses: ./.github/workflows/build_reusable.yml with: - afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type development + afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=dev node run-tests.js --timings -g ${{ matrix.group }} -c ${TEST_CONCURRENCY} --type development secrets: inherit test-ppr-prod: @@ -303,10 +313,10 @@ jobs: strategy: fail-fast: false matrix: - group: [1, 2, 3] + group: [1/4, 2/4, 3/4, 4/4] uses: ./.github/workflows/build_reusable.yml with: - afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }}/3 -c ${TEST_CONCURRENCY} --type production + afterBuild: __NEXT_EXPERIMENTAL_PPR=true NEXT_EXTERNAL_TESTS_FILTERS="test/ppr-tests-manifest.json" NEXT_TEST_MODE=start node run-tests.js --timings -g ${{ matrix.group }} -c ${TEST_CONCURRENCY} --type production secrets: inherit report-test-results: diff --git a/packages/next/src/build/utils.ts b/packages/next/src/build/utils.ts index 643ca58b94036..9accdee7157f1 100644 --- a/packages/next/src/build/utils.ts +++ b/packages/next/src/build/utils.ts @@ -1572,7 +1572,10 @@ export async function isPageStatic({ ) } - if (appConfig.dynamic === 'force-dynamic') { + // If force dynamic was set and we don't have PPR enabled, then set the + // revalidate to 0. + // TODO: (PPR) remove this once PPR is enabled by default + if (appConfig.dynamic === 'force-dynamic' && !ppr) { appConfig.revalidate = 0 } diff --git a/packages/next/src/client/components/maybe-postpone.ts b/packages/next/src/client/components/maybe-postpone.ts deleted file mode 100644 index de216a5a378bc..0000000000000 --- a/packages/next/src/client/components/maybe-postpone.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { StaticGenerationStore } from './static-generation-async-storage.external' - -export function maybePostpone( - staticGenerationStore: StaticGenerationStore, - reason: string -) { - // If we aren't performing a static generation or we aren't using PPR then - // we don't need to postpone. - if ( - !staticGenerationStore.isStaticGeneration || - !staticGenerationStore.experimental.ppr - ) { - return - } - - if (!staticGenerationStore.postpone) { - throw new Error( - 'Invariant: PPR is enabled but the postpone API is unavailable' - ) - } - - // Keep track of if the postpone API has been called. - staticGenerationStore.postponeWasTriggered = true - - staticGenerationStore.postpone( - `This page needs to bail out of prerendering at this point because it used ${reason}. ` + - `React throws this special object to indicate where. It should not be caught by ` + - `your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error` - ) -} diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.external.ts index 1119969c6c275..205143ad7b66a 100644 --- a/packages/next/src/client/components/static-generation-async-storage.external.ts +++ b/packages/next/src/client/components/static-generation-async-storage.external.ts @@ -16,6 +16,13 @@ export interface StaticGenerationStore { readonly isRevalidate?: boolean readonly isUnstableCacheCallback?: boolean + /** + * If defined, this function when called will throw an error postponing + * rendering during the React render phase. This should not be invoked outside + * of the React render phase as it'll throw an error. + */ + readonly postpone: ((reason: string) => never) | undefined + forceDynamic?: boolean fetchCache?: | 'only-cache' @@ -30,7 +37,6 @@ export interface StaticGenerationStore { dynamicShouldError?: boolean pendingRevalidates?: Record> postponeWasTriggered?: boolean - postpone?: (reason: string) => never dynamicUsageDescription?: string dynamicUsageStack?: string @@ -46,10 +52,6 @@ export interface StaticGenerationStore { fetchMetrics?: FetchMetrics isDraftMode?: boolean - - readonly experimental: { - readonly ppr: boolean - } } export type StaticGenerationAsyncStorage = diff --git a/packages/next/src/client/components/static-generation-bailout.ts b/packages/next/src/client/components/static-generation-bailout.ts index 558c2ec763081..df9df4123d085 100644 --- a/packages/next/src/client/components/static-generation-bailout.ts +++ b/packages/next/src/client/components/static-generation-bailout.ts @@ -1,7 +1,6 @@ import type { AppConfigDynamic } from '../../build/utils' import { DynamicServerError } from './hooks-server-context' -import { maybePostpone } from './maybe-postpone' import { staticGenerationAsyncStorage } from './static-generation-async-storage.external' class StaticGenBailoutError extends Error { @@ -47,7 +46,8 @@ export const staticGenerationBailout: StaticGenerationBailout = ( link: 'https://nextjs.org/docs/messages/dynamic-server-error', }) - maybePostpone(staticGenerationStore, reason) + // If postpone is available, we should postpone the render. + staticGenerationStore.postpone?.(reason) // As this is a bailout, we don't want to revalidate, so set the revalidate // to 0. diff --git a/packages/next/src/server/app-render/app-render.tsx b/packages/next/src/server/app-render/app-render.tsx index 407b66af3adeb..a22b23fee4765 100644 --- a/packages/next/src/server/app-render/app-render.tsx +++ b/packages/next/src/server/app-render/app-render.tsx @@ -1119,7 +1119,7 @@ async function renderToHTMLOrFlightImpl( if ( // if PPR is enabled renderOpts.experimental.ppr && - // and a call to `maybePostpone` happened + // and a call to `postpone` happened staticGenerationStore.postponeWasTriggered && // but there's no postpone state !metadata.postponed diff --git a/packages/next/src/server/app-render/create-component-tree.tsx b/packages/next/src/server/app-render/create-component-tree.tsx index 9da1f4e8a148c..12a01c9c63efd 100644 --- a/packages/next/src/server/app-render/create-component-tree.tsx +++ b/packages/next/src/server/app-render/create-component-tree.tsx @@ -1,5 +1,5 @@ import type { FlightSegmentPath, CacheNodeSeedData } from './types' -import React from 'react' +import React, { type ReactNode } from 'react' import { isClientReference } from '../../lib/client-reference' import { getLayoutOrPageModule } from '../lib/app-dir-module' import type { LoaderTree } from '../lib/app-dir-module' @@ -10,10 +10,26 @@ import { createComponentStylesAndScripts } from './create-component-styles-and-s import { getLayerAssets } from './get-layer-assets' import { hasLoadingComponentInTree } from './has-loading-component-in-tree' +type ComponentTree = { + seedData: CacheNodeSeedData + styles: ReactNode +} + /** - * Use the provided loader tree to create the React Component tree. + * This component will call `React.postpone` that throws the postponed error. */ +export const Postpone = ({ + postpone, +}: { + postpone: (reason: string) => never +}): never => { + // Call the postpone API now with the reason set to "force-dynamic". + return postpone('dynamic = "force-dynamic" was used') +} +/** + * Use the provided loader tree to create the React Component tree. + */ export async function createComponentTree({ createSegmentPath, loaderTree: tree, @@ -38,10 +54,7 @@ export async function createComponentTree({ asNotFound?: boolean metadataOutlet?: React.ReactNode ctx: AppRenderContext -}): Promise<{ - seedData: CacheNodeSeedData - styles: React.ReactNode -}> { +}): Promise { const { renderOpts: { nextConfigOutput }, staticGenerationStore, @@ -155,7 +168,13 @@ export async function createComponentTree({ staticGenerationStore.dynamicShouldError = true } else if (dynamic === 'force-dynamic') { staticGenerationStore.forceDynamic = true - staticGenerationBailout(`force-dynamic`, { dynamic }) + + // TODO: (PPR) remove this bailout once PPR is the default + if (!staticGenerationStore.postpone) { + // If the postpone API isn't available, we can't postpone the render and + // therefore we can't use the dynamic API. + staticGenerationBailout(`force-dynamic`, { dynamic }) + } } else { staticGenerationStore.dynamicShouldError = false if (dynamic === 'force-static') { @@ -183,7 +202,10 @@ export async function createComponentTree({ if ( staticGenerationStore.isStaticGeneration && - ctx.defaultRevalidate === 0 + ctx.defaultRevalidate === 0 && + // If the postpone API isn't available, we can't postpone the render and + // therefore we can't use the dynamic API. + !staticGenerationStore.postpone ) { const dynamicUsageDescription = `revalidate: 0 configured ${segment}` staticGenerationStore.dynamicUsageDescription = dynamicUsageDescription @@ -192,10 +214,8 @@ export async function createComponentTree({ } } - if ( - staticGenerationStore?.dynamicUsageErr && - !staticGenerationStore.experimental.ppr - ) { + // If there's a dynamic usage error attached to the store, throw it. + if (staticGenerationStore.dynamicUsageErr) { throw staticGenerationStore.dynamicUsageErr } @@ -391,6 +411,21 @@ export async function createComponentTree({ } } + // If force-dynamic is used and the current render supports postponing, we + // replace it with a node that will postpone the render. This ensures that the + // postpone is invoked during the react render phase and not during the next + // render phase. + if (staticGenerationStore.forceDynamic && staticGenerationStore.postpone) { + return { + seedData: [ + actualSegment, + parallelRouteCacheNodeSeedData, + , + ], + styles: layerAssets, + } + } + const isClientComponent = isClientReference(layoutOrPageMod) // If it's a not found route, and we don't have any matched parallel @@ -453,13 +488,13 @@ export async function createComponentTree({ )} {/* This null is currently critical. The wrapped Component can render null and if there was not fragment - surrounding it this would look like a pending tree data state on the client which will cause an errror - and break the app. Long-term we need to move away from using null as a partial tree identifier since it - is a valid return type for the components we wrap. Once we make this change we can safely remove the - fragment. The reason the extra null here is required is that fragments which only have 1 child are elided. - If the Component above renders null the actual treedata will look like `[null, null]`. If we remove the extra - null it will look like `null` (the array is elided) and this is what confuses the client router. - TODO-APP update router to use a Symbol for partial tree detection */} + surrounding it this would look like a pending tree data state on the client which will cause an error + and break the app. Long-term we need to move away from using null as a partial tree identifier since it + is a valid return type for the components we wrap. Once we make this change we can safely remove the + fragment. The reason the extra null here is required is that fragments which only have 1 child are elided. + If the Component above renders null the actual tree data will look like `[null, null]`. If we remove the extra + null it will look like `null` (the array is elided) and this is what confuses the client router. + TODO-APP update router to use a Symbol for partial tree detection */} {null} , ], 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 18e0076a9f781..f3068d3f3924f 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 @@ -77,8 +77,22 @@ export const StaticGenerationAsyncStorageWrapper: AsyncStorageWrapper< isOnDemandRevalidate: renderOpts.isOnDemandRevalidate, isDraftMode: renderOpts.isDraftMode, - experimental: renderOpts.experimental, - postpone, + + postpone: + // If we aren't performing a static generation or we aren't using PPR then + // we don't need to postpone. + isStaticGeneration && renderOpts.experimental.ppr && postpone + ? (reason: string) => { + // Keep track of if the postpone API has been called. + store.postponeWasTriggered = true + + return postpone( + `This page needs to bail out of prerendering at this point because it used ${reason}. ` + + `React throws this special object to indicate where. It should not be caught by ` + + `your own try/catch. Learn more: https://nextjs.org/docs/messages/ppr-caught-error` + ) + } + : undefined, } // TODO: remove this when we resolve accessing the store outside the execution context diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 8e49d9d1c52ee..2e3933245e84c 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -1886,13 +1886,7 @@ export default abstract class Server { // If we're in minimal mode, then try to get the postponed information from // the request metadata. If available, use it for resuming the postponed // render. - let resumed: { postponed: string } | null = null - if (this.minimalMode) { - const postponed = getRequestMeta(req, 'postponed') - if (postponed) { - resumed = { postponed } - } - } + const minimalPostponed = getRequestMeta(req, 'postponed') // If PPR is enabled, and this is a RSC request (but not a prefetch), then // we can use this fact to only generate the flight data for the request @@ -1921,7 +1915,7 @@ export default abstract class Server { // Server actions can use non-GET/HEAD methods. !isServerAction && // Resume can use non-GET/HEAD methods. - !resumed && + !minimalPostponed && !is404Page && !is500Page && pathname !== '/_error' && @@ -2079,7 +2073,7 @@ export default abstract class Server { isSSG && !opts.supportsDynamicHTML && !isServerAction && - !resumed && + !minimalPostponed && !isDynamicRSCRequest ) { ssgCacheKey = `${locale ? `/${locale}` : ''}${ @@ -2142,11 +2136,15 @@ export default abstract class Server { const { routeModule } = components - type Renderer = ( + type Renderer = (context: { + /** + * The postponed data for this render. This is only provided when resuming + * a render that has been postponed. + */ postponed: string | undefined - ) => Promise + }) => Promise - const doRender: Renderer = async (postponed) => { + const doRender: Renderer = async ({ postponed }) => { // In development, we always want to generate dynamic HTML. const supportsDynamicHTML: boolean = // If this isn't a data request and we're not in development, then we @@ -2157,7 +2155,7 @@ export default abstract class Server { (!isSSG && !hasStaticPaths) || // If this request has provided postponed data, it supports dynamic // HTML. - !!postponed || + typeof postponed === 'string' || // If this is a dynamic RSC request, then this render supports dynamic // HTML (it's dynamic). isDynamicRSCRequest @@ -2186,7 +2184,11 @@ export default abstract class Server { ...(isAppPath ? { incrementalCache, - isRevalidate: isSSG, + // This is a revalidation request if the request is for a static + // page and it is not being resumed from a postponed render and + // it is not a dynamic RSC request then it is a revalidation + // request. + isRevalidate: isSSG && !postponed && !isDynamicRSCRequest, originalPathname: components.ComponentMod.originalPathname, serverActions: this.nextConfig.experimental.serverActions, } @@ -2386,7 +2388,8 @@ export default abstract class Server { isAppPath && isSSG && metadata.revalidate === 0 && - !this.renderOpts.dev + !this.renderOpts.dev && + !renderOpts.experimental.ppr ) { const staticBailoutInfo = metadata.staticBailoutInfo @@ -2489,12 +2492,6 @@ export default abstract class Server { isOnDemandRevalidate = true } - // Only requests that aren't revalidating can be resumed. - const postponed = - !isOnDemandRevalidate && !isRevalidating && resumed - ? resumed.postponed - : undefined - // only allow on-demand revalidate for fallback: true/blocking // or for prerendered fallback: false paths if ( @@ -2577,7 +2574,7 @@ export default abstract class Server { // We pass `undefined` as there cannot be a postponed state in // development. - const result = await doRender(undefined) + const result = await doRender({ postponed: undefined }) if (!result) { return null } @@ -2588,7 +2585,14 @@ export default abstract class Server { } } - const result = await doRender(postponed) + const result = await doRender({ + // Only requests that aren't revalidating can be resumed. If we have the + // minimal postponed data, then we should resume the render with it. + postponed: + !isOnDemandRevalidate && !isRevalidating && minimalPostponed + ? minimalPostponed + : undefined, + }) if (!result) { return null } @@ -2648,7 +2652,7 @@ export default abstract class Server { // If this is a resume request in minimal mode it is streamed with dynamic // content and should not be cached. - if (this.minimalMode && resumed?.postponed) { + if (minimalPostponed) { revalidate = 0 } @@ -2765,7 +2769,7 @@ export default abstract class Server { } else if (isAppPath) { // If the request has a postponed state and it's a resume request we // should error. - if (cachedData.postponed && resumed) { + if (cachedData.postponed && minimalPostponed) { throw new Error( 'Invariant: postponed state should not be present on a resume request' ) @@ -2875,7 +2879,7 @@ export default abstract class Server { // Perform the render again, but this time, provide the postponed state. // We don't await because we want the result to start streaming now, and // we've already chained the transformer's readable to the render result. - doRender(cachedData.postponed) + doRender({ postponed: cachedData.postponed }) .then(async (result) => { if (!result) { throw new Error('Invariant: expected a result to be returned') diff --git a/packages/next/src/server/lib/patch-fetch.ts b/packages/next/src/server/lib/patch-fetch.ts index d90e2ba11640a..8efbc228aea63 100644 --- a/packages/next/src/server/lib/patch-fetch.ts +++ b/packages/next/src/server/lib/patch-fetch.ts @@ -12,7 +12,6 @@ import { NEXT_CACHE_TAG_MAX_LENGTH, } from '../../lib/constants' import * as Log from '../../build/output/log' -import { maybePostpone } from '../../client/components/maybe-postpone' const isEdgeRuntime = process.env.NEXT_RUNTIME === 'edge' @@ -372,15 +371,19 @@ export function patchFetch({ // we don't consider autoNoCache to switch to dynamic during // revalidate although if it occurs during build we do !autoNoCache && + // If the revalidate value isn't currently set or the value is less + // than the current revalidate value, we should update the revalidate + // value. (typeof staticGenerationStore.revalidate === 'undefined' || (typeof revalidate === 'number' && (staticGenerationStore.revalidate === false || (typeof staticGenerationStore.revalidate === 'number' && revalidate < staticGenerationStore.revalidate)))) ) { - // If enabled, we should bail out of static generation. + // If we were setting the revalidate value to 0, we should try to + // postpone instead first. if (revalidate === 0) { - maybePostpone(staticGenerationStore, 'revalidate: 0') + staticGenerationStore.postpone?.('revalidate: 0') } staticGenerationStore.revalidate = revalidate @@ -594,17 +597,17 @@ export function patchFetch({ ? ` ${staticGenerationStore.urlPathname}` : '' }` - const err = new DynamicServerError(dynamicUsageReason) - staticGenerationStore.dynamicUsageErr = err - staticGenerationStore.dynamicUsageStack = err.stack - staticGenerationStore.dynamicUsageDescription = dynamicUsageReason // If enabled, we should bail out of static generation. - maybePostpone(staticGenerationStore, dynamicUsageReason) + staticGenerationStore.postpone?.(dynamicUsageReason) // PPR is not enabled, or React postpone is not available, we // should set the revalidate to 0. staticGenerationStore.revalidate = 0 + + const err = new DynamicServerError(dynamicUsageReason) + staticGenerationStore.dynamicUsageErr = err + staticGenerationStore.dynamicUsageDescription = dynamicUsageReason } const hasNextConfig = 'next' in init @@ -623,13 +626,13 @@ export function patchFetch({ ? ` ${staticGenerationStore.urlPathname}` : '' }` + + // If enabled, we should bail out of static generation. + staticGenerationStore.postpone?.(dynamicUsageReason) + const err = new DynamicServerError(dynamicUsageReason) staticGenerationStore.dynamicUsageErr = err - staticGenerationStore.dynamicUsageStack = err.stack staticGenerationStore.dynamicUsageDescription = dynamicUsageReason - - // If enabled, we should bail out of static generation. - maybePostpone(staticGenerationStore, dynamicUsageReason) } if (!forceDynamic || next.revalidate !== 0) { diff --git a/packages/next/src/server/render-result.ts b/packages/next/src/server/render-result.ts index 6f9f87d0f6f50..2e8b1379b35c6 100644 --- a/packages/next/src/server/render-result.ts +++ b/packages/next/src/server/render-result.ts @@ -204,22 +204,42 @@ export default class RenderResult< /** * Pipes the response to a writable stream. This will close/cancel the - * writable stream if an error is encountered. + * writable stream if an error is encountered. If this doesn't throw, then + * the writable stream will be closed or aborted. * * @param writable Writable stream to pipe the response to */ public async pipeTo(writable: WritableStream): Promise { try { - await this.readable.pipeTo(writable) + await this.readable.pipeTo(writable, { + // We want to close the writable stream ourselves so that we can wait + // for the waitUntil promise to resolve before closing it. If an error + // is encountered, we'll abort the writable stream if we swallowed the + // error. + preventClose: true, + }) + + // If there is a waitUntil promise, wait for it to resolve before + // closing the writable stream. + if (this.waitUntil) await this.waitUntil + + // Close the writable stream. + await writable.close() } catch (err) { - // If this isn't a client abort, then re-throw the error. - if (!isAbortError(err)) { - throw err - } - } finally { - if (this.waitUntil) { - await this.waitUntil + // If this is an abort error, we should abort the writable stream (as we + // took ownership of it when we started piping). We don't need to re-throw + // because we handled the error. + if (isAbortError(err)) { + // Abort the writable stream if an error is encountered. + await writable.abort(err) + + return } + + // We're not aborting the writer here as when this method throws it's not + // clear as to how so the caller should assume it's their responsibility + // to clean up the writer. + throw err } } 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 237bdf1688a28..5ac1d458bd322 100644 --- a/packages/next/src/server/web/spec-extension/unstable-cache.ts +++ b/packages/next/src/server/web/spec-extension/unstable-cache.ts @@ -1,8 +1,8 @@ -import { maybePostpone } from '../../../client/components/maybe-postpone' import type { StaticGenerationStore, StaticGenerationAsyncStorage, } from '../../../client/components/static-generation-async-storage.external' + import { staticGenerationAsyncStorage as _staticGenerationAsyncStorage } from '../../../client/components/static-generation-async-storage.external' import { CACHE_ONE_YEAR } from '../../../lib/constants' import { addImplicitTags, validateTags } from '../../lib/patch-fetch' @@ -33,7 +33,9 @@ export function unstable_cache( if (store && typeof options.revalidate === 'number') { // Revalidate 0 is a special case, it means opt-out of static generation. if (options.revalidate === 0) { - maybePostpone(store, 'revalidate: 0') + // If postpone is supported we should postpone the render. + store.postpone?.('revalidate: 0') + // Set during dynamic rendering store.revalidate = 0 // If revalidate was already set in the store before we should check if the new value is lower, set it to the lowest of the two. @@ -75,9 +77,7 @@ export function unstable_cache( urlPathname: store?.urlPathname || '/', isUnstableCacheCallback: true, isStaticGeneration: store?.isStaticGeneration === true, - experimental: { - ppr: store?.experimental?.ppr === true, - }, + postpone: store?.postpone, }, async () => { const tags = validateTags( diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index 6ab4bf5267757..a2efc37dee287 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -1705,35 +1705,38 @@ createNextDescribe( { path: '/stale-cache-serving-edge/app-page' }, { path: '/stale-cache-serving-edge/route-handler' }, ])('should stream properly for $path', async ({ path }) => { - // prime cache initially - await next.fetch(path) + // Prime the cache. + let res = await next.fetch(path) + expect(res.status).toBe(200) + + // Consume the cache, the revalidations are completed on the end of the + // stream so we need to wait for that to complete. + await res.text() for (let i = 0; i < 6; i++) { await waitFor(1000) - const start = Date.now() - let streamStart = 0 - const res = await next.fetch(path) - const chunks: any[] = [] - await new Promise((bodyResolve) => { - res.body.on('data', (chunk) => { - if (!streamStart) { - streamStart = Date.now() + const timings = { + start: Date.now(), + startedStreaming: 0, + } + + res = await next.fetch(path) + + // eslint-disable-next-line no-loop-func + await new Promise((resolve) => { + res.body.on('data', () => { + if (!timings.startedStreaming) { + timings.startedStreaming = Date.now() } - chunks.push(chunk) }) res.body.on('end', () => { - bodyResolve() + resolve() }) }) - require('console').log({ - start, - duration: Date.now() - start, - streamStart, - startDuration: streamStart - start, - }) - expect(streamStart - start).toBeLessThan(3000) + + expect(timings.startedStreaming - timings.start).toBeLessThan(3000) } }) diff --git a/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js b/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js index 7476245fbf597..23b94efed6e8c 100644 --- a/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js +++ b/test/e2e/app-dir/app-static/app/gen-params-dynamic-revalidate/[slug]/page.js @@ -1,22 +1,11 @@ +import { fetchRetry } from '../../../lib/fetch-retry' + export const revalidate = 3 export async function generateStaticParams() { return [{ slug: 'one' }] } -const fetchRetry = async (url, init) => { - for (let i = 0; i < 5; i++) { - try { - return await fetch(url, init) - } catch (err) { - if (i === 4) { - throw err - } - console.log(`Failed to fetch`, err, `retrying...`) - } - } -} - export default async function page({ params }) { const { slug } = params let data diff --git a/test/e2e/app-dir/app-static/app/gen-params-dynamic/[slug]/page.js b/test/e2e/app-dir/app-static/app/gen-params-dynamic/[slug]/page.js index a2877f298b44e..f9d5366ea389b 100644 --- a/test/e2e/app-dir/app-static/app/gen-params-dynamic/[slug]/page.js +++ b/test/e2e/app-dir/app-static/app/gen-params-dynamic/[slug]/page.js @@ -1,20 +1,9 @@ +import { fetchRetry } from '../../../lib/fetch-retry' + export async function generateStaticParams() { return [{ slug: 'one' }] } -const fetchRetry = async (url, init) => { - for (let i = 0; i < 5; i++) { - try { - return await fetch(url, init) - } catch (err) { - if (i === 4) { - throw err - } - console.log(`Failed to fetch`, err, `retrying...`) - } - } -} - export default async function page({ params }) { const { slug } = params const data = await fetchRetry( diff --git a/test/e2e/app-dir/app-static/app/variable-revalidate-edge/post-method/page.js b/test/e2e/app-dir/app-static/app/variable-revalidate-edge/post-method/page.js index d8ae4909afa4b..0ca937144c965 100644 --- a/test/e2e/app-dir/app-static/app/variable-revalidate-edge/post-method/page.js +++ b/test/e2e/app-dir/app-static/app/variable-revalidate-edge/post-method/page.js @@ -1,17 +1,6 @@ -export const runtime = 'experimental-edge' +import { fetchRetry } from '../../../lib/fetch-retry' -const fetchRetry = async (url, init) => { - for (let i = 0; i < 5; i++) { - try { - return await fetch(url, init) - } catch (err) { - if (i === 4) { - throw err - } - console.log(`Failed to fetch`, err, `retrying...`) - } - } -} +export const runtime = 'experimental-edge' export default async function Page() { const data = await fetchRetry( diff --git a/test/e2e/app-dir/app-static/app/variable-revalidate/headers-instance/page.js b/test/e2e/app-dir/app-static/app/variable-revalidate/headers-instance/page.js index 0798d79dd6d74..870fc9f6b4477 100644 --- a/test/e2e/app-dir/app-static/app/variable-revalidate/headers-instance/page.js +++ b/test/e2e/app-dir/app-static/app/variable-revalidate/headers-instance/page.js @@ -1,15 +1,4 @@ -const fetchRetry = async (url, init) => { - for (let i = 0; i < 5; i++) { - try { - return await fetch(url, init) - } catch (err) { - if (i === 4) { - throw err - } - console.log(`Failed to fetch`, err, `retrying...`) - } - } -} +import { fetchRetry } from '../../../lib/fetch-retry' export default async function Page() { const data = await fetchRetry( diff --git a/test/e2e/app-dir/app-static/app/variable-revalidate/post-method/page.js b/test/e2e/app-dir/app-static/app/variable-revalidate/post-method/page.js index ffb942c08bf56..72637db68c414 100644 --- a/test/e2e/app-dir/app-static/app/variable-revalidate/post-method/page.js +++ b/test/e2e/app-dir/app-static/app/variable-revalidate/post-method/page.js @@ -1,15 +1,4 @@ -const fetchRetry = async (url, init) => { - for (let i = 0; i < 5; i++) { - try { - return await fetch(url, init) - } catch (err) { - if (i === 4) { - throw err - } - console.log(`Failed to fetch`, err, `retrying...`) - } - } -} +import { fetchRetry } from '../../../lib/fetch-retry' export default async function Page() { const data = await fetchRetry( diff --git a/test/e2e/app-dir/app-static/app/variable-revalidate/status-code/page.js b/test/e2e/app-dir/app-static/app/variable-revalidate/status-code/page.js index 884a6c3da6eee..89a380f33b46d 100644 --- a/test/e2e/app-dir/app-static/app/variable-revalidate/status-code/page.js +++ b/test/e2e/app-dir/app-static/app/variable-revalidate/status-code/page.js @@ -1,17 +1,6 @@ -export const revalidate = 0 +import { fetchRetry } from '../../../lib/fetch-retry' -const fetchRetry = async (url, init) => { - for (let i = 0; i < 5; i++) { - try { - return await fetch(url, init) - } catch (err) { - if (i === 4) { - throw err - } - console.log(`Failed to fetch`, err, `retrying...`) - } - } -} +export const revalidate = 0 export default async function Page() { const data = await fetchRetry( diff --git a/test/e2e/app-dir/app-static/lib/fetch-retry.js b/test/e2e/app-dir/app-static/lib/fetch-retry.js new file mode 100644 index 0000000000000..3f83f558f5df7 --- /dev/null +++ b/test/e2e/app-dir/app-static/lib/fetch-retry.js @@ -0,0 +1,22 @@ +const MAX_ATTEMPTS = 5 + +export const fetchRetry = async (url, init) => { + for (let i = 0; i < MAX_ATTEMPTS; i++) { + try { + return await fetch(url, init) + } catch (err) { + // FIXME: (PPR) this is a workaround until we have a way to detect postpone errors + // For PPR, we need to detect if this is a postpone error so we can + // re-throw it. + if (err.$$typeof === Symbol.for('react.postpone')) { + throw err + } + + if (i === MAX_ATTEMPTS - 1) { + throw err + } + + console.log(`Failed to fetch`, err, `retrying...`) + } + } +} diff --git a/test/ppr-tests-manifest.json b/test/ppr-tests-manifest.json index faaa19186704e..245e69a789749 100644 --- a/test/ppr-tests-manifest.json +++ b/test/ppr-tests-manifest.json @@ -1,6 +1,14 @@ { "version": 2, "suites": { + "test/e2e/app-dir/app-static/app-static.test.ts": { + "failed": [ + "app-dir static/dynamic handling usePathname should have values from canonical url on rewrite", + "app-dir static/dynamic handling should have correct prerender-manifest entries", + "app-dir static/dynamic handling should output HTML/RSC files for static paths", + "app-dir static/dynamic handling should output debug info for static bailouts" + ] + }, "test/e2e/app-dir/app-client-cache/client-cache.test.ts": { "failed": [ "app dir client cache semantics prefetch={undefined} - default should re-use the full cache for only 30 seconds", @@ -37,6 +45,22 @@ "app dir - rsc basics should render server components correctly" ] }, + "test/e2e/app-dir/navigation/navigation.test.ts": { + "failed": [ + "app dir - navigation redirect status code should respond with 308 status code if permanent flag is set", + "app dir - navigation redirect status code should respond with 307 status code in client component", + "app dir - navigation redirect status code should respond with 307 status code in server component", + "app dir - navigation bots should block rendering for bots and return 404 status", + "app dir - navigation navigation between pages and app should not continously initiate a mpa navigation to the same URL when router state changes" + ] + }, + "test/e2e/app-dir/app-static/app-static-custom-handler.test.ts": { + "failed": [ + "app-dir static/dynamic handling should output debug info for static bailouts", + "app-dir static/dynamic handling should have correct prerender-manifest entries", + "app-dir static/dynamic handling should output HTML/RSC files for static paths" + ] + }, "test/production/app-dir/unexpected-error/unexpected-error.test.ts": { "failed": [ "unexpected-error should set response status to 500 for unexpected errors in ssr app route", @@ -57,11 +81,7 @@ "test/e2e/app-dir/ppr/**/*", "test/e2e/app-dir/app-prefetch*/**/*", "test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts", - "test/e2e/app-dir/searchparams-static-bailout/searchparams-static-bailout.test.ts", - "test/e2e/app-dir/app-static/app-static-custom-handler.test.ts", - "test/e2e/app-dir/app-static/app-static.test.ts", - "test/e2e/app-dir/app-static/app-static-custom-cache-handler-esm.test.ts", - "test/e2e/app-dir/navigation/navigation.test.ts" + "test/e2e/app-dir/searchparams-static-bailout/searchparams-static-bailout.test.ts" ] } } From 873bd82ff96b60e84d2a419d43f0428a0a8e0cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mustafa=20=C3=87or?= Date: Wed, 6 Dec 2023 06:21:56 +0300 Subject: [PATCH 118/189] docs: Server Action example (#59159) --- .../02-api-reference/04-functions/revalidateTag.mdx | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/02-app/02-api-reference/04-functions/revalidateTag.mdx b/docs/02-app/02-api-reference/04-functions/revalidateTag.mdx index 2af2cb5a06fb3..5174116dcdbd2 100644 --- a/docs/02-app/02-api-reference/04-functions/revalidateTag.mdx +++ b/docs/02-app/02-api-reference/04-functions/revalidateTag.mdx @@ -43,6 +43,17 @@ export default async function submit() { } ``` +```js filename="app/actions.js" switcher +'use server' + +import { revalidateTag } from 'next/cache' + +export default async function submit() { + await addPost() + revalidateTag('posts') +} +``` + ### Route Handler ```ts filename="app/api/revalidate/route.ts" switcher From caa05b4753685b3e8dbb79781d6137a8c8bfbe17 Mon Sep 17 00:00:00 2001 From: Jiwon Choi Date: Wed, 6 Dec 2023 12:30:27 +0900 Subject: [PATCH 119/189] docs: Remove invalid URL (#58823) This PR removes guidance to invalid URL --- .../01-building-your-application/05-optimizing/10-testing.mdx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/03-pages/01-building-your-application/05-optimizing/10-testing.mdx b/docs/03-pages/01-building-your-application/05-optimizing/10-testing.mdx index 80f3345e90338..b5dbf85eb8384 100644 --- a/docs/03-pages/01-building-your-application/05-optimizing/10-testing.mdx +++ b/docs/03-pages/01-building-your-application/05-optimizing/10-testing.mdx @@ -535,7 +535,3 @@ The Next.js community has created packages and articles you may find helpful: - [next-router-mock](https://github.com/scottrippey/next-router-mock) for Storybook. - [Test Preview Vercel Deploys with Cypress](https://glebbahmutov.com/blog/develop-preview-test/) by Gleb Bahmutov. - -For more information on what to read next, we recommend: - - - pages/basic-features/environment-variables#test-environment-variables From 75975dd5e4f85be24e19b689dc1a16213b1f59d1 Mon Sep 17 00:00:00 2001 From: Willem-Jaap <67187467+Willem-Jaap@users.noreply.github.com> Date: Wed, 6 Dec 2023 04:31:58 +0100 Subject: [PATCH 120/189] docs: Fix incorrect prop name in client component (#58591) `updateItem` is the name of the action, not the passed prop. The correct property name is `myAction`. --- docs/02-app/02-api-reference/04-functions/server-actions.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/02-app/02-api-reference/04-functions/server-actions.mdx b/docs/02-app/02-api-reference/04-functions/server-actions.mdx index 01c275d6c3ead..bd29d63003315 100644 --- a/docs/02-app/02-api-reference/04-functions/server-actions.mdx +++ b/docs/02-app/02-api-reference/04-functions/server-actions.mdx @@ -76,9 +76,9 @@ In some cases, you might want to pass down a Server Action to a Client Component ```jsx filename="app/client-component.jsx" 'use client' -export default function ClientComponent({ updateItem }) { +export default function ClientComponent({ myAction }) { return ( -
+
From d0159160dca04e6c801c82fde38bc7e932fa577d Mon Sep 17 00:00:00 2001 From: Jackie <102015496+JackieLi565@users.noreply.github.com> Date: Tue, 5 Dec 2023 22:33:14 -0500 Subject: [PATCH 121/189] docs: update Firebase link to `with-firebase` example (#58621) --- .../01-routing/09-authenticating.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/03-pages/01-building-your-application/01-routing/09-authenticating.mdx b/docs/03-pages/01-building-your-application/01-routing/09-authenticating.mdx index 4995c92433564..3d904406955db 100644 --- a/docs/03-pages/01-building-your-application/01-routing/09-authenticating.mdx +++ b/docs/03-pages/01-building-your-application/01-routing/09-authenticating.mdx @@ -130,7 +130,7 @@ To see examples with other authentication providers, check out the [examples fol - [Auth0](https://github.com/vercel/next.js/tree/canary/examples/auth0) - [Clerk](https://github.com/vercel/next.js/tree/canary/examples/with-clerk) -- [Firebase](https://github.com/vercel/next.js/tree/canary/examples/with-firebase-authentication) +- [Firebase](https://github.com/vercel/next.js/tree/canary/examples/with-firebase) - [Magic](https://github.com/vercel/next.js/tree/canary/examples/with-magic) - [Nhost](https://github.com/vercel/next.js/tree/canary/examples/with-nhost-auth-realtime-graphql) - [Ory](https://github.com/vercel/examples/tree/main/solutions/auth-with-ory) From 3caa2891c786e9c909c917789f8bac7e9fbc2ec8 Mon Sep 17 00:00:00 2001 From: Thoushif Aazam Shaik Date: Tue, 5 Dec 2023 21:33:47 -0600 Subject: [PATCH 122/189] docs: added missing comma to the props list (#58596) --- docs/02-app/02-api-reference/02-file-conventions/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/02-app/02-api-reference/02-file-conventions/page.mdx b/docs/02-app/02-api-reference/02-file-conventions/page.mdx index e1cfa04de45b0..f32a65caeff66 100644 --- a/docs/02-app/02-api-reference/02-file-conventions/page.mdx +++ b/docs/02-app/02-api-reference/02-file-conventions/page.mdx @@ -10,7 +10,7 @@ export default function Page({ params, searchParams, }: { - params: { slug: string } + params: { slug: string }, searchParams: { [key: string]: string | string[] | undefined } }) { return

My Page

From 4a5226890746174c60146d1d7e5e5227d8b224ef Mon Sep 17 00:00:00 2001 From: Peter Kellner Date: Tue, 5 Dec 2023 19:34:19 -0800 Subject: [PATCH 123/189] docs: Update route handles TS code snippets (#59021) --- .../01-routing/10-route-handlers.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/02-app/01-building-your-application/01-routing/10-route-handlers.mdx b/docs/02-app/01-building-your-application/01-routing/10-route-handlers.mdx index 3da9d0cb5a2e0..a79988e1bf5a9 100644 --- a/docs/02-app/01-building-your-application/01-routing/10-route-handlers.mdx +++ b/docs/02-app/01-building-your-application/01-routing/10-route-handlers.mdx @@ -99,7 +99,7 @@ export async function GET(request: Request) { const res = await fetch(`https://data.mongodb-api.com/product/${id}`, { headers: { 'Content-Type': 'application/json', - 'API-Key': process.env.DATA_API_KEY, + 'API-Key': process.env.DATA_API_KEY!, }, }) const product = await res.json() @@ -132,7 +132,7 @@ export async function POST() { method: 'POST', headers: { 'Content-Type': 'application/json', - 'API-Key': process.env.DATA_API_KEY, + 'API-Key': process.env.DATA_API_KEY!, }, body: JSON.stringify({ time: new Date().toISOString() }), }) From 3f20b46b59c6a91fed562cffc842e1db79727539 Mon Sep 17 00:00:00 2001 From: Justin Pfifer <61801015+jpfifer@users.noreply.github.com> Date: Tue, 5 Dec 2023 20:34:37 -0700 Subject: [PATCH 124/189] docs: Add note about middleware and runtimes (#58873) Co-authored-by: Justin Pfifer Co-authored-by: Lee Robinson --- .../01-building-your-application/01-routing/11-middleware.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/02-app/01-building-your-application/01-routing/11-middleware.mdx b/docs/02-app/01-building-your-application/01-routing/11-middleware.mdx index b15fa22d81922..429ecd008b833 100644 --- a/docs/02-app/01-building-your-application/01-routing/11-middleware.mdx +++ b/docs/02-app/01-building-your-application/01-routing/11-middleware.mdx @@ -388,6 +388,10 @@ export default async function middleware(req) { } ``` +## Runtime + +Middleware currently only supports the [Edge runtime](/docs/app/building-your-application/rendering/edge-and-nodejs-runtimes). The Node.js runtime can not be used. + ## Version History | Version | Changes | From f431600ce4067b00724dbcf0727caaddd90a73c1 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 5 Dec 2023 20:39:45 -0800 Subject: [PATCH 125/189] Revert "added comma to the props list" (#59314) Reverts vercel/next.js#58596 This is failing lint checks [x-ref](https://github.com/vercel/next.js/actions/runs/7109843046/job/19355454595) --- docs/02-app/02-api-reference/02-file-conventions/page.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/02-app/02-api-reference/02-file-conventions/page.mdx b/docs/02-app/02-api-reference/02-file-conventions/page.mdx index f32a65caeff66..e1cfa04de45b0 100644 --- a/docs/02-app/02-api-reference/02-file-conventions/page.mdx +++ b/docs/02-app/02-api-reference/02-file-conventions/page.mdx @@ -10,7 +10,7 @@ export default function Page({ params, searchParams, }: { - params: { slug: string }, + params: { slug: string } searchParams: { [key: string]: string | string[] | undefined } }) { return

My Page

From 59f7ca85c2efce459b906a235ef6ccc1b0e537fc Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Tue, 5 Dec 2023 21:29:23 -0800 Subject: [PATCH 126/189] remove additional static prefetch code (#59313) This is a continuation from https://github.com/vercel/next.js/pull/58783 to remove the remaining code related to static prefetching. --- ...tatic-generation-async-storage.external.ts | 1 - .../components/static-generation-bailout.ts | 6 -- packages/next/src/server/base-server.ts | 24 -------- .../app-dir/app-prefetch/prefetching.test.ts | 18 ------ .../e2e/app-dir/app-static/app-static.test.ts | 17 ------ test/e2e/app-dir/app/index.test.ts | 56 ------------------- 6 files changed, 122 deletions(-) diff --git a/packages/next/src/client/components/static-generation-async-storage.external.ts b/packages/next/src/client/components/static-generation-async-storage.external.ts index 205143ad7b66a..1ea0a0130a3f9 100644 --- a/packages/next/src/client/components/static-generation-async-storage.external.ts +++ b/packages/next/src/client/components/static-generation-async-storage.external.ts @@ -41,7 +41,6 @@ export interface StaticGenerationStore { dynamicUsageDescription?: string dynamicUsageStack?: string dynamicUsageErr?: DynamicServerError - staticPrefetchBailout?: boolean nextFetchId?: number pathWasRevalidated?: boolean diff --git a/packages/next/src/client/components/static-generation-bailout.ts b/packages/next/src/client/components/static-generation-bailout.ts index df9df4123d085..204ed3c843cdc 100644 --- a/packages/next/src/client/components/static-generation-bailout.ts +++ b/packages/next/src/client/components/static-generation-bailout.ts @@ -53,12 +53,6 @@ export const staticGenerationBailout: StaticGenerationBailout = ( // to 0. staticGenerationStore.revalidate = 0 - if (!dynamic) { - // we can statically prefetch pages that opt into dynamic, - // but not things like headers/cookies - staticGenerationStore.staticPrefetchBailout = true - } - if (staticGenerationStore.isStaticGeneration) { const err = new DynamicServerError(message) staticGenerationStore.dynamicUsageDescription = reason diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index 2e3933245e84c..a06bc4ab55879 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -2314,30 +2314,6 @@ export default abstract class Server { { page: pathname, params: opts.params, query, renderOpts } ) } else if (isAppPageRouteModule(routeModule)) { - // TODO: Re-enable once static prefetches re-land - // if ( - // !opts.experimental.ppr && - // isPrefetchRSCRequest && - // process.env.NODE_ENV === 'production' && - // !this.minimalMode - // ) { - // try { - // const prefetchRsc = await this.getPrefetchRsc(resolvedUrlPathname) - // if (prefetchRsc) { - // res.setHeader( - // 'cache-control', - // 'private, no-cache, no-store, max-age=0, must-revalidate' - // ) - // res.setHeader('content-type', RSC_CONTENT_TYPE_HEADER) - // res.body(prefetchRsc).send() - // return null - // } - // } catch { - // // We fallback to invoking the function if prefetch data is not - // // available. - // } - // } - const module = components.routeModule as AppPageRouteModule // Due to the way we pass data by mutating `renderOpts`, we can't extend the diff --git a/test/e2e/app-dir/app-prefetch/prefetching.test.ts b/test/e2e/app-dir/app-prefetch/prefetching.test.ts index 63fb9d55cdd81..b6143f9bfd16e 100644 --- a/test/e2e/app-dir/app-prefetch/prefetching.test.ts +++ b/test/e2e/app-dir/app-prefetch/prefetching.test.ts @@ -302,24 +302,6 @@ createNextDescribe( }) describe('dynamic rendering', () => { - async function hasStaticPrefetch(filePath: string): Promise { - try { - await next.readFile(`.next/server/app${filePath}`) - return true - } catch { - return false - } - } - it('should not generate a static prefetch for layouts that use cookies/headers', async () => { - expect( - await hasStaticPrefetch('/prefetch-dynamic-usage/foo.prefetch.rsc') - ).toBe(false) - - expect( - await hasStaticPrefetch('/prefetch-dynamic-usage/bar.prefetch.rsc') - ).toBe(false) - }) - describe.each(['/force-dynamic', '/revalidate-0'])('%s', (basePath) => { it('should not re-render layout when navigating between sub-pages', async () => { const logStartIndex = next.cliOutput.length diff --git a/test/e2e/app-dir/app-static/app-static.test.ts b/test/e2e/app-dir/app-static/app-static.test.ts index a2efc37dee287..d5259853cf5a3 100644 --- a/test/e2e/app-dir/app-static/app-static.test.ts +++ b/test/e2e/app-dir/app-static/app-static.test.ts @@ -507,7 +507,6 @@ createNextDescribe( 'ssg-draft-mode.rsc', 'ssr-forced/page.js', 'articles/works.rsc', - // 'custom.prefetch.rsc', 'force-cache/page.js', 'ssg-draft-mode.html', 'articles/works.html', @@ -526,7 +525,6 @@ createNextDescribe( 'force-static/first.html', 'force-static/second.rsc', 'ssg-draft-mode/test.rsc', - // 'ssr-forced.prefetch.rsc', 'isr-error-handling.html', 'articles/[slug]/page.js', 'no-store/static/page.js', @@ -537,15 +535,11 @@ createNextDescribe( 'no-store/dynamic/page.js', 'blog/seb/second-post.html', 'ssg-draft-mode/test-2.rsc', - // 'response-url.prefetch.rsc', 'blog/styfle/first-post.rsc', - // 'default-cache.prefetch.rsc', 'dynamic-error/[id]/page.js', 'ssg-draft-mode/test-2.html', 'blog/styfle/first-post.html', 'blog/styfle/second-post.rsc', - // 'fetch-no-cache.prefetch.rsc', - // 'force-no-store.prefetch.rsc', 'force-static/[slug]/page.js', 'hooks/use-pathname/slug.rsc', 'hooks/use-search-params.rsc', @@ -571,12 +565,10 @@ createNextDescribe( 'react-fetch-deduping-node/page.js', 'variable-revalidate/encoding.html', 'variable-revalidate/cookie/page.js', - // 'gen-params-dynamic/one.prefetch.rsc', 'ssg-draft-mode/[[...route]]/page.js', 'variable-revalidate/post-method.rsc', 'stale-cache-serving/app-page/page.js', 'dynamic-no-gen-params/[slug]/page.js', - // 'ssr-auto/cache-no-store.prefetch.rsc', 'static-to-dynamic-error/[id]/page.js', 'variable-revalidate/encoding/page.js', 'variable-revalidate/no-store/page.js', @@ -590,7 +582,6 @@ createNextDescribe( 'variable-revalidate/revalidate-3.html', 'force-dynamic-prerender/[slug]/page.js', 'gen-params-dynamic-revalidate/one.html', - // 'react-fetch-deduping-node.prefetch.rsc', 'ssr-auto/fetch-revalidate-zero/page.js', 'variable-revalidate/authorization.html', '_not-found_client-reference-manifest.js', @@ -603,8 +594,6 @@ createNextDescribe( 'variable-revalidate/headers-instance.rsc', 'variable-revalidate/revalidate-3/page.js', 'stale-cache-serving-edge/app-page/page.js', - // 'stale-cache-serving/app-page.prefetch.rsc', - // 'force-dynamic-catch-all/slug.prefetch.rsc', 'hooks/use-search-params/force-static.html', 'hooks/use-search-params/with-suspense.rsc', 'route-handler/revalidate-360-isr/route.js', @@ -612,13 +601,11 @@ createNextDescribe( 'variable-revalidate-edge/no-store/page.js', 'variable-revalidate/authorization/page.js', 'variable-revalidate/headers-instance.html', - // 'variable-revalidate/no-store.prefetch.rsc', 'stale-cache-serving/route-handler/route.js', 'hooks/use-search-params/with-suspense.html', 'route-handler-edge/revalidate-360/route.js', 'variable-revalidate/revalidate-360-isr.rsc', 'variable-revalidate/revalidate-360/page.js', - // 'ssr-auto/fetch-revalidate-zero.prefetch.rsc', 'static-to-dynamic-error-forced/[id]/page.js', 'variable-config-revalidate/revalidate-3.rsc', 'variable-revalidate/revalidate-360-isr.html', @@ -629,7 +616,6 @@ createNextDescribe( 'variable-config-revalidate/revalidate-3.html', 'variable-revalidate-edge/post-method/page.js', 'variable-revalidate/headers-instance/page.js', - // 'variable-revalidate/status-code.prefetch.rsc', 'force-cache/page_client-reference-manifest.js', 'hooks/use-search-params/with-suspense/page.js', 'variable-revalidate-edge/revalidate-3/page.js', @@ -640,10 +626,8 @@ createNextDescribe( 'stale-cache-serving-edge/route-handler/route.js', 'blog/[author]/page_client-reference-manifest.js', 'default-cache/page_client-reference-manifest.js', - // 'force-dynamic-prerender/frameworks.prefetch.rsc', 'variable-config-revalidate/revalidate-3/page.js', 'variable-revalidate/post-method-request/page.js', - // 'variable-revalidate/revalidate-360.prefetch.rsc', 'fetch-no-cache/page_client-reference-manifest.js', 'force-dynamic-catch-all/[slug]/[[...id]]/page.js', 'force-no-store/page_client-reference-manifest.js', @@ -675,7 +659,6 @@ createNextDescribe( 'partial-gen-params-no-additional-lang/fr/second.html', 'partial-gen-params-no-additional-slug/en/second.html', 'partial-gen-params-no-additional-slug/fr/second.html', - // 'variable-revalidate/post-method-request.prefetch.rsc', 'variable-revalidate-edge/post-method-request/page.js', 'force-static/[slug]/page_client-reference-manifest.js', 'blog/[author]/[slug]/page_client-reference-manifest.js', diff --git a/test/e2e/app-dir/app/index.test.ts b/test/e2e/app-dir/app/index.test.ts index fa9bca3d9e514..bef69d621e64e 100644 --- a/test/e2e/app-dir/app/index.test.ts +++ b/test/e2e/app-dir/app/index.test.ts @@ -2,8 +2,6 @@ import { createNextDescribe } from 'e2e-utils' import { check, getRedboxHeader, hasRedbox, waitFor } from 'next-test-utils' import cheerio from 'cheerio' import stripAnsi from 'strip-ansi' -import { BrowserInterface } from 'test/lib/browsers/base' -import { Request } from 'playwright-core' createNextDescribe( 'app dir - basic', @@ -37,60 +35,6 @@ createNextDescribe( ) }) - // TODO: Re-enable once static prefetches re-land - it.skip('should use RSC prefetch data from build', async () => { - expect( - await next.readFile('.next/server/app/linking.prefetch.rsc') - ).toBeTruthy() - expect( - await next.readFile('.next/server/app/linking/about.prefetch.rsc') - ).toContain('About loading...') - expect( - await next.readFile( - '.next/server/app/dashboard/deployments/breakdown.prefetch.rsc' - ) - ).toBeTruthy() - expect( - await next - .readFile( - '.next/server/app/dashboard/deployments/[id].prefetch.rsc' - ) - .catch(() => false) - ).toBeFalsy() - - const outputStart = next.cliOutput.length - const browser: BrowserInterface = await next.browser('/') - const rscReqs = [] - - browser.on('request', (req: Request) => { - if (req.headers()['rsc']) { - rscReqs.push(req.url()) - } - }) - - await browser.eval('window.location.href = "/linking"') - - await check(async () => { - return rscReqs.length > 3 ? 'success' : JSON.stringify(rscReqs) - }, 'success') - - const trimmedOutput = next.cliOutput.substring(outputStart) - - expect(trimmedOutput).not.toContain( - 'rendering dashboard/(custom)/deployments/breakdown' - ) - expect(trimmedOutput).not.toContain( - 'rendering /dashboard/deployments/[id]' - ) - expect(trimmedOutput).not.toContain('rendering linking about page') - - await browser.elementByCss('#breakdown').click() - await check( - () => next.cliOutput.substring(outputStart), - /rendering .*breakdown/ - ) - }) - if (!process.env.NEXT_EXPERIMENTAL_COMPILE) { it('should have correct size in build output', async () => { expect(next.cliOutput).toMatch( From 06cf74a66a1d8531413f3965fabcac9dd6f7d123 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 6 Dec 2023 07:57:13 +0100 Subject: [PATCH 127/189] add module tracing for client reference and next/dynamic walking (#59306) ### What? add tracing to the module graph walking Closes PACK-2090 --- .../visit_client_reference.rs | 61 +++++++++++++------ .../src/next_dynamic/visit_dynamic.rs | 42 +++++++++---- 2 files changed, 74 insertions(+), 29 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs b/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs index e2f22bd390360..f4bf3c0a64a9f 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs @@ -8,7 +8,7 @@ use turbo_tasks::{ debug::ValueDebugFormat, graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow}, trace::TraceRawVcs, - TryJoinIterExt, Vc, + ReadRef, TryJoinIterExt, ValueToString, Vc, }; use turbopack_binding::turbopack::core::{ module::{Module, Modules}, @@ -71,11 +71,17 @@ impl ClientReferenceGraph { entries .iter() .copied() - .map(|module| VisitClientReferenceNode { - server_component: None, - ty: VisitClientReferenceNodeType::Internal(module), + .map(|module| async move { + Ok(VisitClientReferenceNode { + server_component: None, + ty: VisitClientReferenceNodeType::Internal( + module, + module.ident().to_string().await?, + ), + }) }) - .collect::>(), + .try_join() + .await?, VisitClientReference, ) .await @@ -95,11 +101,11 @@ impl ClientReferenceGraph { for node in this.graph.reverse_topological() { match &node.ty { - VisitClientReferenceNodeType::Internal(_asset) => { + VisitClientReferenceNodeType::Internal(_asset, _) => { // No-op. These nodes are only useful during graph // traversal. } - VisitClientReferenceNodeType::ClientReference(client_reference) => { + VisitClientReferenceNodeType::ClientReference(client_reference, _) => { client_reference_types.insert(*client_reference.ty()); } } @@ -117,15 +123,15 @@ impl ClientReferenceGraph { .graph .reverse_topological_from_node(&VisitClientReferenceNode { server_component: None, - ty: VisitClientReferenceNodeType::Internal(entry), + ty: VisitClientReferenceNodeType::Internal(entry, entry.ident().to_string().await?), }) { match &node.ty { - VisitClientReferenceNodeType::Internal(_asset) => { + VisitClientReferenceNodeType::Internal(_asset, _) => { // No-op. These nodes are only useful during graph // traversal. } - VisitClientReferenceNodeType::ClientReference(client_reference) => { + VisitClientReferenceNodeType::ClientReference(client_reference, _) => { entry_client_references.push(*client_reference); } } @@ -149,8 +155,8 @@ struct VisitClientReferenceNode { Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, ValueDebugFormat, TraceRawVcs, )] enum VisitClientReferenceNodeType { - ClientReference(ClientReference), - Internal(Vc>), + ClientReference(ClientReference, ReadRef), + Internal(Vc>, ReadRef), } impl Visit for VisitClientReference { @@ -160,8 +166,8 @@ impl Visit for VisitClientReference { fn visit(&mut self, edge: Self::Edge) -> VisitControlFlow { match edge.ty { - VisitClientReferenceNodeType::ClientReference(_) => VisitControlFlow::Skip(edge), - VisitClientReferenceNodeType::Internal(_) => VisitControlFlow::Continue(edge), + VisitClientReferenceNodeType::ClientReference(..) => VisitControlFlow::Skip(edge), + VisitClientReferenceNodeType::Internal(..) => VisitControlFlow::Continue(edge), } } @@ -171,8 +177,8 @@ impl Visit for VisitClientReference { match node.ty { // This should never occur since we always skip visiting these // nodes' edges. - VisitClientReferenceNodeType::ClientReference(_) => Ok(vec![]), - VisitClientReferenceNodeType::Internal(module) => { + VisitClientReferenceNodeType::ClientReference(..) => Ok(vec![]), + VisitClientReferenceNodeType::Internal(module, _) => { let references = module.references().await?; let referenced_modules = references @@ -202,6 +208,7 @@ impl Visit for VisitClientReference { client_reference_module, ), }, + client_reference_module.ident().to_string().await?, ), }); } @@ -219,6 +226,7 @@ impl Visit for VisitClientReference { css_client_reference_asset, ), }, + css_client_reference_asset.ident().to_string().await?, ), }); } @@ -229,13 +237,19 @@ impl Visit for VisitClientReference { { return Ok(VisitClientReferenceNode { server_component: Some(server_component_asset), - ty: VisitClientReferenceNodeType::Internal(module), + ty: VisitClientReferenceNodeType::Internal( + module, + module.ident().to_string().await?, + ), }); } Ok(VisitClientReferenceNode { server_component: node.server_component, - ty: VisitClientReferenceNodeType::Internal(module), + ty: VisitClientReferenceNodeType::Internal( + module, + module.ident().to_string().await?, + ), }) }); @@ -246,4 +260,15 @@ impl Visit for VisitClientReference { } } } + + fn span(&mut self, node: &VisitClientReferenceNode) -> tracing::Span { + match &node.ty { + VisitClientReferenceNodeType::ClientReference(_, name) => { + tracing::info_span!("client reference", name = **name) + } + VisitClientReferenceNodeType::Internal(_, name) => { + tracing::info_span!("module", name = **name) + } + } + } } diff --git a/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs b/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs index 3cdfef6f215d9..6b89f807b2664 100644 --- a/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs +++ b/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs @@ -4,7 +4,7 @@ use anyhow::Result; use tracing::Instrument; use turbo_tasks::{ graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow}, - TryJoinIterExt, Vc, + ReadRef, TryJoinIterExt, ValueToString, Vc, }; use turbopack_binding::turbopack::core::{ module::{Module, Modules}, @@ -28,8 +28,11 @@ impl NextDynamicEntries { .await? .iter() .copied() - .map(VisitDynamicNode::Internal) - .collect::>(), + .map(|m| async move { + Ok(VisitDynamicNode::Internal(m, m.ident().to_string().await?)) + }) + .try_join() + .await?, VisitDynamic, ) .await @@ -42,11 +45,11 @@ impl NextDynamicEntries { for node in nodes { match node { - VisitDynamicNode::Internal(_asset) => { + VisitDynamicNode::Internal(_asset, _) => { // No-op. These nodes are only useful during graph // traversal. } - VisitDynamicNode::Dynamic(dynamic_asset) => { + VisitDynamicNode::Dynamic(dynamic_asset, _) => { next_dynamics.push(dynamic_asset); } } @@ -63,8 +66,8 @@ struct VisitDynamic; #[derive(Clone, Eq, PartialEq, Hash)] enum VisitDynamicNode { - Dynamic(Vc), - Internal(Vc>), + Dynamic(Vc, ReadRef), + Internal(Vc>, ReadRef), } impl Visit for VisitDynamic { @@ -82,8 +85,8 @@ impl Visit for VisitDynamic { let node = node.clone(); async move { let module = match node { - VisitDynamicNode::Dynamic(dynamic_module) => Vc::upcast(dynamic_module), - VisitDynamicNode::Internal(module) => module, + VisitDynamicNode::Dynamic(dynamic_module, _) => Vc::upcast(dynamic_module), + VisitDynamicNode::Internal(module, _) => module, }; let references = module.references().await?; @@ -105,10 +108,16 @@ impl Visit for VisitDynamic { if let Some(next_dynamic_module) = Vc::try_resolve_downcast_type::(module).await? { - return Ok(VisitDynamicNode::Dynamic(next_dynamic_module)); + return Ok(VisitDynamicNode::Dynamic( + next_dynamic_module, + next_dynamic_module.ident().to_string().await?, + )); } - Ok(VisitDynamicNode::Internal(module)) + Ok(VisitDynamicNode::Internal( + module, + module.ident().to_string().await?, + )) }); let nodes = referenced_modules.try_join().await?; @@ -116,4 +125,15 @@ impl Visit for VisitDynamic { Ok(nodes) } } + + fn span(&mut self, node: &VisitDynamicNode) -> tracing::Span { + match node { + VisitDynamicNode::Dynamic(_, name) => { + tracing::info_span!("dynamic module", name = **name) + } + VisitDynamicNode::Internal(_, name) => { + tracing::info_span!("module", name = **name) + } + } + } } From 0082d54893893b71b4be50b1ace748015781c0dc Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 6 Dec 2023 09:23:46 +0100 Subject: [PATCH 128/189] side effects optimization (#58972) ### What? Code update for refactoring in https://github.com/vercel/turbo/pull/6590 Closes PACK-2043 --- Cargo.lock | 69 ++++++++++--------- Cargo.toml | 6 +- packages/next-swc/crates/next-api/src/app.rs | 8 +-- .../crates/next-api/src/instrumentation.rs | 28 ++++++-- .../crates/next-api/src/middleware.rs | 39 +++++++---- .../next-swc/crates/next-api/src/pages.rs | 10 +-- .../next-swc/crates/next-api/src/project.rs | 20 ++---- .../crates/next-api/src/server_actions.rs | 24 ++++--- .../crates/next-core/src/bootstrap.rs | 52 +++++++------- .../crates/next-core/src/loader_tree.rs | 29 ++++---- .../crates/next-core/src/middleware.rs | 10 +-- .../next-core/src/next_app/app_page_entry.rs | 20 +++--- .../next-core/src/next_app/app_route_entry.rs | 30 ++++---- .../next-core/src/next_app/metadata/image.rs | 16 +++-- .../next-core/src/next_client/context.rs | 3 +- .../css_client_reference_module.rs | 16 ++--- .../css_client_reference_module_type.rs | 13 ++-- ...cmascript_client_reference_proxy_module.rs | 11 +-- .../ecmascript_client_reference_transition.rs | 53 ++++++++------ .../crates/next-core/src/next_config.rs | 33 +++++---- .../src/next_dynamic/dynamic_transition.rs | 20 ++++-- .../crates/next-core/src/next_edge/entry.rs | 11 +-- .../next-core/src/next_font/google/mod.rs | 35 +++++----- .../crates/next-core/src/next_image/module.rs | 41 ++++++----- .../next-core/src/next_pages/page_entry.rs | 28 +++++--- .../next-core/src/next_server/context.rs | 8 ++- .../next-core/src/next_server/resolve.rs | 24 ++++--- .../transforms/swc_ecma_transform_plugins.rs | 9 +-- .../crates/next-core/src/page_loader.rs | 25 ++++--- packages/next/package.json | 2 +- .../react-refresh-utils/internal/helpers.ts | 21 +++++- pnpm-lock.yaml | 10 +-- 32 files changed, 426 insertions(+), 298 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 621eb73e4c0cd..6ae5ea955e73a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "serde", "smallvec", @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "serde", @@ -7678,7 +7678,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-trait", @@ -7710,7 +7710,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "cargo-lock", @@ -7722,7 +7722,7 @@ dependencies = [ [[package]] name = "turbo-tasks-bytes" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "bytes", @@ -7737,7 +7737,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "dotenvs", @@ -7751,7 +7751,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7768,7 +7768,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "auto-hash-map", @@ -7799,7 +7799,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "base16", "hex", @@ -7811,7 +7811,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -7825,7 +7825,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "proc-macro2", "quote", @@ -7835,7 +7835,7 @@ dependencies = [ [[package]] name = "turbo-tasks-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "mimalloc", ] @@ -7843,7 +7843,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "auto-hash-map", @@ -7868,7 +7868,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-recursion", @@ -7900,7 +7900,7 @@ dependencies = [ [[package]] name = "turbopack-binding" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "auto-hash-map", "mdxjs", @@ -7941,7 +7941,7 @@ dependencies = [ [[package]] name = "turbopack-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7965,7 +7965,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "clap 4.4.2", @@ -7983,7 +7983,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-recursion", @@ -8013,7 +8013,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-trait", @@ -8027,6 +8027,7 @@ dependencies = [ "serde", "smallvec", "swc_core", + "tracing", "turbo-tasks", "turbo-tasks-build", "turbo-tasks-fs", @@ -8039,7 +8040,7 @@ dependencies = [ [[package]] name = "turbopack-dev" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8063,7 +8064,7 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-compression", @@ -8100,7 +8101,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-trait", @@ -8134,7 +8135,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-hmr-protocol" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "serde", "serde_json", @@ -8145,7 +8146,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-plugins" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-trait", @@ -8168,7 +8169,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-runtime" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "indoc", @@ -8185,7 +8186,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8201,7 +8202,7 @@ dependencies = [ [[package]] name = "turbopack-image" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "base64 0.21.4", @@ -8221,7 +8222,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "serde", @@ -8236,7 +8237,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "mdxjs", @@ -8251,7 +8252,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "async-stream", @@ -8286,7 +8287,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "serde", @@ -8302,7 +8303,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "swc_core", "turbo-tasks", @@ -8313,7 +8314,7 @@ dependencies = [ [[package]] name = "turbopack-trace-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "crossbeam-channel", @@ -8328,7 +8329,7 @@ dependencies = [ [[package]] name = "turbopack-wasm" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231205.2#8cb1c34181948ea6e85584d05eb9f69e86e11859" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" dependencies = [ "anyhow", "indexmap 1.9.3", diff --git a/Cargo.toml b/Cargo.toml index 51f53646dd088..6cc2e8c07e971 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,11 +43,11 @@ swc_core = { version = "0.86.81", features = [ testing = { version = "0.35.11" } # Turbo crates -turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231205.2" } +turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.2" } # [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros.. -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231205.2" } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.2" } # [TODO]: need to refactor embed_directory! macro usage in next-core -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231205.2" } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.2" } # General Deps diff --git a/packages/next-swc/crates/next-api/src/app.rs b/packages/next-swc/crates/next-api/src/app.rs index 0baadc9a7fe75..1f4c52511d754 100644 --- a/packages/next-swc/crates/next-api/src/app.rs +++ b/packages/next-swc/crates/next-api/src/app.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use indexmap::IndexSet; use next_core::{ all_assets_from_entries, @@ -822,9 +822,9 @@ impl AppEndpoint { .edge_rsc_runtime_entries() .await? .clone_value(); - let Some(evaluatable) = Vc::try_resolve_sidecast(app_entry.rsc_entry).await? else { - bail!("Entry module must be evaluatable"); - }; + let evaluatable = Vc::try_resolve_sidecast(app_entry.rsc_entry) + .await? + .context("Entry module must be evaluatable")?; evaluatable_assets.push(evaluatable); let (loader, manifest) = create_server_actions_manifest( diff --git a/packages/next-swc/crates/next-api/src/instrumentation.rs b/packages/next-swc/crates/next-api/src/instrumentation.rs index 1871334d018c6..97df566479e71 100644 --- a/packages/next-swc/crates/next-api/src/instrumentation.rs +++ b/packages/next-swc/crates/next-api/src/instrumentation.rs @@ -17,6 +17,8 @@ use turbopack_binding::{ context::AssetContext, module::Module, output::{OutputAsset, OutputAssets}, + reference_type::{EntryReferenceSubType, ReferenceType}, + source::Source, virtual_output::VirtualOutputAsset, }, ecmascript::chunk::EcmascriptChunkPlaceable, @@ -34,7 +36,7 @@ use crate::{ pub struct InstrumentationEndpoint { project: Vc, context: Vc>, - userland_module: Vc>, + source: Vc>, is_edge: bool, } @@ -44,13 +46,13 @@ impl InstrumentationEndpoint { pub fn new( project: Vc, context: Vc>, - userland_module: Vc>, + source: Vc>, is_edge: bool, ) -> Vc { Self { project, context, - userland_module, + source, is_edge, } .cell() @@ -58,10 +60,18 @@ impl InstrumentationEndpoint { #[turbo_tasks::function] async fn edge_files(&self) -> Result> { + let userland_module = self + .context + .process( + self.source, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Instrumentation)), + ) + .module(); + let module = wrap_edge_entry( self.context, self.project.project_path(), - self.userland_module, + userland_module, "instrumentation".to_string(), ); @@ -102,7 +112,15 @@ impl InstrumentationEndpoint { self.project.server_compile_time_info().environment(), ); - let Some(module) = Vc::try_resolve_downcast(self.userland_module).await? else { + let userland_module = self + .context + .process( + self.source, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Instrumentation)), + ) + .module(); + + let Some(module) = Vc::try_resolve_downcast(userland_module).await? else { bail!("Entry module must be evaluatable"); }; diff --git a/packages/next-swc/crates/next-api/src/middleware.rs b/packages/next-swc/crates/next-api/src/middleware.rs index a87b9d4a4205b..8472b4876f5b3 100644 --- a/packages/next-swc/crates/next-api/src/middleware.rs +++ b/packages/next-swc/crates/next-api/src/middleware.rs @@ -21,6 +21,8 @@ use turbopack_binding::{ context::AssetContext, module::Module, output::{OutputAsset, OutputAssets}, + reference_type::{EntryReferenceSubType, ReferenceType}, + source::Source, virtual_output::VirtualOutputAsset, }, ecmascript::chunk::EcmascriptChunkPlaceable, @@ -37,7 +39,7 @@ use crate::{ pub struct MiddlewareEndpoint { project: Vc, context: Vc>, - userland_module: Vc>, + source: Vc>, } #[turbo_tasks::value_impl] @@ -46,23 +48,28 @@ impl MiddlewareEndpoint { pub fn new( project: Vc, context: Vc>, - userland_module: Vc>, + source: Vc>, ) -> Vc { Self { project, context, - userland_module, + source, } .cell() } #[turbo_tasks::function] async fn edge_files(&self) -> Result> { - let module = get_middleware_module( - self.context, - self.project.project_path(), - self.userland_module, - ); + let userland_module = self + .context + .process( + self.source, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Middleware)), + ) + .module(); + + let module = + get_middleware_module(self.context, self.project.project_path(), userland_module); let module = wrap_edge_entry( self.context, @@ -85,9 +92,9 @@ impl MiddlewareEndpoint { bail!("Entry module must be evaluatable"); }; - let Some(evaluatable) = Vc::try_resolve_sidecast(module).await? else { - bail!("Entry module must be evaluatable"); - }; + let evaluatable = Vc::try_resolve_sidecast(module) + .await? + .context("Entry module must be evaluatable")?; evaluatable_assets.push(evaluatable); let edge_chunking_context = self.project.edge_chunking_context(); @@ -102,7 +109,15 @@ impl MiddlewareEndpoint { async fn output_assets(self: Vc) -> Result> { let this = self.await?; - let config = parse_config_from_source(this.userland_module); + let userland_module = this + .context + .process( + this.source, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Middleware)), + ) + .module(); + + let config = parse_config_from_source(userland_module); let edge_files = self.edge_files(); let mut output_assets = edge_files.await?.clone_value(); diff --git a/packages/next-swc/crates/next-api/src/pages.rs b/packages/next-swc/crates/next-api/src/pages.rs index a9ddba24fb99b..84c8bfd79401d 100644 --- a/packages/next-swc/crates/next-api/src/pages.rs +++ b/packages/next-swc/crates/next-api/src/pages.rs @@ -645,7 +645,9 @@ impl PageEndpoint { async move { let this = self.await?; - let ssr_module = module_context.process(self.source(), reference_type.clone()); + let ssr_module = module_context + .process(self.source(), reference_type.clone()) + .module(); let config = parse_config_from_source(ssr_module).await?; let is_edge = matches!(config.runtime, NextRuntime::Edge); @@ -663,9 +665,9 @@ impl PageEndpoint { ); let mut evaluatable_assets = edge_runtime_entries.await?.clone_value(); - let Some(evaluatable) = Vc::try_resolve_sidecast(ssr_module).await? else { - bail!("Entry module must be evaluatable"); - }; + let evaluatable = Vc::try_resolve_sidecast(ssr_module) + .await? + .context("could not process page loader entry module")?; evaluatable_assets.push(evaluatable); let edge_files = edge_chunking_context.evaluated_chunk_group( diff --git a/packages/next-swc/crates/next-api/src/project.rs b/packages/next-swc/crates/next-api/src/project.rs index a1e42a312ab7c..a913a38f660dd 100644 --- a/packages/next-swc/crates/next-api/src/project.rs +++ b/packages/next-swc/crates/next-api/src/project.rs @@ -42,7 +42,6 @@ use turbopack_binding::{ environment::ServerAddr, file_source::FileSource, output::{OutputAsset, OutputAssets}, - reference_type::{EntryReferenceSubType, ReferenceType}, resolve::{find_context_file, FindContextFileResult}, source::Source, version::{Update, Version, VersionState, VersionedContent}, @@ -729,15 +728,13 @@ impl Project { } #[turbo_tasks::function] - fn middleware_endpoint(self: Vc, source: Vc>) -> Vc { + async fn middleware_endpoint( + self: Vc, + source: Vc>, + ) -> Result> { let context = self.middleware_context(); - let module = context.process( - source, - Value::new(ReferenceType::Entry(EntryReferenceSubType::Middleware)), - ); - - MiddlewareEndpoint::new(self, context, module) + Ok(MiddlewareEndpoint::new(self, context, source)) } #[turbo_tasks::function] @@ -775,12 +772,7 @@ impl Project { self.node_instrumentation_context() }; - let module = context.process( - source, - Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), - ); - - InstrumentationEndpoint::new(self, context, module, is_edge) + InstrumentationEndpoint::new(self, context, source, is_edge) } #[turbo_tasks::function] diff --git a/packages/next-swc/crates/next-api/src/server_actions.rs b/packages/next-swc/crates/next-api/src/server_actions.rs index dee4e5fd10e79..c2cb352135564 100644 --- a/packages/next-swc/crates/next-api/src/server_actions.rs +++ b/packages/next-swc/crates/next-api/src/server_actions.rs @@ -1,6 +1,6 @@ use std::{io::Write, iter::once}; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use indexmap::{map::Entry, IndexMap}; use next_core::{ next_manifests::{ActionLayer, ActionManifestWorkerEntry, ServerReferenceManifest}, @@ -57,10 +57,9 @@ pub(crate) async fn create_server_actions_manifest( let actions = get_actions(rsc_entry, server_reference_modules, asset_context); let loader = build_server_actions_loader(project_path, page_name, actions, asset_context).await?; - let Some(evaluable) = Vc::try_resolve_sidecast::>(loader).await? - else { - bail!("loader module must be evaluatable"); - }; + let evaluable = Vc::try_resolve_sidecast::>(loader) + .await? + .context("loader module must be evaluatable")?; let loader_id = loader .as_chunk_item(Vc::upcast(chunking_context)) @@ -108,10 +107,12 @@ async fn build_server_actions_loader( let file = File::from(contents.build()); let source = VirtualSource::new(output_path, AssetContent::file(file.into())); let import_map = import_map.into_iter().map(|(k, v)| (v, k)).collect(); - let module = asset_context.process( - Vc::upcast(source), - Value::new(ReferenceType::Internal(Vc::cell(import_map))), - ); + let module = asset_context + .process( + Vc::upcast(source), + Value::new(ReferenceType::Internal(Vc::cell(import_map))), + ) + .module(); let Some(placeable) = Vc::try_resolve_sidecast::>(module).await? @@ -249,7 +250,10 @@ async fn to_rsc_context( } else { ReferenceType::TypeScript(TypeScriptReferenceSubType::Undefined) }; - Ok(asset_context.process(Vc::upcast(source), Value::new(ty))) + let module = asset_context + .process(Vc::upcast(source), Value::new(ty)) + .module(); + Ok(module) } /// Our graph traversal visitor, which finds the primary modules directly diff --git a/packages/next-swc/crates/next-core/src/bootstrap.rs b/packages/next-swc/crates/next-core/src/bootstrap.rs index ed33404956ed5..d5645e2829699 100644 --- a/packages/next-swc/crates/next-core/src/bootstrap.rs +++ b/packages/next-swc/crates/next-core/src/bootstrap.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use indexmap::IndexMap; use turbo_tasks::{Value, ValueToString, Vc}; use turbo_tasks_fs::{File, FileSystemPath}; @@ -77,35 +77,39 @@ pub async fn bootstrap( config.insert("PAGE".to_string(), path.to_string()); config.insert("PATHNAME".to_string(), pathname); - let config_asset = context.process( - Vc::upcast(VirtualSource::new( - asset.ident().path().join("bootstrap-config.ts".to_string()), - AssetContent::file( - File::from( - config - .iter() - .map(|(k, v)| format!("export const {} = {};\n", k, StringifyJs(v))) - .collect::>() - .join(""), - ) - .into(), - ), - )), - Value::new(ReferenceType::Internal(InnerAssets::empty())), - ); + let config_asset = context + .process( + Vc::upcast(VirtualSource::new( + asset.ident().path().join("bootstrap-config.ts".to_string()), + AssetContent::file( + File::from( + config + .iter() + .map(|(k, v)| format!("export const {} = {};\n", k, StringifyJs(v))) + .collect::>() + .join(""), + ) + .into(), + ), + )), + Value::new(ReferenceType::Internal(InnerAssets::empty())), + ) + .module(); let mut inner_assets = inner_assets.await?.clone_value(); inner_assets.insert("ENTRY".to_string(), asset); inner_assets.insert("BOOTSTRAP_CONFIG".to_string(), config_asset); - let asset = context.process( - bootstrap_asset, - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let asset = context + .process( + bootstrap_asset, + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); - let Some(asset) = Vc::try_resolve_sidecast::>(asset).await? else { - bail!("internal module must be evaluatable"); - }; + let asset = Vc::try_resolve_sidecast::>(asset) + .await? + .context("internal module must be evaluatable")?; Ok(asset) } diff --git a/packages/next-swc/crates/next-core/src/loader_tree.rs b/packages/next-swc/crates/next-core/src/loader_tree.rs index 5c471de68ef71..50248ca51461e 100644 --- a/packages/next-swc/crates/next-core/src/loader_tree.rs +++ b/packages/next-swc/crates/next-core/src/loader_tree.rs @@ -146,9 +146,10 @@ impl LoaderTreeBuilder { EcmaScriptModulesReferenceSubType::Undefined, )); - let module = - self.server_component_transition - .process(source, self.context, reference_ty); + let module = self + .server_component_transition + .process(source, self.context, reference_ty) + .module(); self.inner_assets.insert(format!("COMPONENT_{i}"), module); } @@ -268,15 +269,16 @@ impl LoaderTreeBuilder { app_page.clone(), ); - self.inner_assets.insert( - inner_module_id, - self.context.process( + let module = self + .context + .process( source, Value::new(ReferenceType::EcmaScriptModules( EcmaScriptModulesReferenceSubType::Undefined, )), - ), - ); + ) + .module(); + self.inner_assets.insert(inner_module_id, module); let s = " "; writeln!(self.loader_tree_code, "{s}{identifier},")?; @@ -346,15 +348,16 @@ impl LoaderTreeBuilder { let inner_module_id = format!("METADATA_ALT_{i}"); self.imports .push(format!("import {identifier} from \"{inner_module_id}\";")); - self.inner_assets.insert( - inner_module_id, - self.context.process( + let module = self + .context + .process( Vc::upcast(TextContentFileSource::new(Vc::upcast(FileSource::new( alt_path, )))), Value::new(ReferenceType::Internal(InnerAssets::empty())), - ), - ); + ) + .module(); + self.inner_assets.insert(inner_module_id, module); writeln!(self.loader_tree_code, "{s} alt: {identifier},")?; } diff --git a/packages/next-swc/crates/next-core/src/middleware.rs b/packages/next-swc/crates/next-core/src/middleware.rs index 643aa2dcb2019..92ff48c07dfb8 100644 --- a/packages/next-swc/crates/next-core/src/middleware.rs +++ b/packages/next-swc/crates/next-core/src/middleware.rs @@ -47,10 +47,12 @@ pub async fn get_middleware_module( INNER.to_string() => userland_module }; - let module = context.process( - source, - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let module = context + .process( + source, + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); Ok(module) } 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 640e7a70ccb23..0ad5161f4f194 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 @@ -106,10 +106,12 @@ pub async fn get_app_page_entry( let file = File::from(result.build()); let source = VirtualSource::new(source.ident().path(), AssetContent::file(file.into())); - let mut rsc_entry = context.process( - Vc::upcast(source), - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let mut rsc_entry = context + .process( + Vc::upcast(source), + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); if is_edge { rsc_entry = wrap_edge_page( @@ -190,10 +192,12 @@ async fn wrap_edge_page( INNER.to_string() => entry }; - let wrapped = context.process( - Vc::upcast(source), - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let wrapped = context + .process( + Vc::upcast(source), + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); Ok(wrap_edge_entry( context, 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 dd5db449f6bc4..5cf997000e6dd 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 @@ -67,19 +67,23 @@ pub async fn get_app_route_entry( ) .await?; - let userland_module = context.process( - source, - Value::new(ReferenceType::Entry(EntryReferenceSubType::AppRoute)), - ); + let userland_module = context + .process( + source, + Value::new(ReferenceType::Entry(EntryReferenceSubType::AppRoute)), + ) + .module(); let inner_assets = indexmap! { INNER.to_string() => userland_module }; - let mut rsc_entry = context.process( - Vc::upcast(virtual_source), - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let mut rsc_entry = context + .process( + Vc::upcast(virtual_source), + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); if is_edge { rsc_entry = wrap_edge_route( @@ -129,10 +133,12 @@ async fn wrap_edge_route( INNER.to_string() => entry }; - let wrapped = context.process( - Vc::upcast(source), - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let wrapped = context + .process( + Vc::upcast(source), + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); Ok(wrap_edge_entry(context, project_root, wrapped, pathname)) } diff --git a/packages/next-swc/crates/next-core/src/next_app/metadata/image.rs b/packages/next-swc/crates/next-core/src/next_app/metadata/image.rs index 68e8a7c6677dd..888252b8623ea 100644 --- a/packages/next-swc/crates/next-core/src/next_app/metadata/image.rs +++ b/packages/next-swc/crates/next-core/src/next_app/metadata/image.rs @@ -63,13 +63,15 @@ pub async fn dynamic_image_metadata_source( }; let source = Vc::upcast(FileSource::new(path)); - let exports = &*collect_direct_exports(asset_context.process( - source, - turbo_tasks::Value::new(ReferenceType::EcmaScriptModules( - EcmaScriptModulesReferenceSubType::Undefined, - )), - )) - .await?; + let module = asset_context + .process( + source, + turbo_tasks::Value::new(ReferenceType::EcmaScriptModules( + EcmaScriptModulesReferenceSubType::Undefined, + )), + ) + .module(); + let exports = &*collect_direct_exports(module).await?; let exported_fields_excluding_default = exports .iter() .filter(|e| *e != "default") diff --git a/packages/next-swc/crates/next-core/src/next_client/context.rs b/packages/next-swc/crates/next-core/src/next_client/context.rs index fd63edfcc0ee0..43e32b2435674 100644 --- a/packages/next-swc/crates/next-core/src/next_client/context.rs +++ b/packages/next-swc/crates/next-core/src/next_client/context.rs @@ -17,7 +17,7 @@ use turbopack_binding::{ resolve::{parse::Request, pattern::Pattern}, }, dev::{react_refresh::assert_can_resolve_react_refresh, DevChunkingContext}, - ecmascript::chunk::EcmascriptChunkingContext, + ecmascript::{chunk::EcmascriptChunkingContext, TreeShakingMode}, node::execution_context::ExecutionContext, turbopack::{ condition::ContextCondition, @@ -267,6 +267,7 @@ pub async fn get_client_module_options_context( preset_env_versions: Some(env), execution_context: Some(execution_context), custom_ecma_transform_plugins, + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() }; diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module.rs b/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module.rs index 8a3f6fc73cbd6..ab14d203d9bbe 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module.rs @@ -1,4 +1,4 @@ -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use turbo_tasks::Vc; use turbopack_binding::turbopack::{ core::{ @@ -72,10 +72,9 @@ impl ParseCss for CssClientReferenceModule { impl ProcessCss for CssClientReferenceModule { #[turbo_tasks::function] async fn get_css_with_placeholder(&self) -> Result> { - let Some(imp) = Vc::try_resolve_sidecast::>(self.client_module).await? - else { - bail!("CSS client reference client module must be CSS processable"); - }; + let imp = Vc::try_resolve_sidecast::>(self.client_module) + .await? + .context("CSS client reference client module must be CSS processable")?; Ok(imp.get_css_with_placeholder()) } @@ -85,10 +84,9 @@ impl ProcessCss for CssClientReferenceModule { &self, chunking_context: Vc>, ) -> Result> { - let Some(imp) = Vc::try_resolve_sidecast::>(self.client_module).await? - else { - bail!("CSS client reference client module must be CSS processable"); - }; + let imp = Vc::try_resolve_sidecast::>(self.client_module) + .await? + .context("CSS client reference client module must be CSS processable")?; Ok(imp.finalize_css(chunking_context)) } diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module_type.rs b/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module_type.rs index cc9f4b343df0e..029fc68060560 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module_type.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/css_client_reference/css_client_reference_module_type.rs @@ -39,11 +39,14 @@ impl CustomModuleType for CssClientReferenceModuleType { context: Vc, _part: Option>, ) -> Result>> { - let client_module = self.client_transition.process( - source, - context, - Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), - ); + let client_module = self + .client_transition + .process( + source, + context, + Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), + ) + .module(); let Some(client_module) = Vc::try_resolve_sidecast::>(client_module).await? diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs b/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs index 61b52dba9874c..d9f0b8784f6ee 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_proxy_module.rs @@ -99,10 +99,13 @@ impl EcmascriptClientReferenceProxyModule { proxy_module_content, ); - let proxy_module = this.server_asset_context.process( - Vc::upcast(proxy_source), - Value::new(ReferenceType::Undefined), - ); + let proxy_module = this + .server_asset_context + .process( + Vc::upcast(proxy_source), + Value::new(ReferenceType::Undefined), + ) + .module(); let Some(proxy_module) = Vc::try_resolve_downcast_type::(proxy_module).await? diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_transition.rs b/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_transition.rs index 32a72b0fb609f..c2c38ffa5e209 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_transition.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/ecmascript_client_reference/ecmascript_client_reference_transition.rs @@ -2,8 +2,8 @@ use anyhow::{bail, Result}; use turbo_tasks::{Value, Vc}; use turbopack_binding::turbopack::{ core::{ + context::ProcessResult, file_source::FileSource, - module::Module, reference_type::{EntryReferenceSubType, ReferenceType}, source::Source, }, @@ -50,7 +50,7 @@ impl Transition for NextEcmascriptClientReferenceTransition { source: Vc>, context: Vc, _reference_type: Value, - ) -> Result>> { + ) -> Result> { let context = self.process_context(context); let this = self.await?; @@ -66,21 +66,27 @@ impl Transition for NextEcmascriptClientReferenceTransition { } else { source }; - let client_module = this.client_transition.process( - client_source, - context, - Value::new(ReferenceType::Entry( - EntryReferenceSubType::AppClientComponent, - )), - ); + let client_module = this + .client_transition + .process( + client_source, + context, + Value::new(ReferenceType::Entry( + EntryReferenceSubType::AppClientComponent, + )), + ) + .module(); - let ssr_module = this.ssr_transition.process( - source, - context, - Value::new(ReferenceType::Entry( - EntryReferenceSubType::AppClientComponent, - )), - ); + let ssr_module = this + .ssr_transition + .process( + source, + context, + Value::new(ReferenceType::Entry( + EntryReferenceSubType::AppClientComponent, + )), + ) + .module(); let Some(client_module) = Vc::try_resolve_sidecast::>(client_module).await? @@ -105,11 +111,14 @@ impl Transition for NextEcmascriptClientReferenceTransition { context.layer, ); - Ok(Vc::upcast(EcmascriptClientReferenceProxyModule::new( - source.ident(), - Vc::upcast(server_context), - client_module, - ssr_module, - ))) + Ok( + ProcessResult::Module(Vc::upcast(EcmascriptClientReferenceProxyModule::new( + source.ident(), + Vc::upcast(server_context), + client_module, + ssr_module, + ))) + .cell(), + ) } } diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index 9c012d17bb6ef..63a202b74af25 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -9,7 +9,7 @@ use turbopack_binding::{ turbopack::{ core::{ changed::any_content_changed_of_module, - context::AssetContext, + context::{AssetContext, ProcessResult}, file_source::FileSource, ident::AssetIdent, issue::{ @@ -849,19 +849,28 @@ async fn load_next_config_and_custom_routes_internal( ); let config_asset = config_file.map(FileSource::new); - let config_changed = config_asset.map_or_else(Completion::immutable, |config_asset| { + let config_changed = if let Some(config_asset) = config_asset { // This invalidates the execution when anything referenced by the config file // changes - let config_asset = context.process( - Vc::upcast(config_asset), - Value::new(ReferenceType::Internal(InnerAssets::empty())), - ); - any_content_changed_of_module(config_asset) - }); - let load_next_config_asset = context.process( - next_asset("entry/config/next.js".to_string()), - Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), - ); + match *context + .process( + Vc::upcast(config_asset), + Value::new(ReferenceType::Internal(InnerAssets::empty())), + ) + .await? + { + ProcessResult::Module(module) => any_content_changed_of_module(module), + ProcessResult::Ignore => Completion::immutable(), + } + } else { + Completion::immutable() + }; + let load_next_config_asset = context + .process( + next_asset("entry/config/next.js".to_string()), + Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), + ) + .module(); let config_value = evaluate( load_next_config_asset, project_path, diff --git a/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_transition.rs b/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_transition.rs index 3f82dfe025375..6ff27e070812b 100644 --- a/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_transition.rs +++ b/packages/next-swc/crates/next-core/src/next_dynamic/dynamic_transition.rs @@ -1,7 +1,7 @@ use anyhow::Result; use turbo_tasks::{Value, Vc}; use turbopack_binding::turbopack::{ - core::{module::Module, reference_type::ReferenceType, source::Source}, + core::{context::ProcessResult, reference_type::ReferenceType, source::Source}, turbopack::{ transition::{ContextTransition, Transition}, ModuleAssetContext, @@ -39,15 +39,21 @@ impl Transition for NextDynamicTransition { source: Vc>, context: Vc, _reference_type: Value, - ) -> Result>> { + ) -> Result> { let context = self.process_context(context); let this = self.await?; - let client_module = - this.client_transition - .process(source, context, Value::new(ReferenceType::Undefined)); - - Ok(Vc::upcast(NextDynamicEntryModule::new(client_module))) + Ok(match *this + .client_transition + .process(source, context, Value::new(ReferenceType::Undefined)) + .await? + { + ProcessResult::Module(client_module) => { + ProcessResult::Module(Vc::upcast(NextDynamicEntryModule::new(client_module))) + } + ProcessResult::Ignore => ProcessResult::Ignore, + } + .cell()) } } diff --git a/packages/next-swc/crates/next-core/src/next_edge/entry.rs b/packages/next-swc/crates/next-core/src/next_edge/entry.rs index 62b0833d0fc52..87adebc2bcfdf 100644 --- a/packages/next-swc/crates/next-core/src/next_edge/entry.rs +++ b/packages/next-swc/crates/next-core/src/next_edge/entry.rs @@ -39,8 +39,11 @@ pub async fn wrap_edge_entry( "MODULE".to_string() => entry }; - Ok(context.process( - Vc::upcast(virtual_source), - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - )) + let module = context + .process( + Vc::upcast(virtual_source), + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); + Ok(module) } diff --git a/packages/next-swc/crates/next-core/src/next_font/google/mod.rs b/packages/next-swc/crates/next-core/src/next_font/google/mod.rs index 094833ceca549..ece90cfc8fc1d 100644 --- a/packages/next-swc/crates/next-core/src/next_font/google/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_font/google/mod.rs @@ -446,22 +446,25 @@ async fn get_mock_stylesheet( let context = node_evaluate_asset_context(execution_context, None, None, "next_font".to_string()); let loader_path = mock_fs.root().join("loader.js".to_string()); - let mocked_response_asset = context.process( - Vc::upcast(VirtualSource::new( - loader_path, - AssetContent::file( - File::from(format!( - "import data from './{}'; export default function load() {{ return data; }};", - response_path - .file_name() - .context("Must exist")? - .to_string_lossy(), - )) - .into(), - ), - )), - Value::new(ReferenceType::Internal(InnerAssets::empty())), - ); + let mocked_response_asset = context + .process( + Vc::upcast(VirtualSource::new( + loader_path, + AssetContent::file( + File::from(format!( + "import data from './{}'; export default function load() {{ return data; \ + }};", + response_path + .file_name() + .context("Must exist")? + .to_string_lossy(), + )) + .into(), + ), + )), + Value::new(ReferenceType::Internal(InnerAssets::empty())), + ) + .module(); let root = mock_fs.root(); let val = evaluate( diff --git a/packages/next-swc/crates/next-core/src/next_image/module.rs b/packages/next-swc/crates/next-core/src/next_image/module.rs index 72369f3cec3df..459c6517cc6aa 100644 --- a/packages/next-swc/crates/next-core/src/next_image/module.rs +++ b/packages/next-swc/crates/next-core/src/next_image/module.rs @@ -1,5 +1,6 @@ +use anyhow::Result; use indexmap::indexmap; -use turbo_tasks::Vc; +use turbo_tasks::{TaskInput, Vc}; use turbopack_binding::{ turbo::tasks::Value, turbopack::{ @@ -15,7 +16,7 @@ use turbopack_binding::{ use super::source_asset::StructuredImageFileSource; #[turbo_tasks::value(serialization = "auto_for_input")] -#[derive(Clone, Copy, Debug, PartialOrd, Ord, Hash)] +#[derive(Clone, Copy, Debug, PartialOrd, Ord, Hash, TaskInput)] pub enum BlurPlaceholderMode { /// Do not generate a blur placeholder at all. None, @@ -37,30 +38,32 @@ pub struct StructuredImageModuleType { pub blur_placeholder_mode: BlurPlaceholderMode, } +#[turbo_tasks::value_impl] impl StructuredImageModuleType { - pub(crate) fn create_module( + #[turbo_tasks::function] + pub(crate) async fn create_module( source: Vc>, blur_placeholder_mode: BlurPlaceholderMode, context: Vc, - ) -> Vc> { + ) -> Result>> { let static_asset = StaticModuleAsset::new(source, Vc::upcast(context)); - context.process( - Vc::upcast( - StructuredImageFileSource { - image: source, - blur_placeholder_mode, - } - .cell(), - ), - Value::new(ReferenceType::Internal(Vc::cell(indexmap!( - "IMAGE".to_string() => Vc::upcast(static_asset) - )))), - ) + let module = context + .process( + Vc::upcast( + StructuredImageFileSource { + image: source, + blur_placeholder_mode, + } + .cell(), + ), + Value::new(ReferenceType::Internal(Vc::cell(indexmap!( + "IMAGE".to_string() => Vc::upcast(static_asset) + )))), + ) + .module(); + Ok(module) } -} -#[turbo_tasks::value_impl] -impl StructuredImageModuleType { #[turbo_tasks::function] pub fn new(blur_placeholder_mode: Value) -> Vc { StructuredImageModuleType::cell(StructuredImageModuleType { diff --git a/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs b/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs index be587ac651108..ef20616bcc540 100644 --- a/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs +++ b/packages/next-swc/crates/next-core/src/next_pages/page_entry.rs @@ -43,7 +43,9 @@ pub async fn create_page_ssr_entry_module( let definition_page = &*next_original_name.await?; let definition_pathname = &*pathname.await?; - let ssr_module = ssr_module_context.process(source, reference_type.clone()); + let ssr_module = ssr_module_context + .process(source, reference_type.clone()) + .module(); let reference_type = reference_type.into_value(); @@ -116,12 +118,14 @@ pub async fn create_page_ssr_entry_module( )); } - let mut ssr_module = ssr_module_context.process( - source, - Value::new(ReferenceType::Internal(Vc::cell(indexmap! { - INNER.to_string() => ssr_module, - }))), - ); + let mut ssr_module = ssr_module_context + .process( + source, + Value::new(ReferenceType::Internal(Vc::cell(indexmap! { + INNER.to_string() => ssr_module, + }))), + ) + .module(); if matches!(runtime, NextRuntime::Edge) { if reference_type == ReferenceType::Entry(EntryReferenceSubType::Page) { @@ -209,10 +213,12 @@ async fn wrap_edge_page( INNER.to_string() => entry }; - let wrapped = context.process( - Vc::upcast(source), - Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), - ); + let wrapped = context + .process( + Vc::upcast(source), + Value::new(ReferenceType::Internal(Vc::cell(inner_assets))), + ) + .module(); Ok(wrap_edge_entry( context, 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 41efaa11ecba1..4b2f34a4827f7 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 @@ -17,7 +17,7 @@ use turbopack_binding::{ free_var_references, resolve::{parse::Request, pattern::Pattern}, }, - ecmascript::{references::esm::UrlRewriteBehavior, TransformPlugin}, + ecmascript::{references::esm::UrlRewriteBehavior, TransformPlugin, TreeShakingMode}, ecmascript_plugin::transform::directives::client::ClientDirectiveTransformer, node::execution_context::ExecutionContext, turbopack::{ @@ -389,6 +389,7 @@ pub async fn get_server_module_options_context( execution_context: Some(execution_context), esm_url_rewrite_behavior: url_rewrite_behavior, use_lightningcss, + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() }; @@ -458,6 +459,7 @@ pub async fn get_server_module_options_context( custom_ecma_transform_plugins: base_ecma_transform_plugins, execution_context: Some(execution_context), use_lightningcss, + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() }; let foreign_code_module_options_context = ModuleOptionsContext { @@ -543,6 +545,7 @@ pub async fn get_server_module_options_context( custom_ecma_transform_plugins: base_ecma_transform_plugins, execution_context: Some(execution_context), use_lightningcss, + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() }; let foreign_code_module_options_context = ModuleOptionsContext { @@ -582,6 +585,7 @@ pub async fn get_server_module_options_context( ServerContextType::AppRoute { .. } => { let module_options_context = ModuleOptionsContext { execution_context: Some(execution_context), + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() }; let internal_module_options_context = ModuleOptionsContext { @@ -630,6 +634,7 @@ pub async fn get_server_module_options_context( let module_options_context = ModuleOptionsContext { execution_context: Some(execution_context), + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() }; let internal_module_options_context = ModuleOptionsContext { @@ -669,6 +674,7 @@ pub async fn get_server_module_options_context( pub fn get_build_module_options_context() -> Vc { ModuleOptionsContext { enable_typescript_transform: Some(Default::default()), + tree_shaking_mode: Some(TreeShakingMode::ReexportsOnly), ..Default::default() } .cell() diff --git a/packages/next-swc/crates/next-core/src/next_server/resolve.rs b/packages/next-swc/crates/next-core/src/next_server/resolve.rs index 411030c757ed1..985d8e952501e 100644 --- a/packages/next-swc/crates/next-core/src/next_server/resolve.rs +++ b/packages/next-swc/crates/next-core/src/next_server/resolve.rs @@ -187,17 +187,19 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin { // unsupported file type, bundle it Ok(ResolveResultOption::none()) } - (FileType::CommonJs, _) => { - // mark as external - Ok(ResolveResultOption::some( - ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(), - )) - } - (FileType::EcmaScriptModule, true) => { - // mark as external - Ok(ResolveResultOption::some( - ResolveResult::primary(ResolveResultItem::OriginalReferenceExternal).cell(), - )) + (FileType::CommonJs, _) | (FileType::EcmaScriptModule, true) => { + if let Some(request) = request.await?.request() { + // mark as external + Ok(ResolveResultOption::some( + ResolveResult::primary(ResolveResultItem::OriginalReferenceTypeExternal( + request, + )) + .cell(), + )) + } else { + // unsupported request, bundle it + Ok(ResolveResultOption::none()) + } } (FileType::EcmaScriptModule, false) => { // even with require() this resolves to a ESM, diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs index 8346d11d01147..1148fcc97c326 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs @@ -33,7 +33,7 @@ pub async fn get_swc_ecma_transform_plugin_impl( project_path: Vc, plugin_configs: &[(String, serde_json::Value)], ) -> Result> { - use anyhow::bail; + use anyhow::{bail, Context}; use turbo_tasks::Value; use turbo_tasks_fs::FileContent; use turbopack_binding::turbopack::{ @@ -83,9 +83,10 @@ pub async fn get_swc_ecma_transform_plugin_impl( None, ) .await?; - let Some(plugin_module) = *plugin_wasm_module_resolve_result.first_module().await? else { - bail!("Expected to find module"); - }; + let plugin_module = plugin_wasm_module_resolve_result + .first_module() + .await? + .context("Expected to find module")?; let content = &*plugin_module.content().file_content().await?; diff --git a/packages/next-swc/crates/next-core/src/page_loader.rs b/packages/next-swc/crates/next-core/src/page_loader.rs index a8b2f2a907560..aa6a6221246b4 100644 --- a/packages/next-swc/crates/next-core/src/page_loader.rs +++ b/packages/next-swc/crates/next-core/src/page_loader.rs @@ -53,15 +53,22 @@ pub async fn create_page_loader_entry_module( AssetContent::file(file.into()), )); - Ok(client_context.process( - virtual_source, - Value::new(ReferenceType::Internal(Vc::cell(indexmap! { - "PAGE".to_string() => client_context.process( - entry_asset, - Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)) - ), - }))), - )) + let module = client_context + .process( + entry_asset, + Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)), + ) + .module(); + + let module = client_context + .process( + virtual_source, + Value::new(ReferenceType::Internal(Vc::cell(indexmap! { + "PAGE".to_string() => module, + }))), + ) + .module(); + Ok(module) } #[turbo_tasks::value(shared)] diff --git a/packages/next/package.json b/packages/next/package.json index 41d7aa76bec0b..beec68c485535 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -195,7 +195,7 @@ "@types/ws": "8.2.0", "@vercel/ncc": "0.34.0", "@vercel/nft": "0.24.4", - "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231205.2", + "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2", "acorn": "8.5.0", "amphtml-validator": "1.0.35", "anser": "1.4.9", diff --git a/packages/react-refresh-utils/internal/helpers.ts b/packages/react-refresh-utils/internal/helpers.ts index 3b6aabc39a80b..fd26cc05994ee 100644 --- a/packages/react-refresh-utils/internal/helpers.ts +++ b/packages/react-refresh-utils/internal/helpers.ts @@ -73,7 +73,12 @@ function registerExportsForReactRefresh( if (isSafeExport(key)) { continue } - var exportValue = moduleExports[key] + try { + var exportValue = moduleExports[key] + } catch { + // This might fail due to circular dependencies + continue + } var typeID = moduleID + ' %exports% ' + key RefreshRuntime.register(exportValue, typeID) } @@ -91,7 +96,12 @@ function getRefreshBoundarySignature(moduleExports: unknown): Array { if (isSafeExport(key)) { continue } - var exportValue = moduleExports[key] + try { + var exportValue = moduleExports[key] + } catch { + // This might fail due to circular dependencies + continue + } signature.push(key) signature.push(RefreshRuntime.getFamilyByType(exportValue)) } @@ -113,7 +123,12 @@ function isReactRefreshBoundary(moduleExports: unknown): boolean { if (isSafeExport(key)) { continue } - var exportValue = moduleExports[key] + try { + var exportValue = moduleExports[key] + } catch { + // This might fail due to circular dependencies + return false + } if (!RefreshRuntime.isLikelyComponentType(exportValue)) { areAllExportsComponents = false } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 513a8290d8328..7aed958b5a1a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1077,8 +1077,8 @@ importers: specifier: 0.24.4 version: 0.24.4 '@vercel/turbopack-ecmascript-runtime': - specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231205.2 - version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231205.2(react-refresh@0.12.0)(webpack@5.86.0)' + specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2 + version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2(react-refresh@0.12.0)(webpack@5.86.0)' acorn: specifier: 8.5.0 version: 8.5.0 @@ -24647,9 +24647,9 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231205.2(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231205.2} - id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231205.2' + '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2(react-refresh@0.12.0)(webpack@5.86.0)': + resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2} + id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 dependencies: From 50d4578791e40a0113ac134caf49478738cf2717 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 6 Dec 2023 08:50:05 +0000 Subject: [PATCH 129/189] v14.0.4-canary.44 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 18 +++++++++--------- 18 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lerna.json b/lerna.json index 5e136c52b67bb..7de42c5f25026 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.43" + "version": "14.0.4-canary.44" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index f2e42be16b65c..e298e661af4bc 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index bd56c4f074b44..aa2465e4fbe99 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.43", + "@next/eslint-plugin-next": "14.0.4-canary.44", "@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 a115145aab69c..9a82a04ba9954 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index ba174df65a3dd..ae2d88cd24309 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "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 f4b871687d792..0a328bf7873b8 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 47764b7a10c52..e8b5383efeddd 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index f7535b5c80964..1987ee70ed2e4 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 93d3330593541..b1d7c8fcbd139 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 5cca06057f3d7..da70d85fc8fdc 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "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 204c4a38832b3..efea237dded56 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "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 212b0ac961f37..f9e1cacbd07a9 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 648665cdf944d..228168475b58d 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index beec68c485535..1f740eea86bdb 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.43", + "@next/env": "14.0.4-canary.44", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.43", - "@next/polyfill-nomodule": "14.0.4-canary.43", - "@next/react-dev-overlay": "14.0.4-canary.43", - "@next/react-refresh-utils": "14.0.4-canary.43", - "@next/swc": "14.0.4-canary.43", + "@next/polyfill-module": "14.0.4-canary.44", + "@next/polyfill-nomodule": "14.0.4-canary.44", + "@next/react-dev-overlay": "14.0.4-canary.44", + "@next/react-refresh-utils": "14.0.4-canary.44", + "@next/swc": "14.0.4-canary.44", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 94b480d735c1b..749402c5082cb 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": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 5909160ebaa1d..ad336d5f5bebf 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "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 1c38eb47ab223..7c30590156baa 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.43", + "version": "14.0.4-canary.44", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.43", + "next": "14.0.4-canary.44", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7aed958b5a1a2..1ccd49d6c84cc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.43 + specifier: 14.0.4-canary.44 version: link:../next outdent: specifier: 0.8.0 @@ -24648,7 +24648,7 @@ packages: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2} + resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2} id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 From 4f67cbfe4a26436cf2f82e31c8de24b6ff031090 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Wed, 6 Dec 2023 12:07:33 +0100 Subject: [PATCH 130/189] Move App Router client-side constants to separate file (#59239) ## What? Noticed constants.js was included in the client-side bundle. This ensures only the needed constants are included. ## How? Created a separate file for client-side constants. Closes NEXT-1789 --- packages/next/src/build/index.ts | 2 +- packages/next/src/client/components/app-router-headers.ts | 2 ++ packages/next/src/client/components/redirect-status-code.ts | 5 +++++ packages/next/src/client/components/redirect.ts | 2 +- .../components/router-reducer/fetch-server-response.ts | 2 +- packages/next/src/lib/constants.ts | 2 -- packages/next/src/lib/redirect-status.ts | 2 +- .../src/server/app-render/make-get-server-inserted-html.tsx | 2 +- packages/next/src/server/base-http/index.ts | 2 +- packages/next/src/server/base-server.ts | 4 ++-- packages/next/src/server/lib/router-server.ts | 2 +- packages/next/src/shared/lib/constants.ts | 6 ------ 12 files changed, 16 insertions(+), 17 deletions(-) create mode 100644 packages/next/src/client/components/redirect-status-code.ts diff --git a/packages/next/src/build/index.ts b/packages/next/src/build/index.ts index 23a2a852acf69..a8e3a0b821dfe 100644 --- a/packages/next/src/build/index.ts +++ b/packages/next/src/build/index.ts @@ -28,7 +28,6 @@ import { MIDDLEWARE_FILENAME, PAGES_DIR_ALIAS, INSTRUMENTATION_HOOK_FILENAME, - NEXT_DID_POSTPONE_HEADER, RSC_PREFETCH_SUFFIX, RSC_SUFFIX, } from '../lib/constants' @@ -142,6 +141,7 @@ import { RSC_HEADER, RSC_CONTENT_TYPE_HEADER, RSC_VARY_HEADER, + NEXT_DID_POSTPONE_HEADER, } from '../client/components/app-router-headers' import { webpackBuild } from './webpack-build' import { NextBuildContext } from './build-context' diff --git a/packages/next/src/client/components/app-router-headers.ts b/packages/next/src/client/components/app-router-headers.ts index 9bf9c9685347c..41bb97d1afd89 100644 --- a/packages/next/src/client/components/app-router-headers.ts +++ b/packages/next/src/client/components/app-router-headers.ts @@ -15,3 +15,5 @@ export const FLIGHT_PARAMETERS = [ ] as const export const NEXT_RSC_UNION_QUERY = '_rsc' as const + +export const NEXT_DID_POSTPONE_HEADER = 'x-nextjs-postponed' as const diff --git a/packages/next/src/client/components/redirect-status-code.ts b/packages/next/src/client/components/redirect-status-code.ts new file mode 100644 index 0000000000000..2312fcdcd7f44 --- /dev/null +++ b/packages/next/src/client/components/redirect-status-code.ts @@ -0,0 +1,5 @@ +export enum RedirectStatusCode { + SeeOther = 303, + TemporaryRedirect = 307, + PermanentRedirect = 308, +} diff --git a/packages/next/src/client/components/redirect.ts b/packages/next/src/client/components/redirect.ts index 28ad8f0fafad8..d349ee438f507 100644 --- a/packages/next/src/client/components/redirect.ts +++ b/packages/next/src/client/components/redirect.ts @@ -1,7 +1,7 @@ import { requestAsyncStorage } from './request-async-storage.external' import type { ResponseCookies } from '../../server/web/spec-extension/cookies' import { actionAsyncStorage } from './action-async-storage.external' -import { RedirectStatusCode } from '../../shared/lib/constants' +import { RedirectStatusCode } from './redirect-status-code' const REDIRECT_ERROR_CODE = 'NEXT_REDIRECT' diff --git a/packages/next/src/client/components/router-reducer/fetch-server-response.ts b/packages/next/src/client/components/router-reducer/fetch-server-response.ts index e6a7a2b87775b..b6cb4d43bb4fb 100644 --- a/packages/next/src/client/components/router-reducer/fetch-server-response.ts +++ b/packages/next/src/client/components/router-reducer/fetch-server-response.ts @@ -23,12 +23,12 @@ import { NEXT_URL, RSC_HEADER, RSC_CONTENT_TYPE_HEADER, + NEXT_DID_POSTPONE_HEADER, } from '../app-router-headers' import { urlToUrlWithoutFlightMarker } from '../app-router' import { callServer } from '../../app-call-server' import { PrefetchKind } from './router-reducer-types' import { hexHash } from '../../../shared/lib/hash' -import { NEXT_DID_POSTPONE_HEADER } from '../../../lib/constants' export type FetchServerResponseResult = [ flightData: FlightData, diff --git a/packages/next/src/lib/constants.ts b/packages/next/src/lib/constants.ts index 10e1793f5d952..707b970a7b3e8 100644 --- a/packages/next/src/lib/constants.ts +++ b/packages/next/src/lib/constants.ts @@ -6,8 +6,6 @@ export const PRERENDER_REVALIDATE_HEADER = 'x-prerender-revalidate' export const PRERENDER_REVALIDATE_ONLY_GENERATED_HEADER = 'x-prerender-revalidate-if-generated' -export const NEXT_DID_POSTPONE_HEADER = 'x-nextjs-postponed' - export const RSC_PREFETCH_SUFFIX = '.prefetch.rsc' export const RSC_SUFFIX = '.rsc' export const NEXT_DATA_SUFFIX = '.json' diff --git a/packages/next/src/lib/redirect-status.ts b/packages/next/src/lib/redirect-status.ts index d4fd5740edfd2..95a18b00ee584 100644 --- a/packages/next/src/lib/redirect-status.ts +++ b/packages/next/src/lib/redirect-status.ts @@ -1,4 +1,4 @@ -import { RedirectStatusCode } from '../shared/lib/constants' +import { RedirectStatusCode } from '../client/components/redirect-status-code' export const allowedStatusCodes = new Set([301, 302, 303, 307, 308]) diff --git a/packages/next/src/server/app-render/make-get-server-inserted-html.tsx b/packages/next/src/server/app-render/make-get-server-inserted-html.tsx index 11c8e7ec46298..64b8a55cd4720 100644 --- a/packages/next/src/server/app-render/make-get-server-inserted-html.tsx +++ b/packages/next/src/server/app-render/make-get-server-inserted-html.tsx @@ -7,7 +7,7 @@ import { } from '../../client/components/redirect' import { renderToReadableStream } from 'react-dom/server.edge' import { streamToString } from '../stream-utils/node-web-streams-helper' -import { RedirectStatusCode } from '../../shared/lib/constants' +import { RedirectStatusCode } from '../../client/components/redirect-status-code' export function makeGetServerInsertedHTML({ polyfills, diff --git a/packages/next/src/server/base-http/index.ts b/packages/next/src/server/base-http/index.ts index 63c5035f13384..ad3454bd67463 100644 --- a/packages/next/src/server/base-http/index.ts +++ b/packages/next/src/server/base-http/index.ts @@ -1,7 +1,7 @@ import type { IncomingHttpHeaders, OutgoingHttpHeaders } from 'http' import type { I18NConfig } from '../config-shared' -import { RedirectStatusCode } from '../../shared/lib/constants' +import { RedirectStatusCode } from '../../client/components/redirect-status-code' import type { NextApiRequestCookies } from '../api-utils' import { getCookieParser } from '../api-utils/get-cookie-parser' diff --git a/packages/next/src/server/base-server.ts b/packages/next/src/server/base-server.ts index a06bc4ab55879..aa586d8a9ab36 100644 --- a/packages/next/src/server/base-server.ts +++ b/packages/next/src/server/base-server.ts @@ -50,9 +50,9 @@ import { APP_PATHS_MANIFEST, NEXT_BUILTIN_DOCUMENT, PAGES_MANIFEST, - RedirectStatusCode, STATIC_STATUS_PAGES, } from '../shared/lib/constants' +import { RedirectStatusCode } from '../client/components/redirect-status-code' import { isDynamicRoute } from '../shared/lib/router/utils' import { checkIsOnDemandRevalidate } from './api-utils' import { setConfig } from '../shared/lib/runtime-config.external' @@ -83,6 +83,7 @@ import { RSC_VARY_HEADER, NEXT_RSC_UNION_QUERY, NEXT_ROUTER_PREFETCH_HEADER, + NEXT_DID_POSTPONE_HEADER, } from '../client/components/app-router-headers' import type { MatchOptions, @@ -107,7 +108,6 @@ import { import { CACHE_ONE_YEAR, NEXT_CACHE_TAGS_HEADER, - NEXT_DID_POSTPONE_HEADER, NEXT_QUERY_PARAM_PREFIX, } from '../lib/constants' import { normalizeLocalePath } from '../shared/lib/i18n/normalize-locale-path' diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index d3dbc5eeb3ee7..2163dbdf7d268 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -29,8 +29,8 @@ import { isPostpone } from './router-utils/is-postpone' import { PHASE_PRODUCTION_SERVER, PHASE_DEVELOPMENT_SERVER, - RedirectStatusCode, } from '../../shared/lib/constants' +import { RedirectStatusCode } from '../../client/components/redirect-status-code' import { DevBundlerService } from './dev-bundler-service' import { type Span, trace } from '../../trace' diff --git a/packages/next/src/shared/lib/constants.ts b/packages/next/src/shared/lib/constants.ts index d02e14896c7ac..a803579c59671 100644 --- a/packages/next/src/shared/lib/constants.ts +++ b/packages/next/src/shared/lib/constants.ts @@ -154,9 +154,3 @@ export const SYSTEM_ENTRYPOINTS = new Set([ CLIENT_STATIC_FILES_RUNTIME_AMP, CLIENT_STATIC_FILES_RUNTIME_MAIN_APP, ]) - -export enum RedirectStatusCode { - SeeOther = 303, - TemporaryRedirect = 307, - PermanentRedirect = 308, -} From f6ebc2be771fbe67ce2172c6e71cec24def29689 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 6 Dec 2023 11:10:39 +0000 Subject: [PATCH 131/189] v14.0.4-canary.45 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 7de42c5f25026..755cac8639689 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.44" + "version": "14.0.4-canary.45" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index e298e661af4bc..571ee41689535 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index aa2465e4fbe99..2c18fb540d554 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.44", + "@next/eslint-plugin-next": "14.0.4-canary.45", "@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 9a82a04ba9954..613222dc0100d 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index ae2d88cd24309..ee7d68ba10e71 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "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 0a328bf7873b8..848610f7d3f92 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index e8b5383efeddd..0d1600b0e60b5 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 1987ee70ed2e4..6d37cc7afd926 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index b1d7c8fcbd139..cb154dd084af2 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index da70d85fc8fdc..1ac5536401946 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "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 efea237dded56..0d7a8496c2481 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "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 f9e1cacbd07a9..975a05a6249ce 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 228168475b58d..048dd671f77b4 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 1f740eea86bdb..50c07ff4af078 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.44", + "@next/env": "14.0.4-canary.45", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.44", - "@next/polyfill-nomodule": "14.0.4-canary.44", - "@next/react-dev-overlay": "14.0.4-canary.44", - "@next/react-refresh-utils": "14.0.4-canary.44", - "@next/swc": "14.0.4-canary.44", + "@next/polyfill-module": "14.0.4-canary.45", + "@next/polyfill-nomodule": "14.0.4-canary.45", + "@next/react-dev-overlay": "14.0.4-canary.45", + "@next/react-refresh-utils": "14.0.4-canary.45", + "@next/swc": "14.0.4-canary.45", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 749402c5082cb..3d569e5abb7d5 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": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index ad336d5f5bebf..71284d41a73a3 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "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 7c30590156baa..a3aa45b2ddc97 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.44", + "version": "14.0.4-canary.45", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.44", + "next": "14.0.4-canary.45", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1ccd49d6c84cc..c7914d41ce211 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.44 + specifier: 14.0.4-canary.45 version: link:../next outdent: specifier: 0.8.0 From 182a4b44f4930108e969e7232e09aea7d5b66e8a Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 6 Dec 2023 14:48:05 +0100 Subject: [PATCH 132/189] reduce function calls in walk (#59332) ### What? Reduce the number of function calls ### Why? Performance on incremental builds ### How? Closes PACK-2104 --- .../visit_client_reference.rs | 18 +++-------------- .../src/next_dynamic/visit_dynamic.rs | 20 ++++--------------- 2 files changed, 7 insertions(+), 31 deletions(-) diff --git a/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs b/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs index f4bf3c0a64a9f..5c47b1e94c719 100644 --- a/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs +++ b/packages/next-swc/crates/next-core/src/next_client_reference/visit_client_reference.rs @@ -12,7 +12,7 @@ use turbo_tasks::{ }; use turbopack_binding::turbopack::core::{ module::{Module, Modules}, - reference::ModuleReference, + reference::primary_referenced_modules, }; use super::{ @@ -179,21 +179,9 @@ impl Visit for VisitClientReference { // nodes' edges. VisitClientReferenceNodeType::ClientReference(..) => Ok(vec![]), VisitClientReferenceNodeType::Internal(module, _) => { - let references = module.references().await?; + let referenced_modules = primary_referenced_modules(module).await?; - let referenced_modules = references - .iter() - .copied() - .map(|reference| async move { - let resolve_result = reference.resolve_reference(); - let assets = resolve_result.primary_modules().await?; - Ok(assets.clone_value()) - }) - .try_join() - .await?; - let referenced_modules = referenced_modules.into_iter().flatten(); - - let referenced_modules = referenced_modules.map(|module| async move { + let referenced_modules = referenced_modules.iter().map(|module| async move { let module = module.resolve().await?; if let Some(client_reference_module) = Vc::try_resolve_downcast_type::(module) diff --git a/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs b/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs index 6b89f807b2664..486dfb4dc5f82 100644 --- a/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs +++ b/packages/next-swc/crates/next-core/src/next_dynamic/visit_dynamic.rs @@ -8,7 +8,7 @@ use turbo_tasks::{ }; use turbopack_binding::turbopack::core::{ module::{Module, Modules}, - reference::ModuleReference, + reference::primary_referenced_modules, }; use super::NextDynamicEntryModule; @@ -89,21 +89,9 @@ impl Visit for VisitDynamic { VisitDynamicNode::Internal(module, _) => module, }; - let references = module.references().await?; - - let referenced_modules = references - .iter() - .copied() - .map(|reference| async move { - let resolve_result = reference.resolve_reference(); - let assets = resolve_result.primary_modules().await?; - Ok(assets.clone_value()) - }) - .try_join() - .await?; - let referenced_modules = referenced_modules.into_iter().flatten(); - - let referenced_modules = referenced_modules.map(|module| async move { + let referenced_modules = primary_referenced_modules(module).await?; + + let referenced_modules = referenced_modules.iter().map(|module| async move { let module = module.resolve().await?; if let Some(next_dynamic_module) = Vc::try_resolve_downcast_type::(module).await? From 8db04a8332daacdabf6c4a3378613102d6e401c9 Mon Sep 17 00:00:00 2001 From: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com> Date: Wed, 6 Dec 2023 08:49:58 -0500 Subject: [PATCH 133/189] Update Turbopack test manifest (#59326) This auto-generated PR updates the integration test manifest used when testing Turbopack. --- test/turbopack-tests-manifest.json | 191 +++++++++++++++++------------ 1 file changed, 112 insertions(+), 79 deletions(-) diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index 5bc1830d28c67..6a152e9827840 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -338,7 +338,6 @@ "packages/next/src/client/components/router-reducer/reducers/server-patch-reducer.test.tsx": { "passed": [ "serverPatchReducer should apply server patch", - "serverPatchReducer should apply server patch (concurrent)", "serverPatchReducer should apply server patch without affecting focusAndScrollRef" ], "failed": [], @@ -828,7 +827,8 @@ "getNamedRouteRegex should handle interception markers not adjacent to dynamic path segments", "getNamedRouteRegex should handle multi-level interception markers", "getNamedRouteRegex should handle optional catch-all dynamic path segments", - "getNamedRouteRegex should handle optional dynamic path segments" + "getNamedRouteRegex should handle optional dynamic path segments", + "getNamedRouteRegex should match named routes correctly when interception markers are adjacent to dynamic segments" ], "failed": [], "pending": [], @@ -1459,8 +1459,8 @@ "optimizePackageImports app - should render the icons correctly without creating all the modules", "optimizePackageImports pages - should optimize recursive wildcard export mapping", "optimizePackageImports pages - should render the icons correctly without creating all the modules", - "optimizePackageImports should support visx", - "optimizePackageImports should support MUI" + "optimizePackageImports should support MUI", + "optimizePackageImports should support visx" ], "pending": [], "flakey": [], @@ -1604,6 +1604,7 @@ "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import default behavior should render dynamic import components using a function as first parameter", "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import default behavior should render even there are no physical chunk exists", "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import default behavior should render the component Head content", + "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import ssr:false option should import and render the ESM module correctly on client side", "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import ssr:false option should not render loading on the server side", "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import ssr:false option should render the component on client side", "basic next/dynamic usage, basePath: \"\" with \"document.getInitialProps\" compiler document.getInitialProps Dynamic import ssr:true option Should render the component on the server side", @@ -1616,6 +1617,7 @@ "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import default behavior should render dynamic import components using a function as first parameter", "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import default behavior should render even there are no physical chunk exists", "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import default behavior should render the component Head content", + "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import ssr:false option should import and render the ESM module correctly on client side", "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import ssr:false option should not render loading on the server side", "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import ssr:false option should render the component on client side", "basic next/dynamic usage, basePath: \"\" with \"swc\" compiler swc Dynamic import ssr:true option Should render the component on the server side", @@ -1628,6 +1630,7 @@ "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import default behavior should render dynamic import components using a function as first parameter", "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import default behavior should render even there are no physical chunk exists", "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import default behavior should render the component Head content", + "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import ssr:false option should import and render the ESM module correctly on client side", "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import ssr:false option should not render loading on the server side", "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import ssr:false option should render the component on client side", "basic next/dynamic usage, basePath: \"/docs\" with \"swc\" compiler swc Dynamic import ssr:true option Should render the component on the server side", @@ -1648,6 +1651,7 @@ "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import default behavior should render dynamic import components using a function as first parameter", "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import default behavior should render even there are no physical chunk exists", "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import default behavior should render the component Head content", + "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import ssr:false option should import and render the ESM module correctly on client side", "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import ssr:false option should not render loading on the server side", "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import ssr:false option should render the component on client side", "basic next/dynamic usage, basePath: \"\" with \"babel\" compiler babel Dynamic import ssr:true option Should render the component on the server side", @@ -2271,7 +2275,8 @@ "app-dir action handling should support notFound (javascript disabled)", "app-dir action handling should support setting cookies in route handlers with the correct overrides", "app-dir action handling should support uploading files", - "app-dir action handling should trigger a refresh for a server action that gets discarded due to a navigation" + "app-dir action handling should trigger a refresh for a server action that gets discarded due to a navigation", + "app-dir action handling should work with interception routes" ], "failed": [], "pending": [ @@ -2430,6 +2435,8 @@ }, "test/e2e/app-dir/app-external/app-external.test.ts": { "passed": [ + "app dir - external dependency mixed syntax external modules should handle mixed module in server and client components", + "app dir - external dependency mixed syntax external modules should handle mixed module with next/dynamic", "app dir - external dependency react in external esm packages should use the same react in client app", "app dir - external dependency react in external esm packages should use the same react in edge server app", "app dir - external dependency react in external esm packages should use the same react in pages", @@ -2938,6 +2945,7 @@ "app dir - basic should not serve when layout is provided but no folder index", "app dir - basic should not share edge workers", "app dir - basic should pass props from getServerSideProps in root layout", + "app dir - basic should return normalized dynamic route params for catch-all edge page", "app dir - basic should return the `vary` header from edge runtime", "app dir - basic should return the `vary` header from pages for flight requests", "app dir - basic should serve /index as separate page", @@ -3317,8 +3325,18 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/interception-dynamic-segment/interception-dynamic-segment.test.ts": { + "passed": [ + "interception-dynamic-segment should work when interception route is paired with a dynamic segment" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/interception-middleware-rewrite/interception-middleware-rewrite.test.ts": { "passed": [ + "interception-middleware-rewrite should continue to show the intercepted page when revisiting it", "interception-middleware-rewrite should continue to work after using browser back button and following another intercepting route", "interception-middleware-rewrite should support intercepting routes with a middleware rewrite" ], @@ -3597,20 +3615,20 @@ "test/e2e/app-dir/next-font/next-font.test.ts": { "passed": [], "failed": [ - "app app dir - next-font Dev errors should recover on font loader error", - "app app dir - next-font computed styles should have correct styles at /", - "app app dir - next-font computed styles should have correct styles at /client", - "app app dir - next-font import values should have correct values at /", - "app app dir - next-font import values should have correct values at /client", - "app app dir - next-font import values should transform code in node_modules", - "app app dir - next-font navigation should not have duplicate preload tags on navigation", - "app-old app dir - next-font Dev errors should recover on font loader error", - "app-old app dir - next-font computed styles should have correct styles at /", - "app-old app dir - next-font computed styles should have correct styles at /client", - "app-old app dir - next-font import values should have correct values at /", - "app-old app dir - next-font import values should have correct values at /client", - "app-old app dir - next-font import values should transform code in node_modules", - "app-old app dir - next-font navigation should not have duplicate preload tags on navigation" + "app dir - next/font app app dir - next-font Dev errors should recover on font loader error", + "app dir - next/font app app dir - next-font computed styles should have correct styles at /", + "app dir - next/font app app dir - next-font computed styles should have correct styles at /client", + "app dir - next/font app app dir - next-font import values should have correct values at /", + "app dir - next/font app app dir - next-font import values should have correct values at /client", + "app dir - next/font app app dir - next-font import values should transform code in node_modules", + "app dir - next/font app app dir - next-font navigation should not have duplicate preload tags on navigation", + "app dir - next/font app-old app dir - next-font Dev errors should recover on font loader error", + "app dir - next/font app-old app dir - next-font computed styles should have correct styles at /", + "app dir - next/font app-old app dir - next-font computed styles should have correct styles at /client", + "app dir - next/font app-old app dir - next-font import values should have correct values at /", + "app dir - next/font app-old app dir - next-font import values should have correct values at /client", + "app dir - next/font app-old app dir - next-font import values should transform code in node_modules", + "app dir - next/font app-old app dir - next-font navigation should not have duplicate preload tags on navigation" ], "pending": [], "flakey": [], @@ -3791,17 +3809,17 @@ "runtimeError": false }, "test/e2e/app-dir/ppr-errors/ppr-errors.test.ts": { - "passed": [ - "ppr build errors outside of a suspense boundary should fail the build for uncaught errors", - "ppr build errors outside of a suspense boundary when a postpone call was made but missing postpone data should fail the build", - "ppr build errors outside of a suspense boundary when a postpone call was made but missing postpone data should fail the build & surface any errors that were thrown by user code", - "ppr build errors when a postpone call is caught and logged it should should include a message telling why", - "ppr build errors within a suspense boundary should fail the build for uncaught prerender errors", - "ppr build errors within a suspense boundary when a postpone call was made but missing postpone data should fail the build", - "ppr build errors within a suspense boundary when a postpone call was made but missing postpone data should fail the build & surface any errors that were thrown by user code" - ], + "passed": [], "failed": [], - "pending": [], + "pending": [ + "ppr build errors production mode outside of a suspense boundary should fail the build for uncaught errors", + "ppr build errors production mode outside of a suspense boundary when a postpone call was made but missing postpone data should fail the build", + "ppr build errors production mode outside of a suspense boundary when a postpone call was made but missing postpone data should fail the build & surface any errors that were thrown by user code", + "ppr build errors production mode when a postpone call is caught and logged it should should include a message telling why", + "ppr build errors production mode within a suspense boundary should fail the build for uncaught prerender errors", + "ppr build errors production mode within a suspense boundary when a postpone call was made but missing postpone data should fail the build", + "ppr build errors production mode within a suspense boundary when a postpone call was made but missing postpone data should fail the build & surface any errors that were thrown by user code" + ], "flakey": [], "runtimeError": false }, @@ -5013,6 +5031,7 @@ "Middleware Runtime with i18n allows to access env variables", "Middleware Runtime with i18n hard-navigates when the data request failed", "Middleware Runtime with i18n passes search params with rewrites", + "Middleware Runtime with i18n refreshes the page when middleware changes ", "Middleware Runtime with i18n should accept a URL instance for fetch", "Middleware Runtime with i18n should add a rewrite header on data requests for rewrites", "Middleware Runtime with i18n should allow to abort a fetch request", @@ -5050,6 +5069,7 @@ "Middleware Runtime without i18n allows to access env variables", "Middleware Runtime without i18n hard-navigates when the data request failed", "Middleware Runtime without i18n passes search params with rewrites", + "Middleware Runtime without i18n refreshes the page when middleware changes ", "Middleware Runtime without i18n should accept a URL instance for fetch", "Middleware Runtime without i18n should add a rewrite header on data requests for rewrites", "Middleware Runtime without i18n should allow to abort a fetch request", @@ -5062,6 +5082,7 @@ "Middleware Runtime without i18n should have correct route params for chained rewrite from middleware to config rewrite", "Middleware Runtime without i18n should have correct route params for rewrite from config dynamic route", "Middleware Runtime without i18n should have correct route params for rewrite from config non-dynamic route", + "Middleware Runtime without i18n should have init header for NextResponse.redirect", "Middleware Runtime without i18n should keep non data requests in their original shape", "Middleware Runtime without i18n should normalize data requests into page requests", "Middleware Runtime without i18n should only contain middleware route in dev middleware manifest", @@ -5081,11 +5102,7 @@ "Middleware Runtime without i18n should warn when using Response.redirect with a relative URL", "Middleware Runtime without i18n should work with notFound: true correctly" ], - "failed": [ - "Middleware Runtime with i18n refreshes the page when middleware changes ", - "Middleware Runtime without i18n refreshes the page when middleware changes ", - "Middleware Runtime without i18n should have init header for NextResponse.redirect" - ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -5273,9 +5290,11 @@ "test/e2e/middleware-trailing-slash/test/index.test.ts": { "passed": [ "Middleware Runtime trailing slash allows shallow linking with middleware", + "Middleware Runtime trailing slash refreshes the page when middleware changes ", "Middleware Runtime trailing slash should add a rewrite header on data requests for rewrites", "Middleware Runtime trailing slash should have correct dynamic route params for middleware rewrite to dynamic route", "Middleware Runtime trailing slash should have correct dynamic route params on client-transition to dynamic route", + "Middleware Runtime trailing slash should have correct query values for rewrite to ssg page", "Middleware Runtime trailing slash should have correct route params for chained rewrite from middleware to config rewrite", "Middleware Runtime trailing slash should have correct route params for rewrite from config dynamic route", "Middleware Runtime trailing slash should have correct route params for rewrite from config non-dynamic route", @@ -5295,10 +5314,7 @@ "Middleware Runtime trailing slash without .html extension should work when navigating", "Middleware Runtime trailing slash without .html extension should work when requesting the page directly" ], - "failed": [ - "Middleware Runtime trailing slash refreshes the page when middleware changes ", - "Middleware Runtime trailing slash should have correct query values for rewrite to ssg page" - ], + "failed": [], "pending": [], "flakey": [], "runtimeError": false @@ -5862,6 +5878,26 @@ "flakey": [], "runtimeError": false }, + "test/e2e/testmode/testmode.test.ts": { + "passed": [ + "testmode app router should handle API with fetch in edge function", + "testmode app router should handle API with fetch in serverless function", + "testmode app router should handle API with http.get in serverless function", + "testmode app router should handle RSC with fetch in edge function", + "testmode app router should handle RSC with fetch in serverless function", + "testmode app router should handle RSC with http.get in serverless function", + "testmode middleware should intercept fetchs in middleware", + "testmode page router should handle API with fetch", + "testmode page router should handle API with http.get", + "testmode page router should handle getServerSideProps with fetch", + "testmode page router should handle getServerSideProps with http.get", + "testmode rewrites should handle rewrites" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/third-parties/index.test.ts": { "passed": [ "@next/third-parties basic usage renders GTM", @@ -6797,11 +6833,10 @@ "runtimeError": false }, "test/integration/clean-distdir/test/index.test.js": { - "passed": [ - "Cleaning distDir disabled write should not clean up .next before build start" - ], + "passed": [], "failed": [], "pending": [ + "Cleaning distDir production mode disabled write should not clean up .next before build start", "Cleaning distDir production mode should clean up .next before build start" ], "flakey": [], @@ -6809,13 +6844,6 @@ }, "test/integration/cli/test/index.test.js": { "passed": [ - "CLI Usage build --help", - "CLI Usage build -h", - "CLI Usage build invalid directory", - "CLI Usage build should exit when SIGINT is signalled", - "CLI Usage build should exit when SIGTERM is signalled", - "CLI Usage build should not throw UnhandledPromiseRejectionWarning", - "CLI Usage build should warn when unknown argument provided", "CLI Usage dev --experimental-https", "CLI Usage dev --experimental-https with provided key/cert", "CLI Usage dev --help", @@ -6850,6 +6878,13 @@ ], "failed": [], "pending": [ + "CLI Usage production mode build --help", + "CLI Usage production mode build -h", + "CLI Usage production mode build invalid directory", + "CLI Usage production mode build should exit when SIGINT is signalled", + "CLI Usage production mode build should exit when SIGTERM is signalled", + "CLI Usage production mode build should not throw UnhandledPromiseRejectionWarning", + "CLI Usage production mode build should warn when unknown argument provided", "CLI Usage production mode start --help", "CLI Usage production mode start --keepAliveTimeout Infinity", "CLI Usage production mode start --keepAliveTimeout happy path", @@ -6932,18 +6967,19 @@ }, "test/integration/config-experimental-warning/test/index.test.js": { "passed": [ - "Config Experimental Warning should not show next app info in next start", "Config Experimental Warning should not show warning with config from object", "Config Experimental Warning should not show warning with default config from function", "Config Experimental Warning should not show warning with default value", - "Config Experimental Warning should show next app info with all experimental features in next build", - "Config Experimental Warning should show unrecognized experimental features in warning but not in start log experiments section", "Config Experimental Warning should show warning with config from function with experimental", "Config Experimental Warning should show warning with config from object with experimental", "Config Experimental Warning should show warning with config from object with experimental and multiple keys" ], "failed": [], - "pending": [], + "pending": [ + "Config Experimental Warning production mode should not show next app info in next start", + "Config Experimental Warning production mode should show next app info with all experimental features in next build", + "Config Experimental Warning production mode should show unrecognized experimental features in warning but not in start log experiments section" + ], "flakey": [], "runtimeError": false }, @@ -7340,14 +7376,14 @@ }, "test/integration/css/test/css-modules.test.js": { "passed": [ + "CSS Modules Composes Ordering Development Mode should have correct color on index page (on hover)", + "CSS Modules Composes Ordering Development Mode should have correct color on index page (on load)", "Ordering with Global CSS and Modules (dev) should not execute scripts in any order" ], "failed": [ "Basic CSS Modules Ordering Development Mode should have correct color on index page (on hover)", "Basic CSS Modules Ordering Development Mode should have correct color on index page (on load)", "Basic CSS Modules Ordering Development Mode should have correct color on index page (on nav)", - "CSS Modules Composes Ordering Development Mode should have correct color on index page (on hover)", - "CSS Modules Composes Ordering Development Mode should have correct color on index page (on load)", "Ordering with Global CSS and Modules (dev) should have the correct color (css ordering)", "Ordering with Global CSS and Modules (dev) should have the correct color (css ordering) during hot reloads" ], @@ -13410,15 +13446,14 @@ "runtimeError": false }, "test/integration/page-extensions/test/index.test.js": { - "passed": [ - "Page Extensions should throw if pageExtensions has invalid extensions", - "Page Extensions should throw if pageExtensions is an empty array" - ], - "failed": [ - "Page Extensions should not throw if .d.ts file inside the pages folder", - "Page Extensions should use the default pageExtensions if set to undefined" + "passed": [], + "failed": [], + "pending": [ + "Page Extensions production mode should not throw if .d.ts file inside the pages folder", + "Page Extensions production mode should throw if pageExtensions has invalid extensions", + "Page Extensions production mode should throw if pageExtensions is an empty array", + "Page Extensions production mode should use the default pageExtensions if set to undefined" ], - "pending": [], "flakey": [], "runtimeError": false }, @@ -13736,15 +13771,14 @@ "Basics default setting with react 18 dev should contain dynamicIds in next data for dynamic imports", "Basics default setting with react 18 dev should only render once in SSR", "Basics default setting with react 18 dev useId() values should match on hydration", + "Concurrent mode in the experimental-edge runtime dev should not have the initial route announced", "Concurrent mode in the experimental-edge runtime dev flushes styled-jsx styles as the page renders", "Concurrent mode in the experimental-edge runtime dev should not have invalid config warning", "Concurrent mode in the nodejs runtime dev should not have the initial route announced", "Concurrent mode in the nodejs runtime dev flushes styled-jsx styles as the page renders", "Concurrent mode in the nodejs runtime dev should not have invalid config warning" ], - "failed": [ - "Concurrent mode in the experimental-edge runtime dev should not have the initial route announced" - ], + "failed": [], "pending": [ "Basics production mode default setting with react 18 prod hydrates correctly for normal page", "Basics production mode default setting with react 18 prod no warnings for image related link props", @@ -14597,23 +14631,22 @@ "Telemetry CLI can print telemetry status", "Telemetry CLI can re-disable telemetry", "Telemetry CLI can re-enable telemetry", - "Telemetry CLI cli session: babel tooling config", - "Telemetry CLI cli session: custom babel config (plugin)", - "Telemetry CLI cli session: custom babel config (preset)", - "Telemetry CLI cli session: next config with webpack", - "Telemetry CLI cli session: package.json custom babel config (plugin)", - "Telemetry CLI detects correct cli session defaults", - "Telemetry CLI detects isSrcDir dir correctly for `next dev`", - "Telemetry CLI emits event when swc fails to load" - ], - "failed": [ - "Telemetry CLI detects isSrcDir dir correctly for `next build`", - "Telemetry CLI detects tests correctly for `next build`", - "Telemetry CLI logs completed `next build` with warnings" + "Telemetry CLI detects isSrcDir dir correctly for `next dev`" ], + "failed": [], "pending": [ + "Telemetry CLI production mode cli session: babel tooling config", + "Telemetry CLI production mode cli session: custom babel config (plugin)", + "Telemetry CLI production mode cli session: custom babel config (preset)", + "Telemetry CLI production mode cli session: next config with webpack", + "Telemetry CLI production mode cli session: package.json custom babel config (plugin)", "Telemetry CLI production mode detect page counts correctly for `next build`", - "Telemetry CLI production mode detect static 404 correctly for `next build`" + "Telemetry CLI production mode detect static 404 correctly for `next build`", + "Telemetry CLI production mode detects correct cli session defaults", + "Telemetry CLI production mode detects isSrcDir dir correctly for `next build`", + "Telemetry CLI production mode detects tests correctly for `next build`", + "Telemetry CLI production mode emits event when swc fails to load", + "Telemetry CLI production mode logs completed `next build` with warnings" ], "flakey": [], "runtimeError": false From 34e9d65d29dc08f35ee39dc221fd1f9104b59990 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 6 Dec 2023 17:20:52 +0100 Subject: [PATCH 134/189] update turbopack (#59334) * https://github.com/vercel/turbo/pull/6716 * https://github.com/vercel/turbo/pull/6718 --- Cargo.lock | 68 +++++++++++++++++++------------------- Cargo.toml | 6 ++-- packages/next/package.json | 2 +- pnpm-lock.yaml | 10 +++--- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ae5ea955e73a..7aaa83880d4fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,7 +322,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "serde", "smallvec", @@ -3549,7 +3549,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "serde", @@ -7678,7 +7678,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-trait", @@ -7710,7 +7710,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "cargo-lock", @@ -7722,7 +7722,7 @@ dependencies = [ [[package]] name = "turbo-tasks-bytes" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "bytes", @@ -7737,7 +7737,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "dotenvs", @@ -7751,7 +7751,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7768,7 +7768,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "auto-hash-map", @@ -7799,7 +7799,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "base16", "hex", @@ -7811,7 +7811,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -7825,7 +7825,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "proc-macro2", "quote", @@ -7835,7 +7835,7 @@ dependencies = [ [[package]] name = "turbo-tasks-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "mimalloc", ] @@ -7843,7 +7843,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "auto-hash-map", @@ -7868,7 +7868,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-recursion", @@ -7900,7 +7900,7 @@ dependencies = [ [[package]] name = "turbopack-binding" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "auto-hash-map", "mdxjs", @@ -7941,7 +7941,7 @@ dependencies = [ [[package]] name = "turbopack-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -7965,7 +7965,7 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "clap 4.4.2", @@ -7983,7 +7983,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-recursion", @@ -8013,7 +8013,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-trait", @@ -8040,7 +8040,7 @@ dependencies = [ [[package]] name = "turbopack-dev" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8064,7 +8064,7 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-compression", @@ -8101,7 +8101,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-trait", @@ -8135,7 +8135,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-hmr-protocol" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "serde", "serde_json", @@ -8146,7 +8146,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-plugins" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-trait", @@ -8169,7 +8169,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-runtime" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "indoc", @@ -8186,7 +8186,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "indexmap 1.9.3", @@ -8202,7 +8202,7 @@ dependencies = [ [[package]] name = "turbopack-image" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "base64 0.21.4", @@ -8222,7 +8222,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "serde", @@ -8237,7 +8237,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "mdxjs", @@ -8252,7 +8252,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "async-stream", @@ -8287,7 +8287,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "serde", @@ -8303,7 +8303,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "swc_core", "turbo-tasks", @@ -8314,7 +8314,7 @@ dependencies = [ [[package]] name = "turbopack-trace-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "crossbeam-channel", @@ -8329,7 +8329,7 @@ dependencies = [ [[package]] name = "turbopack-wasm" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.2#16bbf81a2a45b85737e569312b1ee76eec6c388c" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-231206.4#f99cd2550f9f4c2b89e173532cc72797d613b82f" dependencies = [ "anyhow", "indexmap 1.9.3", diff --git a/Cargo.toml b/Cargo.toml index 6cc2e8c07e971..acfb04cae500b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,11 +43,11 @@ swc_core = { version = "0.86.81", features = [ testing = { version = "0.35.11" } # Turbo crates -turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.2" } +turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.4" } # [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros.. -turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.2" } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.4" } # [TODO]: need to refactor embed_directory! macro usage in next-core -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.2" } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-231206.4" } # General Deps diff --git a/packages/next/package.json b/packages/next/package.json index 50c07ff4af078..cdfad7f848dbb 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -195,7 +195,7 @@ "@types/ws": "8.2.0", "@vercel/ncc": "0.34.0", "@vercel/nft": "0.24.4", - "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2", + "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4", "acorn": "8.5.0", "amphtml-validator": "1.0.35", "anser": "1.4.9", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c7914d41ce211..6af67e9323cb7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1077,8 +1077,8 @@ importers: specifier: 0.24.4 version: 0.24.4 '@vercel/turbopack-ecmascript-runtime': - specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2 - version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2(react-refresh@0.12.0)(webpack@5.86.0)' + specifier: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4 + version: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4(react-refresh@0.12.0)(webpack@5.86.0)' acorn: specifier: 8.5.0 version: 8.5.0 @@ -24647,9 +24647,9 @@ packages: /zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2} - id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.2' + '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4(react-refresh@0.12.0)(webpack@5.86.0)': + resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4} + id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 dependencies: From 99b9304bf15c630d5811285c2383a25b09fbf516 Mon Sep 17 00:00:00 2001 From: Tobias Koppers Date: Wed, 6 Dec 2023 17:34:06 +0100 Subject: [PATCH 135/189] disable unused next/dynamic walking in app dir (#59338) ### What? remove expensive unused code Closes PACK-2108 --- packages/next-swc/crates/next-api/src/app.rs | 49 ++++++++++---------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/packages/next-swc/crates/next-api/src/app.rs b/packages/next-swc/crates/next-api/src/app.rs index 1f4c52511d754..10a0c8f539942 100644 --- a/packages/next-swc/crates/next-api/src/app.rs +++ b/packages/next-swc/crates/next-api/src/app.rs @@ -22,7 +22,7 @@ use next_core::{ next_client_reference::{ ClientReferenceGraph, ClientReferenceType, NextEcmascriptClientReferenceTransition, }, - next_dynamic::{NextDynamicEntries, NextDynamicTransition}, + next_dynamic::NextDynamicTransition, next_edge::route_regex::get_named_middleware_regex, next_manifests::{ AppBuildManifest, AppPathsManifest, BuildManifest, ClientReferenceManifest, @@ -584,30 +584,31 @@ impl AppEndpoint { let client_reference_types = client_reference_graph.types(); let client_references = client_reference_graph.entry(rsc_entry_asset); - let app_ssr_entries: Vec<_> = client_reference_types - .await? - .iter() - .map(|client_reference_ty| async move { - let ClientReferenceType::EcmascriptClientReference(entry) = client_reference_ty - else { - return Ok(None); - }; - - Ok(Some(entry.await?.ssr_module)) - }) - .try_join() - .await? - .into_iter() - .flatten() - .collect(); - - let app_node_entries: Vec<_> = app_ssr_entries.iter().copied().chain([rsc_entry]).collect(); - // TODO(alexkirsz) Handle dynamic entries and dynamic chunks. - let _dynamic_entries = NextDynamicEntries::from_entries(Vc::cell( - app_node_entries.iter().copied().map(Vc::upcast).collect(), - )) - .await?; + // let app_ssr_entries: Vec<_> = client_reference_types + // .await? + // .iter() + // .map(|client_reference_ty| async move { + // let ClientReferenceType::EcmascriptClientReference(entry) = + // client_reference_ty else { + // return Ok(None); + // }; + + // Ok(Some(entry.await?.ssr_module)) + // }) + // .try_join() + // .await? + // .into_iter() + // .flatten() + // .collect(); + + // let app_node_entries: Vec<_> = + // app_ssr_entries.iter().copied().chain([rsc_entry]).collect(); + + // let _dynamic_entries = NextDynamicEntries::from_entries(Vc::cell( + // app_node_entries.iter().copied().map(Vc::upcast).collect(), + // )) + // .await?; let app_entry_client_references = client_reference_graph .entry(Vc::upcast(app_entry.rsc_entry)) From 1f6defd4b097fb24d1fcf75a12cb77f082ed9706 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 6 Dec 2023 16:37:29 +0000 Subject: [PATCH 136/189] v14.0.4-canary.46 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 18 +++++++++--------- 18 files changed, 34 insertions(+), 34 deletions(-) diff --git a/lerna.json b/lerna.json index 755cac8639689..ba2666e19d14d 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.45" + "version": "14.0.4-canary.46" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 571ee41689535..e384c0242931c 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 2c18fb540d554..21110002b3edb 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.45", + "@next/eslint-plugin-next": "14.0.4-canary.46", "@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 613222dc0100d..ac6600bbc3345 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index ee7d68ba10e71..73dbe283d253c 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "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 848610f7d3f92..03aa0956b44a4 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 0d1600b0e60b5..093e26f0cc5d7 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 6d37cc7afd926..ac5d40d86655c 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index cb154dd084af2..ffb1175430b2e 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 1ac5536401946..47430fba9aa68 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "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 0d7a8496c2481..e68210c6214f3 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "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 975a05a6249ce..cbc0a0bae9cbe 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 048dd671f77b4..abdbb77de5a33 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index cdfad7f848dbb..0d45846a239e0 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.45", + "@next/env": "14.0.4-canary.46", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.45", - "@next/polyfill-nomodule": "14.0.4-canary.45", - "@next/react-dev-overlay": "14.0.4-canary.45", - "@next/react-refresh-utils": "14.0.4-canary.45", - "@next/swc": "14.0.4-canary.45", + "@next/polyfill-module": "14.0.4-canary.46", + "@next/polyfill-nomodule": "14.0.4-canary.46", + "@next/react-dev-overlay": "14.0.4-canary.46", + "@next/react-refresh-utils": "14.0.4-canary.46", + "@next/swc": "14.0.4-canary.46", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 3d569e5abb7d5..3c77e469d6a67 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": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 71284d41a73a3..d4efe7f8f84aa 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "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 a3aa45b2ddc97..497b226d4ff36 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.45", + "version": "14.0.4-canary.46", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.45", + "next": "14.0.4-canary.46", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6af67e9323cb7..51dbbb3340018 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.45 + specifier: 14.0.4-canary.46 version: link:../next outdent: specifier: 0.8.0 @@ -24648,7 +24648,7 @@ packages: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4(react-refresh@0.12.0)(webpack@5.86.0)': - resolution: {tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4} + resolution: {registry: https://registry.npmjs.org/, tarball: https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4} id: '@gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-231206.4' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 From 61b825be3937dc1f095cde942d623c79559b2c53 Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 6 Dec 2023 12:15:42 -0800 Subject: [PATCH 137/189] fix hmr in multi-zone handling (#59307) ### What? When running a [multi-zone](https://github.com/vercel/next.js/tree/canary/examples/with-zones) app in dev, app pages would infinitely reload ### Why? The HMR upgrade request would fail and get caught into a retry loop. In the multi-zone case, they fail because the upgrade request would be sent again for a request that had already been upgraded. This resulted in a "server.handleUpgrade() was called more than once with the same socket" error, causing the upgrade request to fail. Every time a retry occurred, the page would trigger a full refresh since certain HMR errors cause the browser to reload. ### How? This ensures the upgrade handler only responds to requests that match the configured basePath. Closes NEXT-1797 Fixes #59161 Fixes #56615 Fixes #54454 --- packages/next/src/server/lib/router-server.ts | 10 ++++- .../multi-zone/app/apps/first/pages/index.tsx | 10 ++++- .../app/apps/second/pages/index.tsx | 10 ++++- test/e2e/multi-zone/multi-zone.test.ts | 43 ++++++++++++++++++- 4 files changed, 68 insertions(+), 5 deletions(-) diff --git a/packages/next/src/server/lib/router-server.ts b/packages/next/src/server/lib/router-server.ts index 2163dbdf7d268..70fdcfdb38778 100644 --- a/packages/next/src/server/lib/router-server.ts +++ b/packages/next/src/server/lib/router-server.ts @@ -582,8 +582,14 @@ export async function initialize(opts: { // console.error(_err); }) - if (opts.dev && developmentBundler) { - if (req.url?.includes(`/_next/webpack-hmr`)) { + if (opts.dev && developmentBundler && req.url) { + const isHMRRequest = req.url.includes('/_next/webpack-hmr') + // only handle HMR requests if the basePath in the request + // matches the basePath for the handler responding to the request + const isRequestForCurrentBasepath = + !config.basePath || pathHasPrefix(req.url, config.basePath) + + if (isHMRRequest && isRequestForCurrentBasepath) { return developmentBundler.hotReloader.onHMR(req, socket, head) } } diff --git a/test/e2e/multi-zone/app/apps/first/pages/index.tsx b/test/e2e/multi-zone/app/apps/first/pages/index.tsx index f705a52cfdb5c..12430c178e674 100644 --- a/test/e2e/multi-zone/app/apps/first/pages/index.tsx +++ b/test/e2e/multi-zone/app/apps/first/pages/index.tsx @@ -1,3 +1,11 @@ export default function Page() { - return

hello from first app

+ // this variable is edited by the test to verify HMR + const editedContent = '' + return ( + <> +

hello from first app

+
{editedContent}
+
{Date.now()}
+ + ) } diff --git a/test/e2e/multi-zone/app/apps/second/pages/index.tsx b/test/e2e/multi-zone/app/apps/second/pages/index.tsx index bba3728179bd4..873638c0898b3 100644 --- a/test/e2e/multi-zone/app/apps/second/pages/index.tsx +++ b/test/e2e/multi-zone/app/apps/second/pages/index.tsx @@ -1,3 +1,11 @@ export default function Page() { - return

hello from second app

+ // this variable is edited by the test to verify HMR + const editedContent = '' + return ( + <> +

hello from second app

+
{editedContent}
+
{Date.now()}
+ + ) } diff --git a/test/e2e/multi-zone/multi-zone.test.ts b/test/e2e/multi-zone/multi-zone.test.ts index 50a992399ca39..79b1e6561a812 100644 --- a/test/e2e/multi-zone/multi-zone.test.ts +++ b/test/e2e/multi-zone/multi-zone.test.ts @@ -1,4 +1,5 @@ import { createNextDescribe } from 'e2e-utils' +import { check, waitFor } from 'next-test-utils' import path from 'path' createNextDescribe( @@ -14,7 +15,7 @@ createNextDescribe( }, }, }, - ({ next }) => { + ({ next, isNextDev }) => { it.each([ { pathname: '/first', content: ['hello from first app'] }, { pathname: '/second', content: ['hello from second app'] }, @@ -45,5 +46,45 @@ createNextDescribe( } } ) + + if (isNextDev) { + async function runHMRTest(app: string) { + const browser = await next.browser(`/${app}`) + expect(await browser.elementByCss('body').text()).toContain( + `hello from ${app} app` + ) + const initialTimestamp = await browser.elementById('now').text() + + expect(await browser.elementByCss('body').text()).not.toContain( + 'hmr content' + ) + + await waitFor(1000) + + // verify that the page isn't unexpectedly reloading in the background + const newTimestamp = await browser.elementById('now').text() + expect(newTimestamp).toBe(initialTimestamp) + + // trigger HMR + const filePath = `apps/${app}/pages/index.tsx` + const content = await next.readFile(filePath) + + const patchedContent = content.replace( + `const editedContent = ''`, + `const editedContent = 'hmr content'` + ) + await next.patchFile(filePath, patchedContent) + + await check(() => browser.elementByCss('body').text(), /hmr content/) + + // restore original content + await next.patchFile(filePath, content) + } + + it('should support HMR in both apps', async () => { + await runHMRTest('first') + await runHMRTest('second') + }) + } } ) From 7a733dfd3440ac121ea3c5ff277ee732539e39ed Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Wed, 6 Dec 2023 12:21:28 -0800 Subject: [PATCH 138/189] fix edge route catch-all param parsing (#59343) ### What? Visiting an edge catch-all route incorrectly truncates multiple parameters ### Why? The params are currently coerced into a `ParsedURLQuery`-like format by calling `Object.fromEntries` on `searchParams`, but this doesn't consider multiple param values assigned to the same key ### How? Rather than use `fromEntries`, this uses an existing util to get the path into `ParsedURLQuery` format. Closes NEXT-1814 Fixes #59333 --- .../server/web/edge-route-module-wrapper.ts | 3 ++- .../app/edge/[[...slug]]/route.ts | 13 +++++++++++ .../edge-route-catchall/app/layout.tsx | 16 +++++++++++++ .../edge-route-catchall.test.ts | 23 +++++++++++++++++++ .../edge-route-catchall/next.config.js | 6 +++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 test/e2e/app-dir/edge-route-catchall/app/edge/[[...slug]]/route.ts create mode 100644 test/e2e/app-dir/edge-route-catchall/app/layout.tsx create mode 100644 test/e2e/app-dir/edge-route-catchall/edge-route-catchall.test.ts create mode 100644 test/e2e/app-dir/edge-route-catchall/next.config.js diff --git a/packages/next/src/server/web/edge-route-module-wrapper.ts b/packages/next/src/server/web/edge-route-module-wrapper.ts index 7877c234cf974..68a14fc80d0e2 100644 --- a/packages/next/src/server/web/edge-route-module-wrapper.ts +++ b/packages/next/src/server/web/edge-route-module-wrapper.ts @@ -13,6 +13,7 @@ import { RouteMatcher } from '../future/route-matchers/route-matcher' import type { NextFetchEvent } from './spec-extension/fetch-event' import { internal_getCurrentFunctionWaitUntil } from './internal-edge-wait-until' import { getUtils } from '../server-utils' +import { searchParamsToUrlQuery } from '../../shared/lib/router/utils/querystring' type WrapOptions = Partial> @@ -78,7 +79,7 @@ export class EdgeRouteModuleWrapper { }) const { params } = utils.normalizeDynamicRouteParams( - Object.fromEntries(request.nextUrl.searchParams) + searchParamsToUrlQuery(request.nextUrl.searchParams) ) const prerenderManifest: PrerenderManifest | undefined = diff --git a/test/e2e/app-dir/edge-route-catchall/app/edge/[[...slug]]/route.ts b/test/e2e/app-dir/edge-route-catchall/app/edge/[[...slug]]/route.ts new file mode 100644 index 0000000000000..74f20092b782b --- /dev/null +++ b/test/e2e/app-dir/edge-route-catchall/app/edge/[[...slug]]/route.ts @@ -0,0 +1,13 @@ +import { NextRequest, NextResponse } from 'next/server' + +export const runtime = 'edge' + +type Context = { + params: { + slug: string[] + } +} + +export const GET = async (req: NextRequest, { params }: Context) => { + return NextResponse.json(params) +} diff --git a/test/e2e/app-dir/edge-route-catchall/app/layout.tsx b/test/e2e/app-dir/edge-route-catchall/app/layout.tsx new file mode 100644 index 0000000000000..a14e64fcd5e33 --- /dev/null +++ b/test/e2e/app-dir/edge-route-catchall/app/layout.tsx @@ -0,0 +1,16 @@ +export const metadata = { + title: 'Next.js', + description: 'Generated by Next.js', +} + +export default function RootLayout({ + children, +}: { + children: React.ReactNode +}) { + return ( + + {children} + + ) +} diff --git a/test/e2e/app-dir/edge-route-catchall/edge-route-catchall.test.ts b/test/e2e/app-dir/edge-route-catchall/edge-route-catchall.test.ts new file mode 100644 index 0000000000000..857b18fe9fb39 --- /dev/null +++ b/test/e2e/app-dir/edge-route-catchall/edge-route-catchall.test.ts @@ -0,0 +1,23 @@ +import { createNextDescribe } from 'e2e-utils' + +createNextDescribe( + 'edge-route-catchall', + { + files: __dirname, + }, + ({ next }) => { + it('should correctly normalize edge route catch-all with a single param', async () => { + const result = await next.fetch('/edge/one') + + expect(await result.text()).toBe(JSON.stringify({ slug: ['one'] })) + }) + + it('should correctly normalize edge route catch-all with multiple params', async () => { + const result = await next.fetch('/edge/one/two/three') + + expect(await result.text()).toBe( + JSON.stringify({ slug: ['one', 'two', 'three'] }) + ) + }) + } +) diff --git a/test/e2e/app-dir/edge-route-catchall/next.config.js b/test/e2e/app-dir/edge-route-catchall/next.config.js new file mode 100644 index 0000000000000..807126e4cf0bf --- /dev/null +++ b/test/e2e/app-dir/edge-route-catchall/next.config.js @@ -0,0 +1,6 @@ +/** + * @type {import('next').NextConfig} + */ +const nextConfig = {} + +module.exports = nextConfig From 19fa1fa579fa3fd8e799af954b91bf3610503b02 Mon Sep 17 00:00:00 2001 From: "quisi.do" Date: Wed, 6 Dec 2023 14:21:23 -0800 Subject: [PATCH 139/189] add `logLevel` support to `@next/bundle-analyzer` (#59228) Co-authored-by: Jiachi Liu --- packages/next-bundle-analyzer/index.d.ts | 6 ++++++ packages/next-bundle-analyzer/index.js | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/next-bundle-analyzer/index.d.ts b/packages/next-bundle-analyzer/index.d.ts index d76b617c1f4fe..f34cc32494f03 100644 --- a/packages/next-bundle-analyzer/index.d.ts +++ b/packages/next-bundle-analyzer/index.d.ts @@ -4,6 +4,12 @@ declare function NextBundleAnalyzer(options?: { enabled?: boolean openAnalyzer?: boolean analyzerMode?: 'json' | 'static' + + /** + * Log level. Can be 'info', 'warn', 'error' or 'silent'. + * @default 'info' + */ + logLevel?: 'info' | 'warn' | 'error' | 'silent' | undefined }): (config?: NextConfig) => NextConfig export = NextBundleAnalyzer diff --git a/packages/next-bundle-analyzer/index.js b/packages/next-bundle-analyzer/index.js index e44e2ccf5c82a..855843aec69ac 100644 --- a/packages/next-bundle-analyzer/index.js +++ b/packages/next-bundle-analyzer/index.js @@ -1,5 +1,5 @@ module.exports = - ({ enabled = true, openAnalyzer, analyzerMode } = {}) => + ({ enabled = true, logLevel, openAnalyzer, analyzerMode } = {}) => (nextConfig = {}) => { return Object.assign({}, nextConfig, { webpack(config, options) { @@ -8,6 +8,7 @@ module.exports = config.plugins.push( new BundleAnalyzerPlugin({ analyzerMode: analyzerMode || 'static', + logLevel, openAnalyzer, reportFilename: !options.nextRuntime ? `./analyze/client.html` From d4d9dc40facff846582de9192f89b5b59c682edf Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Wed, 6 Dec 2023 23:22:10 +0000 Subject: [PATCH 140/189] v14.0.4-canary.47 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index ba2666e19d14d..04712bf98e4b3 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.46" + "version": "14.0.4-canary.47" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index e384c0242931c..57d95edd97fa2 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index 21110002b3edb..b90277ff5b670 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.46", + "@next/eslint-plugin-next": "14.0.4-canary.47", "@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 ac6600bbc3345..3de9b1693de6a 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 73dbe283d253c..bef4c19bfa7a4 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "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 03aa0956b44a4..7335c1d9d665b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 093e26f0cc5d7..45f369091eaab 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index ac5d40d86655c..0ee1119ad209f 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index ffb1175430b2e..184d70453b097 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 47430fba9aa68..80f95a60164a3 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "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 e68210c6214f3..6f53706a44450 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "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 cbc0a0bae9cbe..28daf434c3553 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index abdbb77de5a33..147ed79dacda2 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 0d45846a239e0..8d1a5597d86db 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.46", + "@next/env": "14.0.4-canary.47", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.46", - "@next/polyfill-nomodule": "14.0.4-canary.46", - "@next/react-dev-overlay": "14.0.4-canary.46", - "@next/react-refresh-utils": "14.0.4-canary.46", - "@next/swc": "14.0.4-canary.46", + "@next/polyfill-module": "14.0.4-canary.47", + "@next/polyfill-nomodule": "14.0.4-canary.47", + "@next/react-dev-overlay": "14.0.4-canary.47", + "@next/react-refresh-utils": "14.0.4-canary.47", + "@next/swc": "14.0.4-canary.47", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 3c77e469d6a67..954768e6dc427 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": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index d4efe7f8f84aa..7319b304816be 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "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 497b226d4ff36..5c0e890d5a9d3 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.46", + "version": "14.0.4-canary.47", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.46", + "next": "14.0.4-canary.47", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51dbbb3340018..bccb753d7e5f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.46 + specifier: 14.0.4-canary.47 version: link:../next outdent: specifier: 0.8.0 From 0925de117ea84e477789b93395212ae902015ad2 Mon Sep 17 00:00:00 2001 From: Tim Neutkens Date: Thu, 7 Dec 2023 15:03:44 +0100 Subject: [PATCH 141/189] Update tests for Turbopack (#59354) ## What? - Add support for `experimental.externalDir` -- Was already supported, just makes Turbopack not fail on that config option - Skipped `with-babel` test because it tests Babel - Skipped `swc-warnings` test because it tests Babel - Skipped `config-resolve-alias` as it tests webpack config - Skipped `undefined-webpack-config` as it tests webpack config Closes NEXT-1817 --- packages/next/src/lib/turbopack-warning.ts | 2 +- .../e2e/app-dir/with-babel/with-babel.test.ts | 41 +++++++------- test/e2e/swc-warnings/index.test.ts | 40 +++++++------- .../config-resolve-alias/test/index.test.js | 27 ++++++---- .../test/index.test.js | 53 +++++++++++-------- 5 files changed, 92 insertions(+), 71 deletions(-) diff --git a/packages/next/src/lib/turbopack-warning.ts b/packages/next/src/lib/turbopack-warning.ts index ff163f194bf8e..b83cc3a114dff 100644 --- a/packages/next/src/lib/turbopack-warning.ts +++ b/packages/next/src/lib/turbopack-warning.ts @@ -69,6 +69,7 @@ const supportedTurbopackNextConfigOptions = [ 'experimental.useLightningcss', 'experimental.windowHistorySupport', 'experimental.instrumentationHook', + 'experimental.externalDir', // Experimental options that don't affect compilation 'experimental.ppr', @@ -131,7 +132,6 @@ const supportedTurbopackNextConfigOptions = [ // 'experimental.craCompat', // 'experimental.disablePostcssPresetEnv', // 'experimental.esmExternals', - // 'experimental.externalDir', // This is used to force swc-loader to run regardless of finding Babel. // 'experimental.forceSwcTransforms', // 'experimental.fullySpecified', diff --git a/test/e2e/app-dir/with-babel/with-babel.test.ts b/test/e2e/app-dir/with-babel/with-babel.test.ts index 6b1a8c1c2feff..9ec962d5aca51 100644 --- a/test/e2e/app-dir/with-babel/with-babel.test.ts +++ b/test/e2e/app-dir/with-babel/with-babel.test.ts @@ -1,23 +1,26 @@ import { createNextDescribe } from 'e2e-utils' -createNextDescribe( - 'with babel', - { - files: __dirname, - skipDeployment: true, - }, - ({ next, isNextStart }) => { - it('should support babel in app dir', async () => { - const $ = await next.render$('/') - expect($('h1').text()).toBe('hello') - }) - - if (isNextStart) { - it('should contain og package files in middleware', async () => { - const middleware = await next.readFile('.next/server/middleware.js') - // @vercel/og default font should be bundled - expect(middleware).not.toContain('noto-sans-v27-latin-regular.ttf') +// Tests Babel, not needed for Turbopack +;(process.env.TURBOPACK ? describe.skip : describe)('with babel', () => { + createNextDescribe( + 'with babel', + { + files: __dirname, + skipDeployment: true, + }, + ({ next, isNextStart }) => { + it('should support babel in app dir', async () => { + const $ = await next.render$('/') + expect($('h1').text()).toBe('hello') }) + + if (isNextStart) { + it('should contain og package files in middleware', async () => { + const middleware = await next.readFile('.next/server/middleware.js') + // @vercel/og default font should be bundled + expect(middleware).not.toContain('noto-sans-v27-latin-regular.ttf') + }) + } } - } -) + ) +}) diff --git a/test/e2e/swc-warnings/index.test.ts b/test/e2e/swc-warnings/index.test.ts index 018e7b81137e9..4e82fa9f31516 100644 --- a/test/e2e/swc-warnings/index.test.ts +++ b/test/e2e/swc-warnings/index.test.ts @@ -2,35 +2,39 @@ import { createNext } from 'e2e-utils' import { NextInstance } from 'test/lib/next-modes/base' import { renderViaHTTP } from 'next-test-utils' -describe('swc warnings by default', () => { - let next: NextInstance +// Tests Babel, not needed for Turbopack +;(process.env.TURBOPACK ? describe.skip : describe)( + 'swc warnings by default', + () => { + let next: NextInstance - beforeAll(async () => { - next = await createNext({ - files: { - 'pages/index.js': ` + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/index.js': ` export default function Page() { return

hello world

} `, - '.babelrc': ` + '.babelrc': ` { "presets": ["next/babel"] } `, - }, - dependencies: {}, + }, + dependencies: {}, + }) }) - }) - afterAll(() => next.destroy()) + afterAll(() => next.destroy()) - it('should have warning', async () => { - await renderViaHTTP(next.url, '/') - expect(next.cliOutput).toContain( - 'Disabled SWC as replacement for Babel because of custom Babel configuration' - ) - }) -}) + it('should have warning', async () => { + await renderViaHTTP(next.url, '/') + expect(next.cliOutput).toContain( + 'Disabled SWC as replacement for Babel because of custom Babel configuration' + ) + }) + } +) describe('can force swc', () => { let next: NextInstance diff --git a/test/integration/config-resolve-alias/test/index.test.js b/test/integration/config-resolve-alias/test/index.test.js index f67e5000a9854..4694debddc061 100644 --- a/test/integration/config-resolve-alias/test/index.test.js +++ b/test/integration/config-resolve-alias/test/index.test.js @@ -3,14 +3,21 @@ import { join } from 'path' import { runNextCommand } from 'next-test-utils' -describe('Invalid resolve alias', () => { - it('should show relevant error when webpack resolve alias is wrong', async () => { - const { stderr } = await runNextCommand(['build', join(__dirname, '..')], { - stderr: true, - }) +// Skip in Turbopack as it does not support `config.resolve.alias` from webpack. +;(process.env.TURBOPACK ? describe.skip : describe)( + 'Invalid resolve alias', + () => { + it('should show relevant error when webpack resolve alias is wrong', async () => { + const { stderr } = await runNextCommand( + ['build', join(__dirname, '..')], + { + stderr: true, + } + ) - expect(stderr).toMatch( - 'webpack config.resolve.alias was incorrectly overridden. https://' - ) - }) -}) + expect(stderr).toMatch( + 'webpack config.resolve.alias was incorrectly overridden. https://' + ) + }) + } +) diff --git a/test/integration/undefined-webpack-config/test/index.test.js b/test/integration/undefined-webpack-config/test/index.test.js index 5556ad5ae469e..9e1abf0f11df7 100644 --- a/test/integration/undefined-webpack-config/test/index.test.js +++ b/test/integration/undefined-webpack-config/test/index.test.js @@ -7,29 +7,36 @@ const appDir = join(__dirname, '../') const expectedErr = /Webpack config is undefined. You may have forgot to return properly from within the "webpack" method of your next.config.js/ -describe('undefined webpack config error', () => { - ;(process.env.TURBOPACK ? describe.skip : describe)('production mode', () => { - it.skip('should show in production mode', async () => { - const result = await nextBuild(appDir, [], { - stdout: true, - stderr: true, - }) - expect(result.stderr || '' + result.stdout || '').toMatch(expectedErr) - }) - }) +// Tests webpack, not needed for Turbopack +;(process.env.TURBOPACK ? describe.skip : describe)( + 'undefined webpack config error', + () => { + ;(process.env.TURBOPACK ? describe.skip : describe)( + 'production mode', + () => { + it.skip('should show in production mode', async () => { + const result = await nextBuild(appDir, [], { + stdout: true, + stderr: true, + }) + expect(result.stderr || '' + result.stdout || '').toMatch(expectedErr) + }) + } + ) - it('should show in dev mode', async () => { - let output = '' + it('should show in dev mode', async () => { + let output = '' - await launchApp(appDir, await findPort(), { - onStderr(msg) { - output += msg || '' - }, - ontStdout(msg) { - output += msg || '' - }, - }) + await launchApp(appDir, await findPort(), { + onStderr(msg) { + output += msg || '' + }, + ontStdout(msg) { + output += msg || '' + }, + }) - expect(output).toMatch(expectedErr) - }) -}) + expect(output).toMatch(expectedErr) + }) + } +) From 42ec6c89bb21cd33d891e3351fe4aa61562f39d0 Mon Sep 17 00:00:00 2001 From: Vercel Release Bot <88769842+vercel-release-bot@users.noreply.github.com> Date: Thu, 7 Dec 2023 09:51:45 -0500 Subject: [PATCH 142/189] Update Turbopack test manifest (#59356) This auto-generated PR updates the integration test manifest used when testing Turbopack. --- test/turbopack-tests-manifest.json | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/test/turbopack-tests-manifest.json b/test/turbopack-tests-manifest.json index 6a152e9827840..dca09102fcfbe 100644 --- a/test/turbopack-tests-manifest.json +++ b/test/turbopack-tests-manifest.json @@ -3133,6 +3133,16 @@ "flakey": [], "runtimeError": false }, + "test/e2e/app-dir/edge-route-catchall/edge-route-catchall.test.ts": { + "passed": [ + "edge-route-catchall should correctly normalize edge route catch-all with a single param", + "edge-route-catchall should correctly normalize edge route catch-all with multiple params" + ], + "failed": [], + "pending": [], + "flakey": [], + "runtimeError": false + }, "test/e2e/app-dir/edge-route-rewrite/edge-route-rewrite.test.ts": { "passed": [ "edge-route-rewrite it should support a rewrite to a dynamic edge route", @@ -5335,7 +5345,8 @@ "multi-zone should correctly respond for /first/blog/post-1", "multi-zone should correctly respond for /second", "multi-zone should correctly respond for /second/another/post-1", - "multi-zone should correctly respond for /second/blog/post-1" + "multi-zone should correctly respond for /second/blog/post-1", + "multi-zone should support HMR in both apps" ], "failed": [], "pending": [], From 2874bc0656df9031d10eea7beee36ce70e53acef Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 7 Dec 2023 18:11:11 +0100 Subject: [PATCH 143/189] Fix server output bundling packages module resolving (#59369) --- packages/next/src/build/handle-externals.ts | 16 +++++++++++++-- packages/next/src/build/webpack-config.ts | 4 ++++ .../plugins/next-trace-entrypoints-plugin.ts | 5 +++++ .../app-dir/app-external/app-external.test.ts | 19 +++++++++++++++++- .../app-external/app/optout/action/actions.js | 7 +++++++ .../app-external/app/optout/action/page.js | 20 +++++++++++++++++++ test/e2e/app-dir/app-external/next.config.js | 5 ++++- .../dual-pkg-optout/index.cjs | 1 + .../dual-pkg-optout/index.mjs | 1 + .../dual-pkg-optout/package.json | 6 ++++++ 10 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 test/e2e/app-dir/app-external/app/optout/action/actions.js create mode 100644 test/e2e/app-dir/app-external/app/optout/action/page.js create mode 100644 test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.cjs create mode 100644 test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.mjs create mode 100644 test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/package.json diff --git a/packages/next/src/build/handle-externals.ts b/packages/next/src/build/handle-externals.ts index 8c7f4ccc55ce7..8a26dd4042ba4 100644 --- a/packages/next/src/build/handle-externals.ts +++ b/packages/next/src/build/handle-externals.ts @@ -47,6 +47,7 @@ export async function resolveExternal( context: string, request: string, isEsmRequested: boolean, + optOutBundlingPackages: string[], getResolve: ( options: any ) => ( @@ -66,8 +67,15 @@ export async function resolveExternal( let res: string | null = null let isEsm: boolean = false - let preferEsmOptions = - esmExternals && isEsmRequested ? [true, false] : [false] + const preferEsmOptions = + esmExternals && + isEsmRequested && + // For package that marked as externals that should be not bundled, + // we don't resolve them as ESM since it could be resolved as async module, + // such as `import(external package)` in the bundle, valued as a `Promise`. + !optOutBundlingPackages.some((optOut) => request.startsWith(optOut)) + ? [true, false] + : [false] for (const preferEsm of preferEsmOptions) { const resolve = getResolve( @@ -131,10 +139,12 @@ export async function resolveExternal( export function makeExternalHandler({ config, + optOutBundlingPackages, optOutBundlingPackageRegex, dir, }: { config: NextConfigComplete + optOutBundlingPackages: string[] optOutBundlingPackageRegex: RegExp dir: string }) { @@ -289,6 +299,7 @@ export function makeExternalHandler({ context, request, isEsmRequested, + optOutBundlingPackages, getResolve, isLocal ? resolveNextExternal : undefined ) @@ -349,6 +360,7 @@ export function makeExternalHandler({ context, pkg + '/package.json', isEsmRequested, + optOutBundlingPackages, getResolve, isLocal ? resolveNextExternal : undefined ) diff --git a/packages/next/src/build/webpack-config.ts b/packages/next/src/build/webpack-config.ts index 60dde7bbc8ab5..75b0ebdd46141 100644 --- a/packages/next/src/build/webpack-config.ts +++ b/packages/next/src/build/webpack-config.ts @@ -727,9 +727,11 @@ export default async function getBaseWebpackConfig( const crossOrigin = config.crossOrigin + // For original request, such as `package name` const optOutBundlingPackages = EXTERNAL_PACKAGES.concat( ...(config.experimental.serverComponentsExternalPackages || []) ) + // For resolved request, such as `absolute path/package name/foo/bar.js` const optOutBundlingPackageRegex = new RegExp( `[/\\\\]node_modules[/\\\\](${optOutBundlingPackages .map((p) => p.replace(/\//g, '[/\\\\]')) @@ -738,6 +740,7 @@ export default async function getBaseWebpackConfig( const handleExternals = makeExternalHandler({ config, + optOutBundlingPackages, optOutBundlingPackageRegex, dir, }) @@ -1662,6 +1665,7 @@ export default async function getBaseWebpackConfig( outputFileTracingRoot: config.experimental.outputFileTracingRoot, appDirEnabled: hasAppDir, turbotrace: config.experimental.turbotrace, + optOutBundlingPackages, traceIgnores: config.experimental.outputFileTracingIgnores || [], } ), diff --git a/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts b/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts index 5ea193152a283..669d3c6f6afef 100644 --- a/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts +++ b/packages/next/src/build/webpack/plugins/next-trace-entrypoints-plugin.ts @@ -133,6 +133,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { private rootDir: string private appDir: string | undefined private pagesDir: string | undefined + private optOutBundlingPackages: string[] private appDirEnabled?: boolean private tracingRoot: string private entryTraces: Map> @@ -144,6 +145,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { rootDir, appDir, pagesDir, + optOutBundlingPackages, appDirEnabled, traceIgnores, esmExternals, @@ -153,6 +155,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { rootDir: string appDir: string | undefined pagesDir: string | undefined + optOutBundlingPackages: string[] appDirEnabled?: boolean traceIgnores?: string[] outputFileTracingRoot?: string @@ -168,6 +171,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { this.traceIgnores = traceIgnores || [] this.tracingRoot = outputFileTracingRoot || rootDir this.turbotrace = turbotrace + this.optOutBundlingPackages = optOutBundlingPackages } // Here we output all traced assets and webpack chunks to a @@ -743,6 +747,7 @@ export class TraceEntryPointsPlugin implements webpack.WebpackPluginInstance { context, request, isEsmRequested, + this.optOutBundlingPackages, (options) => (_: string, resRequest: string) => { return getResolve(options)(parent, resRequest, job) }, diff --git a/test/e2e/app-dir/app-external/app-external.test.ts b/test/e2e/app-dir/app-external/app-external.test.ts index c458ab3397da9..b734f53bcc358 100644 --- a/test/e2e/app-dir/app-external/app-external.test.ts +++ b/test/e2e/app-dir/app-external/app-external.test.ts @@ -1,5 +1,5 @@ import { createNextDescribe } from 'e2e-utils' -import { shouldRunTurboDevTest } from '../../../lib/next-test-utils' +import { check, shouldRunTurboDevTest } from 'next-test-utils' async function resolveStreamResponse(response: any, onData?: any) { let result = '' @@ -250,5 +250,22 @@ createNextDescribe( const html = await next.render('/async-storage') expect(html).toContain('success') }) + + it('should not prefer to resolve esm over cjs for bundling optout packages', async () => { + const browser = await next.browser('/optout/action') + expect(await browser.elementByCss('#dual-pkg-outout p').text()).toBe('') + + browser.elementByCss('#dual-pkg-outout button').click() + await check(async () => { + const text = await browser.elementByCss('#dual-pkg-outout p').text() + if (process.env.TURBOPACK) { + // The prefer esm won't effect turbopack resolving + expect(text).toBe('dual-pkg-optout:mjs') + } else { + expect(text).toBe('dual-pkg-optout:cjs') + } + return 'success' + }, /success/) + }) } ) diff --git a/test/e2e/app-dir/app-external/app/optout/action/actions.js b/test/e2e/app-dir/app-external/app/optout/action/actions.js new file mode 100644 index 0000000000000..b6c9a47131f15 --- /dev/null +++ b/test/e2e/app-dir/app-external/app/optout/action/actions.js @@ -0,0 +1,7 @@ +'use server' + +import { value as dualPkgOptoutValue } from 'dual-pkg-optout' + +export async function getDualOptoutValue() { + return dualPkgOptoutValue +} diff --git a/test/e2e/app-dir/app-external/app/optout/action/page.js b/test/e2e/app-dir/app-external/app/optout/action/page.js new file mode 100644 index 0000000000000..0d339c7c39262 --- /dev/null +++ b/test/e2e/app-dir/app-external/app/optout/action/page.js @@ -0,0 +1,20 @@ +'use client' + +import { useState } from 'react' +import { getDualOptoutValue } from './actions' + +export default function Page() { + const [optoutDisplayValue, setOptoutDisplayValue] = useState('') + return ( +
+

{optoutDisplayValue}

+ +
+ ) +} diff --git a/test/e2e/app-dir/app-external/next.config.js b/test/e2e/app-dir/app-external/next.config.js index 82662490484e9..4b1cb6524d198 100644 --- a/test/e2e/app-dir/app-external/next.config.js +++ b/test/e2e/app-dir/app-external/next.config.js @@ -2,6 +2,9 @@ module.exports = { reactStrictMode: true, transpilePackages: ['untranspiled-module', 'css', 'font'], experimental: { - serverComponentsExternalPackages: ['conditional-exports-optout'], + serverComponentsExternalPackages: [ + 'conditional-exports-optout', + 'dual-pkg-optout', + ], }, } diff --git a/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.cjs b/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.cjs new file mode 100644 index 0000000000000..a6764e05e13dd --- /dev/null +++ b/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.cjs @@ -0,0 +1 @@ +exports.value = 'dual-pkg-optout:cjs' diff --git a/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.mjs b/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.mjs new file mode 100644 index 0000000000000..1f257f74e95bd --- /dev/null +++ b/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/index.mjs @@ -0,0 +1 @@ +export const value = 'dual-pkg-optout:mjs' diff --git a/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/package.json b/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/package.json new file mode 100644 index 0000000000000..3646ad4bdb5f5 --- /dev/null +++ b/test/e2e/app-dir/app-external/node_modules_bak/dual-pkg-optout/package.json @@ -0,0 +1,6 @@ +{ + "exports": { + "import": "./index.mjs", + "require": "./index.cjs" + } +} From a578cc8192fa3f9182d4fa70f18760f7ae1490bb Mon Sep 17 00:00:00 2001 From: Zack Tanner Date: Thu, 7 Dec 2023 11:17:15 -0800 Subject: [PATCH 144/189] fix inconsistent scroll restoration behavior (#59366) ### What? While scrolled on a page, and when following a link to a new page and clicking the browser back button or using `router.back()`, the scroll position would sometimes restore scroll to the incorrect spot (in the case of the test added in this PR, it'd scroll you back to the top of the list) ### Why? The refactor in #56497 changed the way router actions are processed: specifically, all actions were assumed to be async, even if they could be handled synchronously. For most actions this is fine, as most are currently async. However, `ACTION_RESTORE` (triggered when the `popstate` event occurs) isn't async, and introducing a small amount of delay in the handling of this action can cause the browser to not properly restore the scroll position ### How? This special-cases `ACTION_RESTORE` to synchronously process the action and call `setState` when it's received, rather than creating a promise. To consistently reproduce this behavior, I added an option to our browser interface that'll allow us to programmatically trigger a CPU slowdown. h/t to @alvarlagerlof for isolating the offending commit and sharing a minimal reproduction. Closes NEXT-1819 Likely addresses #58899 but the reproduction was too complex to verify. --- .../src/shared/lib/router/action-queue.ts | 33 +++++++++++-------- .../app/scroll-restoration/context.ts | 10 ++++++ .../app/scroll-restoration/layout.tsx | 27 +++++++++++++++ .../app/scroll-restoration/other/page.tsx | 13 ++++++++ .../app/scroll-restoration/page.tsx | 23 +++++++++++++ .../e2e/app-dir/navigation/navigation.test.ts | 29 ++++++++++++++++ test/lib/browsers/base.ts | 10 +++++- test/lib/browsers/playwright.ts | 14 +++++++- test/lib/next-webdriver.ts | 8 ++++- 9 files changed, 151 insertions(+), 16 deletions(-) create mode 100644 test/e2e/app-dir/navigation/app/scroll-restoration/context.ts create mode 100644 test/e2e/app-dir/navigation/app/scroll-restoration/layout.tsx create mode 100644 test/e2e/app-dir/navigation/app/scroll-restoration/other/page.tsx create mode 100644 test/e2e/app-dir/navigation/app/scroll-restoration/page.tsx diff --git a/packages/next/src/shared/lib/router/action-queue.ts b/packages/next/src/shared/lib/router/action-queue.ts index 54e57c76e6248..03ce7accb2097 100644 --- a/packages/next/src/shared/lib/router/action-queue.ts +++ b/packages/next/src/shared/lib/router/action-queue.ts @@ -6,6 +6,7 @@ import { ACTION_REFRESH, ACTION_SERVER_ACTION, ACTION_NAVIGATE, + ACTION_RESTORE, } from '../../../client/components/router-reducer/router-reducer-types' import type { ReduxDevToolsInstance } from '../../../client/components/use-reducer-with-devtools' import { reducer } from '../../../client/components/router-reducer/router-reducer' @@ -26,7 +27,7 @@ export type AppRouterActionQueue = { export type ActionQueueNode = { payload: ReducerActions next: ActionQueueNode | null - resolve: (value: PromiseLike | AppRouterState) => void + resolve: (value: ReducerState) => void reject: (err: Error) => void discarded?: boolean } @@ -115,14 +116,26 @@ function dispatchAction( setState: DispatchStatePromise ) { let resolvers: { - resolve: (value: AppRouterState | PromiseLike) => void + resolve: (value: ReducerState) => void reject: (reason: any) => void - } + } = { resolve: setState, reject: () => {} } + + // most of the action types are async with the exception of restore + // it's important that restore is handled quickly since it's fired on the popstate event + // and we don't want to add any delay on a back/forward nav + // this only creates a promise for the async actions + if (payload.type !== ACTION_RESTORE) { + // Create the promise and assign the resolvers to the object. + const deferredPromise = new Promise((resolve, reject) => { + resolvers = { resolve, reject } + }) - // Create the promise and assign the resolvers to the object. - const deferredPromise = new Promise((resolve, reject) => { - resolvers = { resolve, reject } - }) + startTransition(() => { + // we immediately notify React of the pending promise -- the resolver is attached to the action node + // and will be called when the associated action promise resolves + setState(deferredPromise) + }) + } const newAction: ActionQueueNode = { payload, @@ -131,12 +144,6 @@ function dispatchAction( reject: resolvers!.reject, } - startTransition(() => { - // we immediately notify React of the pending promise -- the resolver is attached to the action node - // and will be called when the associated action promise resolves - setState(deferredPromise) - }) - // Check if the queue is empty if (actionQueue.pending === null) { // The queue is empty, so add the action and start it immediately diff --git a/test/e2e/app-dir/navigation/app/scroll-restoration/context.ts b/test/e2e/app-dir/navigation/app/scroll-restoration/context.ts new file mode 100644 index 0000000000000..ee51ff9835aae --- /dev/null +++ b/test/e2e/app-dir/navigation/app/scroll-restoration/context.ts @@ -0,0 +1,10 @@ +import { createContext } from 'react' + +export interface Item { + id: number +} + +export const ItemsContext = createContext<{ + items: Item[] + loadMoreItems: () => void +}>({ items: [], loadMoreItems: () => {} }) diff --git a/test/e2e/app-dir/navigation/app/scroll-restoration/layout.tsx b/test/e2e/app-dir/navigation/app/scroll-restoration/layout.tsx new file mode 100644 index 0000000000000..eef2c2f88c4b5 --- /dev/null +++ b/test/e2e/app-dir/navigation/app/scroll-restoration/layout.tsx @@ -0,0 +1,27 @@ +'use client' +import { useState } from 'react' +import { ItemsContext, type Item } from './context' + +const createItems = (start: number, end: number): Item[] => { + const items: Item[] = [] + for (let i = start; i <= end; i++) { + items.push({ id: i }) + } + return items +} + +export default function Layout({ children }: { children: React.ReactNode }) { + const [items, setItems] = useState(createItems(1, 50)) + + const loadMoreItems = () => { + const start = items.length + 1 + const end = start + 50 - 1 + setItems((prevItems) => [...prevItems, ...createItems(start, end)]) + } + + return ( + + {children} + + ) +} diff --git a/test/e2e/app-dir/navigation/app/scroll-restoration/other/page.tsx b/test/e2e/app-dir/navigation/app/scroll-restoration/other/page.tsx new file mode 100644 index 0000000000000..dcc5babec8616 --- /dev/null +++ b/test/e2e/app-dir/navigation/app/scroll-restoration/other/page.tsx @@ -0,0 +1,13 @@ +'use client' +import { useRouter } from 'next/navigation' + +export default function Page() { + const router = useRouter() + return ( +
+ +
+ ) +} diff --git a/test/e2e/app-dir/navigation/app/scroll-restoration/page.tsx b/test/e2e/app-dir/navigation/app/scroll-restoration/page.tsx new file mode 100644 index 0000000000000..34a0ffa0bc861 --- /dev/null +++ b/test/e2e/app-dir/navigation/app/scroll-restoration/page.tsx @@ -0,0 +1,23 @@ +'use client' +import Link from 'next/link' +import React, { useContext } from 'react' +import { ItemsContext } from './context' + +export default function Page() { + const { items, loadMoreItems } = useContext(ItemsContext) + + return ( +
+

Page

+
    + {items.map((item) => ( +
  • Item {item.id}
  • + ))} +
+ + Go to Other +
+ ) +} diff --git a/test/e2e/app-dir/navigation/navigation.test.ts b/test/e2e/app-dir/navigation/navigation.test.ts index 4a568331ca0f6..73986d6f1d6d9 100644 --- a/test/e2e/app-dir/navigation/navigation.test.ts +++ b/test/e2e/app-dir/navigation/navigation.test.ts @@ -732,5 +732,34 @@ createNextDescribe( } }) }) + + describe('scroll restoration', () => { + it('should restore original scroll position when navigating back', async () => { + const browser = await next.browser('/scroll-restoration', { + // throttling the CPU to rule out flakiness based on how quickly the page loads + cpuThrottleRate: 6, + }) + const body = await browser.elementByCss('body') + expect(await body.text()).toContain('Item 50') + await browser.elementById('load-more').click() + await browser.elementById('load-more').click() + await browser.elementById('load-more').click() + expect(await body.text()).toContain('Item 200') + + // scroll to the bottom of the page + await browser.eval('window.scrollTo(0, document.body.scrollHeight)') + + // grab the current position + const scrollPosition = await browser.eval('window.pageYOffset') + + await browser.elementByCss("[href='/scroll-restoration/other']").click() + await browser.elementById('back-button').click() + + const newScrollPosition = await browser.eval('window.pageYOffset') + + // confirm that the scroll position was restored + await check(() => scrollPosition === newScrollPosition, true) + }) + }) } ) diff --git a/test/lib/browsers/base.ts b/test/lib/browsers/base.ts index 3b7b2c6def90a..5788010a4f087 100644 --- a/test/lib/browsers/base.ts +++ b/test/lib/browsers/base.ts @@ -125,7 +125,15 @@ export abstract class BrowserInterface implements PromiseLike { off(event: Event, cb: (...args: any[]) => void) {} async loadPage( url: string, - { disableCache: boolean, beforePageLoad: Function } + { + disableCache, + cpuThrottleRate, + beforePageLoad, + }: { + disableCache?: boolean + cpuThrottleRate?: number + beforePageLoad?: Function + } ): Promise {} async get(url: string): Promise {} diff --git a/test/lib/browsers/playwright.ts b/test/lib/browsers/playwright.ts index 7f3106df6169b..f742a95cc6d58 100644 --- a/test/lib/browsers/playwright.ts +++ b/test/lib/browsers/playwright.ts @@ -128,7 +128,11 @@ export class Playwright extends BrowserInterface { async loadPage( url: string, - opts?: { disableCache: boolean; beforePageLoad?: (...args: any[]) => void } + opts?: { + disableCache: boolean + cpuThrottleRate: number + beforePageLoad?: (...args: any[]) => void + } ) { if (this.activeTrace) { const traceDir = path.join(__dirname, '../../traces') @@ -182,6 +186,14 @@ export class Playwright extends BrowserInterface { session.send('Network.setCacheDisabled', { cacheDisabled: true }) } + if (opts?.cpuThrottleRate) { + const session = await context.newCDPSession(page) + // https://chromedevtools.github.io/devtools-protocol/tot/Emulation/#method-setCPUThrottlingRate + session.send('Emulation.setCPUThrottlingRate', { + rate: opts.cpuThrottleRate, + }) + } + page.on('websocket', (ws) => { if (tracePlaywright) { page diff --git a/test/lib/next-webdriver.ts b/test/lib/next-webdriver.ts index d9f9e9cfd27ca..cd0b7bc9e1d66 100644 --- a/test/lib/next-webdriver.ts +++ b/test/lib/next-webdriver.ts @@ -68,6 +68,7 @@ export default async function webdriver( disableJavaScript?: boolean headless?: boolean ignoreHTTPSErrors?: boolean + cpuThrottleRate?: number } ): Promise { let CurrentInterface: new () => BrowserInterface @@ -87,6 +88,7 @@ export default async function webdriver( disableJavaScript, ignoreHTTPSErrors, headless, + cpuThrottleRate, } = options // we import only the needed interface @@ -124,7 +126,11 @@ export default async function webdriver( console.log(`\n> Loading browser with ${fullUrl}\n`) - await browser.loadPage(fullUrl, { disableCache, beforePageLoad }) + await browser.loadPage(fullUrl, { + disableCache, + cpuThrottleRate, + beforePageLoad, + }) console.log(`\n> Loaded browser with ${fullUrl}\n`) // Wait for application to hydrate From e1fe0c9a14266b1c216306b7392c0006166b113e Mon Sep 17 00:00:00 2001 From: Tomas Fagerbekk Date: Thu, 7 Dec 2023 20:20:07 +0100 Subject: [PATCH 145/189] test: ability to use node debugger (#56277) Fixes ability to run `NODE_OPTIONS='--inspect' next dev` as described in [docs](https://nextjs.org/docs/pages/building-your-application/configuring/debugging), by removing inspect option from NODE_OPTIONS arg passed to worker process. This bug seem to have been introduced in 7d93808c435d6d74f93e045711b1639dc1fc05b3 as a part of a some refactoring. See how `getNodeOptionsWithoutInspect` is no longer used. Fixes #55862 --------- Co-authored-by: Jiachi Liu --- test/integration/cli/test/index.test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/integration/cli/test/index.test.js b/test/integration/cli/test/index.test.js index e316bde63eaa6..34c89f7b7fd68 100644 --- a/test/integration/cli/test/index.test.js +++ b/test/integration/cli/test/index.test.js @@ -530,6 +530,7 @@ describe('CLI Usage', () => { test("NODE_OPTIONS='--inspect'", async () => { const port = await findPort() let output = '' + let errOutput = '' const app = await runNextCommandDev( [dirBasic, '--port', port], undefined, @@ -537,11 +538,16 @@ describe('CLI Usage', () => { onStdout(msg) { output += stripAnsi(msg) }, + onStderr(msg) { + errOutput += stripAnsi(msg) + }, env: { NODE_OPTIONS: '--inspect' }, } ) try { await check(() => output, new RegExp(`http://localhost:${port}`)) + await check(() => errOutput, /Debugger listening on/) + expect(errOutput).not.toContain('address already in use') } finally { await killApp(app) } From d07a370dfa26e5c16ba8af0583b7a2f2f82475cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Badia?= <1901628+raphaelbadia@users.noreply.github.com> Date: Thu, 7 Dec 2023 20:54:34 +0100 Subject: [PATCH 146/189] fixes the logging by showing full URLs only on demand (#58088) fixes #58087 Currently in Next 14, everyone has fullURL flag turned to true, this PR reverts the condition. --------- Co-authored-by: Jiachi Liu --- packages/next/src/build/output/index.ts | 11 ----- packages/next/src/build/output/store.ts | 16 ++++++- packages/next/src/server/next-server.ts | 2 +- .../e2e/app-dir/logging/fetch-logging.test.ts | 46 +++++++++++++++++-- 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/packages/next/src/build/output/index.ts b/packages/next/src/build/output/index.ts index a304daa454b46..10745f2e1ae28 100644 --- a/packages/next/src/build/output/index.ts +++ b/packages/next/src/build/output/index.ts @@ -322,18 +322,7 @@ export function watchCompilers( }) } -const internalSegments = ['[[...__metadata_id__]]', '[__metadata_id__]'] export function reportTrigger(trigger: string, url?: string) { - for (const segment of internalSegments) { - if (trigger.includes(segment)) { - trigger = trigger.replace(segment, '') - } - } - - if (trigger.length > 1 && trigger.endsWith('/')) { - trigger = trigger.slice(0, -1) - } - buildStore.setState({ trigger, url, diff --git a/packages/next/src/build/output/store.ts b/packages/next/src/build/output/store.ts index e15d566c5e8de..3b25d0557f463 100644 --- a/packages/next/src/build/output/store.ts +++ b/packages/next/src/build/output/store.ts @@ -28,6 +28,19 @@ export type OutputState = } )) +const internalSegments = ['[[...__metadata_id__]]', '[__metadata_id__]'] +export function formatTrigger(trigger: string) { + for (const segment of internalSegments) { + if (trigger.includes(segment)) { + trigger = trigger.replace(segment, '') + } + } + if (trigger.length > 1 && trigger.endsWith('/')) { + trigger = trigger.slice(0, -1) + } + return trigger +} + export const store = createStore({ appUrl: null, bindAddr: null, @@ -67,7 +80,8 @@ store.subscribe((state) => { if (state.loading) { if (state.trigger) { - trigger = state.trigger + trigger = formatTrigger(state.trigger) + console.log('trigger', trigger) triggerUrl = state.url if (trigger !== 'initial') { traceSpan = trace('compile-path', undefined, { diff --git a/packages/next/src/server/next-server.ts b/packages/next/src/server/next-server.ts index acb6abf0c95c7..c02af8fd254eb 100644 --- a/packages/next/src/server/next-server.ts +++ b/packages/next/src/server/next-server.ts @@ -1061,7 +1061,7 @@ export default class NextNodeServer extends BaseServer { const loggingFetchesConfig = this.nextConfig.logging?.fetches const enabledVerboseLogging = !!loggingFetchesConfig - const shouldTruncateUrl = loggingFetchesConfig?.fullUrl + const shouldTruncateUrl = !loggingFetchesConfig?.fullUrl if (this.renderOpts.dev) { const { bold, green, yellow, red, gray, white } = diff --git a/test/e2e/app-dir/logging/fetch-logging.test.ts b/test/e2e/app-dir/logging/fetch-logging.test.ts index 885fd61241ab3..8402bc50868d8 100644 --- a/test/e2e/app-dir/logging/fetch-logging.test.ts +++ b/test/e2e/app-dir/logging/fetch-logging.test.ts @@ -1,3 +1,5 @@ +import path from 'path' +import fs from 'fs' import stripAnsi from 'strip-ansi' import { check } from 'next-test-utils' import { createNextDescribe } from 'e2e-utils' @@ -42,7 +44,13 @@ createNextDescribe( files: __dirname, }, ({ next, isNextDev }) => { - function runTests({ withFetchesLogging }: { withFetchesLogging: boolean }) { + function runTests({ + withFetchesLogging, + withFullUrlFetches = false, + }: { + withFetchesLogging: boolean + withFullUrlFetches?: boolean + }) { if (withFetchesLogging) { it('should only log requests in dev mode', async () => { const outputIndex = next.cliOutput.length @@ -74,8 +82,9 @@ createNextDescribe( log.url.includes('api/random?no-cache') ) - // expend full url - expect(logs.every((log) => log.url.includes('..'))).toBe(false) + expect(logs.some((log) => log.url.includes('..'))).toBe( + !withFullUrlFetches + ) if (logEntry?.cache === 'cache: no-cache') { return 'success' @@ -184,8 +193,28 @@ createNextDescribe( } } - describe('with verbose logging', () => { - runTests({ withFetchesLogging: true }) + describe('with fetches verbose logging', () => { + runTests({ withFetchesLogging: true, withFullUrlFetches: true }) + }) + + describe('with fetches default logging', () => { + const curNextConfig = fs.readFileSync( + path.join(__dirname, 'next.config.js'), + { encoding: 'utf-8' } + ) + beforeAll(async () => { + await next.stop() + await next.patchFile( + 'next.config.js', + curNextConfig.replace('fullUrl: true', 'fullUrl: false') + ) + await next.start() + }) + afterAll(async () => { + await next.patchFile('next.config.js', curNextConfig) + }) + + runTests({ withFetchesLogging: true, withFullUrlFetches: false }) }) describe('with verbose logging for edge runtime', () => { @@ -203,11 +232,18 @@ createNextDescribe( }) describe('with default logging', () => { + const curNextConfig = fs.readFileSync( + path.join(__dirname, 'next.config.js'), + { encoding: 'utf-8' } + ) beforeAll(async () => { await next.stop() await next.deleteFile('next.config.js') await next.start() }) + afterAll(async () => { + await next.patchFile('next.config.js', curNextConfig) + }) runTests({ withFetchesLogging: false }) }) From 37c6a10a8917d3bc1389ff6c2a6b3b06fe58e8b5 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 7 Dec 2023 19:57:49 +0000 Subject: [PATCH 147/189] v14.0.4-canary.48 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 04712bf98e4b3..d0e046e2789e8 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.47" + "version": "14.0.4-canary.48" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 57d95edd97fa2..5a46ca9dcd767 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index b90277ff5b670..de6bd4305a3cc 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.47", + "@next/eslint-plugin-next": "14.0.4-canary.48", "@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 3de9b1693de6a..ec4f430985b29 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index bef4c19bfa7a4..4fc61eed715a4 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "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 7335c1d9d665b..fd6d34b8a5f5d 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 45f369091eaab..f30a2f9539b14 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 0ee1119ad209f..0b4921c0593a3 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 184d70453b097..05856f3a96110 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 80f95a60164a3..9592a88613a53 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "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 6f53706a44450..841eb8194241b 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "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 28daf434c3553..e406b5bd50df1 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 147ed79dacda2..bd4e5c6a77be4 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 8d1a5597d86db..d7d155c14938b 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.47", + "@next/env": "14.0.4-canary.48", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.47", - "@next/polyfill-nomodule": "14.0.4-canary.47", - "@next/react-dev-overlay": "14.0.4-canary.47", - "@next/react-refresh-utils": "14.0.4-canary.47", - "@next/swc": "14.0.4-canary.47", + "@next/polyfill-module": "14.0.4-canary.48", + "@next/polyfill-nomodule": "14.0.4-canary.48", + "@next/react-dev-overlay": "14.0.4-canary.48", + "@next/react-refresh-utils": "14.0.4-canary.48", + "@next/swc": "14.0.4-canary.48", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 954768e6dc427..9a11469464673 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": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 7319b304816be..5ce9dcc126954 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "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 5c0e890d5a9d3..a0e3f00d4998f 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.47", + "version": "14.0.4-canary.48", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.47", + "next": "14.0.4-canary.48", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bccb753d7e5f5..688392c9b3b61 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.47 + specifier: 14.0.4-canary.48 version: link:../next outdent: specifier: 0.8.0 From aa08c49d7269d3f7c3ed96b77068d1690eea3587 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 7 Dec 2023 21:02:52 +0100 Subject: [PATCH 148/189] rm console.log (#59381) --- packages/next/src/build/output/store.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/next/src/build/output/store.ts b/packages/next/src/build/output/store.ts index 3b25d0557f463..5ad6197f82244 100644 --- a/packages/next/src/build/output/store.ts +++ b/packages/next/src/build/output/store.ts @@ -81,7 +81,6 @@ store.subscribe((state) => { if (state.loading) { if (state.trigger) { trigger = formatTrigger(state.trigger) - console.log('trigger', trigger) triggerUrl = state.url if (trigger !== 'initial') { traceSpan = trace('compile-path', undefined, { From 77dc763807c31a52278db95a8b71e989d467d95f Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 7 Dec 2023 20:06:40 +0000 Subject: [PATCH 149/189] v14.0.4-canary.49 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index d0e046e2789e8..05e774c5e2575 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.48" + "version": "14.0.4-canary.49" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index 5a46ca9dcd767..ef49283b512d3 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index de6bd4305a3cc..e5f722fc939b2 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.48", + "@next/eslint-plugin-next": "14.0.4-canary.49", "@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 ec4f430985b29..af7079e91ad89 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 4fc61eed715a4..4d9c18db28ba4 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "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 fd6d34b8a5f5d..c3a20553d9f2b 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index f30a2f9539b14..2bb172894b0d1 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index 0b4921c0593a3..d6f21c9518db9 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 05856f3a96110..69dd792eb7930 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 9592a88613a53..0c9af6950b4ad 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "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 841eb8194241b..32f28d21f2f9b 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "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 e406b5bd50df1..fbf696b7596bc 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index bd4e5c6a77be4..44c5eb2c19339 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index d7d155c14938b..92f0f315ff7be 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.48", + "@next/env": "14.0.4-canary.49", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.48", - "@next/polyfill-nomodule": "14.0.4-canary.48", - "@next/react-dev-overlay": "14.0.4-canary.48", - "@next/react-refresh-utils": "14.0.4-canary.48", - "@next/swc": "14.0.4-canary.48", + "@next/polyfill-module": "14.0.4-canary.49", + "@next/polyfill-nomodule": "14.0.4-canary.49", + "@next/react-dev-overlay": "14.0.4-canary.49", + "@next/react-refresh-utils": "14.0.4-canary.49", + "@next/swc": "14.0.4-canary.49", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index 9a11469464673..b300d98b6c85b 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": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 5ce9dcc126954..888afb2301038 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "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 a0e3f00d4998f..94878f173605c 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.48", + "version": "14.0.4-canary.49", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.48", + "next": "14.0.4-canary.49", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 688392c9b3b61..219b8eefaa9ce 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.48 + specifier: 14.0.4-canary.49 version: link:../next outdent: specifier: 0.8.0 From eaa0e7c1ba28c516aa1397f69187f719db763bb0 Mon Sep 17 00:00:00 2001 From: Jiachi Liu Date: Thu, 7 Dec 2023 22:08:02 +0100 Subject: [PATCH 150/189] Skip latest commit check for stable release (#59383) --- .github/workflows/trigger_release.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index 286b896da6ff6..6b7acd05f8c3f 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -54,15 +54,15 @@ jobs: - name: Get commit of the latest tag run: echo "LATEST_TAG_COMMIT=$(git rev-list -n 1 $(git describe --tags --abbrev=0))" >> $GITHUB_ENV - - name: Get latest commit - run: echo "LATEST_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV - - - name: Check if new commits since last tag - run: | - if [ "$LATEST_TAG_COMMIT" = "$LATEST_COMMIT" ]; then - echo "No new commits. Exiting..." - exit 1 - fi + # - name: Get latest commit + # run: echo "LATEST_COMMIT=$(git rev-parse HEAD)" >> $GITHUB_ENV + + # - name: Check if new commits since last tag + # run: | + # if [ "$LATEST_TAG_COMMIT" = "$LATEST_COMMIT" ]; then + # echo "No new commits. Exiting..." + # exit 1 + # fi # https://github.com/actions/virtual-environments/issues/1187 - name: tune linux network From c9f859e6bea4a547d3946e99c5242bb419155598 Mon Sep 17 00:00:00 2001 From: vercel-release-bot Date: Thu, 7 Dec 2023 21:11:20 +0000 Subject: [PATCH 151/189] v14.0.4 --- lerna.json | 2 +- packages/create-next-app/package.json | 2 +- packages/eslint-config-next/package.json | 4 ++-- packages/eslint-plugin-next/package.json | 2 +- packages/font/package.json | 2 +- packages/next-bundle-analyzer/package.json | 2 +- packages/next-codemod/package.json | 2 +- packages/next-env/package.json | 2 +- packages/next-mdx/package.json | 2 +- packages/next-plugin-storybook/package.json | 2 +- packages/next-polyfill-module/package.json | 2 +- packages/next-polyfill-nomodule/package.json | 2 +- packages/next-swc/package.json | 2 +- packages/next/package.json | 14 +++++++------- packages/react-dev-overlay/package.json | 2 +- packages/react-refresh-utils/package.json | 2 +- packages/third-parties/package.json | 4 ++-- pnpm-lock.yaml | 16 ++++++++-------- 18 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lerna.json b/lerna.json index 05e774c5e2575..bcfd879b680d6 100644 --- a/lerna.json +++ b/lerna.json @@ -16,5 +16,5 @@ "registry": "https://registry.npmjs.org/" } }, - "version": "14.0.4-canary.49" + "version": "14.0.4" } diff --git a/packages/create-next-app/package.json b/packages/create-next-app/package.json index ef49283b512d3..1be5d6cc21dae 100644 --- a/packages/create-next-app/package.json +++ b/packages/create-next-app/package.json @@ -1,6 +1,6 @@ { "name": "create-next-app", - "version": "14.0.4-canary.49", + "version": "14.0.4", "keywords": [ "react", "next", diff --git a/packages/eslint-config-next/package.json b/packages/eslint-config-next/package.json index e5f722fc939b2..d45d18c998afa 100644 --- a/packages/eslint-config-next/package.json +++ b/packages/eslint-config-next/package.json @@ -1,6 +1,6 @@ { "name": "eslint-config-next", - "version": "14.0.4-canary.49", + "version": "14.0.4", "description": "ESLint configuration used by Next.js.", "main": "index.js", "license": "MIT", @@ -10,7 +10,7 @@ }, "homepage": "https://nextjs.org/docs/app/building-your-application/configuring/eslint#eslint-config", "dependencies": { - "@next/eslint-plugin-next": "14.0.4-canary.49", + "@next/eslint-plugin-next": "14.0.4", "@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 af7079e91ad89..d14085eb250c2 100644 --- a/packages/eslint-plugin-next/package.json +++ b/packages/eslint-plugin-next/package.json @@ -1,6 +1,6 @@ { "name": "@next/eslint-plugin-next", - "version": "14.0.4-canary.49", + "version": "14.0.4", "description": "ESLint plugin for Next.js.", "main": "dist/index.js", "license": "MIT", diff --git a/packages/font/package.json b/packages/font/package.json index 4d9c18db28ba4..c5b24cca4d985 100644 --- a/packages/font/package.json +++ b/packages/font/package.json @@ -1,6 +1,6 @@ { "name": "@next/font", - "version": "14.0.4-canary.49", + "version": "14.0.4", "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 c3a20553d9f2b..2790b971a7480 100644 --- a/packages/next-bundle-analyzer/package.json +++ b/packages/next-bundle-analyzer/package.json @@ -1,6 +1,6 @@ { "name": "@next/bundle-analyzer", - "version": "14.0.4-canary.49", + "version": "14.0.4", "main": "index.js", "types": "index.d.ts", "license": "MIT", diff --git a/packages/next-codemod/package.json b/packages/next-codemod/package.json index 2bb172894b0d1..0f1d6e94ff7e0 100644 --- a/packages/next-codemod/package.json +++ b/packages/next-codemod/package.json @@ -1,6 +1,6 @@ { "name": "@next/codemod", - "version": "14.0.4-canary.49", + "version": "14.0.4", "license": "MIT", "repository": { "type": "git", diff --git a/packages/next-env/package.json b/packages/next-env/package.json index d6f21c9518db9..910a8841f6afc 100644 --- a/packages/next-env/package.json +++ b/packages/next-env/package.json @@ -1,6 +1,6 @@ { "name": "@next/env", - "version": "14.0.4-canary.49", + "version": "14.0.4", "keywords": [ "react", "next", diff --git a/packages/next-mdx/package.json b/packages/next-mdx/package.json index 69dd792eb7930..f64e4917cd127 100644 --- a/packages/next-mdx/package.json +++ b/packages/next-mdx/package.json @@ -1,6 +1,6 @@ { "name": "@next/mdx", - "version": "14.0.4-canary.49", + "version": "14.0.4", "main": "index.js", "license": "MIT", "repository": { diff --git a/packages/next-plugin-storybook/package.json b/packages/next-plugin-storybook/package.json index 0c9af6950b4ad..f175347080ced 100644 --- a/packages/next-plugin-storybook/package.json +++ b/packages/next-plugin-storybook/package.json @@ -1,6 +1,6 @@ { "name": "@next/plugin-storybook", - "version": "14.0.4-canary.49", + "version": "14.0.4", "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 32f28d21f2f9b..637795a23ead6 100644 --- a/packages/next-polyfill-module/package.json +++ b/packages/next-polyfill-module/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-module", - "version": "14.0.4-canary.49", + "version": "14.0.4", "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 fbf696b7596bc..146e9a0396fd3 100644 --- a/packages/next-polyfill-nomodule/package.json +++ b/packages/next-polyfill-nomodule/package.json @@ -1,6 +1,6 @@ { "name": "@next/polyfill-nomodule", - "version": "14.0.4-canary.49", + "version": "14.0.4", "description": "A polyfill for non-dead, nomodule browsers.", "main": "dist/polyfill-nomodule.js", "license": "MIT", diff --git a/packages/next-swc/package.json b/packages/next-swc/package.json index 44c5eb2c19339..300f2528fb909 100644 --- a/packages/next-swc/package.json +++ b/packages/next-swc/package.json @@ -1,6 +1,6 @@ { "name": "@next/swc", - "version": "14.0.4-canary.49", + "version": "14.0.4", "private": true, "scripts": { "clean": "node ../../scripts/rm.mjs native", diff --git a/packages/next/package.json b/packages/next/package.json index 92f0f315ff7be..f2f69d0a5c38a 100644 --- a/packages/next/package.json +++ b/packages/next/package.json @@ -1,6 +1,6 @@ { "name": "next", - "version": "14.0.4-canary.49", + "version": "14.0.4", "description": "The React Framework", "main": "./dist/server/next.js", "license": "MIT", @@ -92,7 +92,7 @@ ] }, "dependencies": { - "@next/env": "14.0.4-canary.49", + "@next/env": "14.0.4", "@swc/helpers": "0.5.2", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -147,11 +147,11 @@ "@mswjs/interceptors": "0.23.0", "@napi-rs/cli": "2.16.2", "@napi-rs/triples": "1.1.0", - "@next/polyfill-module": "14.0.4-canary.49", - "@next/polyfill-nomodule": "14.0.4-canary.49", - "@next/react-dev-overlay": "14.0.4-canary.49", - "@next/react-refresh-utils": "14.0.4-canary.49", - "@next/swc": "14.0.4-canary.49", + "@next/polyfill-module": "14.0.4", + "@next/polyfill-nomodule": "14.0.4", + "@next/react-dev-overlay": "14.0.4", + "@next/react-refresh-utils": "14.0.4", + "@next/swc": "14.0.4", "@opentelemetry/api": "1.6.0", "@playwright/test": "^1.35.1", "@taskr/clear": "1.1.0", diff --git a/packages/react-dev-overlay/package.json b/packages/react-dev-overlay/package.json index b300d98b6c85b..f4acdb2db16f1 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": "14.0.4-canary.49", + "version": "14.0.4", "description": "A development-only overlay for developing React applications.", "repository": { "url": "vercel/next.js", diff --git a/packages/react-refresh-utils/package.json b/packages/react-refresh-utils/package.json index 888afb2301038..2bce118fb87a5 100644 --- a/packages/react-refresh-utils/package.json +++ b/packages/react-refresh-utils/package.json @@ -1,6 +1,6 @@ { "name": "@next/react-refresh-utils", - "version": "14.0.4-canary.49", + "version": "14.0.4", "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 94878f173605c..e30fb7d7ce72d 100644 --- a/packages/third-parties/package.json +++ b/packages/third-parties/package.json @@ -1,6 +1,6 @@ { "name": "@next/third-parties", - "version": "14.0.4-canary.49", + "version": "14.0.4", "repository": { "url": "vercel/next.js", "directory": "packages/third-parties" @@ -25,7 +25,7 @@ "third-party-capital": "1.0.20" }, "devDependencies": { - "next": "14.0.4-canary.49", + "next": "14.0.4", "outdent": "0.8.0", "prettier": "2.5.1" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 219b8eefaa9ce..e0a2b9ee25deb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -741,7 +741,7 @@ importers: packages/eslint-config-next: dependencies: '@next/eslint-plugin-next': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../eslint-plugin-next '@rushstack/eslint-patch': specifier: ^1.3.3 @@ -806,7 +806,7 @@ importers: packages/next: dependencies: '@next/env': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../next-env '@swc/helpers': specifier: 0.5.2 @@ -933,19 +933,19 @@ importers: specifier: 1.1.0 version: 1.1.0 '@next/polyfill-module': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../next-polyfill-module '@next/polyfill-nomodule': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../next-polyfill-nomodule '@next/react-dev-overlay': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../react-dev-overlay '@next/react-refresh-utils': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../react-refresh-utils '@next/swc': - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../next-swc '@opentelemetry/api': specifier: 1.6.0 @@ -1599,7 +1599,7 @@ importers: version: 1.0.20 devDependencies: next: - specifier: 14.0.4-canary.49 + specifier: 14.0.4 version: link:../next outdent: specifier: 0.8.0 From d5836a30384695e46437a455aaab8e45d1f60765 Mon Sep 17 00:00:00 2001 From: Delba de Oliveira <32464864+delbaoliveira@users.noreply.github.com> Date: Thu, 7 Dec 2023 21:12:25 +0000 Subject: [PATCH 152/189] Docs: Update Server Actions Docs (#59080) - [x] Rename page from `forms-and-mutations` to `server-actions-and-mutations` to account for examples that don't use forms. - [x] Split `/pages` and `/app` content to make easier to edit - [x] Add Security Section - [x] Recommend tainting - [x] Closures and encryption - [x] Overwriting encryption keys - [x] CSRF protection | Allowed Origins - [x] Add examples for Server Actions being called outside forms - [x] `useEffect` - [x] Event handlers - [ ] ~3rd party libraries~ - [x] More form examples - [x] Add note on calling actions in ` + + ) +} +``` + +`updateUser` Server Action will always receive the `userId` argument, in addition to the form data: + +```js filename="app/actions.js" +'use server' + +export async function updateUser(userId, formData) { + // ... +} +``` + +> **Good to know**: +> +> - An alternative is to pass arguments as hidden input fields in the form (e.g. ``). However, the value will be part of the rendered HTML and will not be encoded. +> - `.bind` of a Server Action works in both Server and Client Components. It also supports progressive enhancement. + +#### Pending states + +You can use the React [`useFormStatus`](https://react.dev/reference/react-dom/hooks/useFormStatus) hook to show a pending state while the form is being submitted. + +- `useFormStatus` returns the status for a specific `
`, so it **must be defined as a child of the `` element**. +- `useFormStatus` is a React hook and therefore must be used in a Client Component. + +```tsx filename="app/submit-button.tsx" switcher +'use client' + +import { useFormStatus } from 'react-dom' + +export function SubmitButton() { + const { pending } = useFormStatus() + + return ( + + ) +} +``` + +```jsx filename="app/submit-button.jsx" switcher +'use client' + +import { useFormStatus } from 'react-dom' + +export function SubmitButton() { + const { pending } = useFormStatus() + + return ( + + ) +} +``` + +`` can then be nested in any form: + +```tsx filename="app/page.tsx" switcher +import { SubmitButton } from '@/app/submit-button' +import { createItem } from '@/app/actions' + +export default async function Home() { + return ( + + + + + ) +} +``` + +```jsx filename="app/page.jsx" switcher +import { SubmitButton } from '@/app/submit-button' +import { createItem } from '@/app/actions' + +export default async function Home() { + return ( +
+ + + + ) +} +``` + +#### Server-side validation and error handling + +We recommend using HTML validation like `required` and `type="email"` for basic client-side validation. + +For more advanced server-side validation, you can use a library like [zod](https://zod.dev/) to validate the form fields before mutating the data: + +```tsx filename="app/actions.ts" switcher +'use server' + +import { z } from 'zod' + +const schema = z.object({ + email: z.string({ + invalid_type_error: 'Invalid Email', + }), +}) + +export default async function createUser(formData: FormData) { + const validatedFields = schema.safeParse({ + email: formData.get('email'), + }) + + // Return early if the form data is invalid + if (!validatedFields.success) { + return { + errors: validatedFields.error.flatten().fieldErrors, + } + } + + // Mutate data +} +``` + +```jsx filename="app/actions.js" switcher +'use server' + +import { z } from 'zod' + +const schema = z.object({ + email: z.string({ + invalid_type_error: 'Invalid Email', + }), +}) + +export default async function createsUser(formData) { + const validatedFields = schema.safeParse({ + email: formData.get('email'), + }) + + // Return early if the form data is invalid + if (!validatedFields.success) { + return { + errors: validatedFields.error.flatten().fieldErrors, + } + } + + // Mutate data +} +``` + +> **Good to know:** +> +> - Before mutating data, you should always ensure a user is also authorized to perform the action. See [Authentication and Authorization](#authentication-and-authorization). +> - Refer to the [Zod documentation](https://zod.dev/) for more information. + +Once the fields have been validated on the server, you can return a serializable object in your action and use the React [`useFormState`](https://react.dev/reference/react-dom/hooks/useFormState) hook to show a message to the user. + +- By passing the action to `useFormState`, the action's function signature changes to receive a new `prevState` or `initialState` parameter as its first argument. +- `useFormState` is a React hook and therefore must be used in a Client Component. + +```tsx filename="app/actions.ts" switcher +'use server' + +export async function createUser(prevState: any, formData: FormData) { + // ... + return { + message: 'Please enter a valid email', + } +} +``` + +```jsx filename="app/actions.js" switcher +'use server' + +export async function createUser(prevState, formData) { + // ... + return { + message: 'Please enter a valid email', + } +} +``` + +Then, you can pass your action to the `useFormState` hook and use the returned `state` to display an error message. + +```tsx filename="app/ui/signup.tsx" switcher +'use client' + +import { useFormState } from 'react-dom' +import { createUser } from '@/app/actions' + +const initialState = { + message: null, +} + +export function Signup() { + const [state, formAction] = useFormState(createUser, initialState) + + return ( +
+ + + {/* ... */} +

+ {state?.message} +

+ +
+ ) +} +``` + +```jsx filename="app/ui/signup.js" switcher +'use client' + +import { useFormState } from 'react-dom' +import { createUser } from '@/app/actions' + +const initialState = { + message: null, +} + +export function Signup() { + const [state, formAction] = useFormState(createUser, initialState) + + return ( +
+ + + {/* ... */} +

+ {state?.message} +

+ +
+ ) +} +``` + +#### Optimistic updates + +You can use the React [`useOptimistic`](https://react.dev/reference/react/useOptimistic) hook to optimistically update the UI before the Server Action finishes, rather than waiting for the response: + +```tsx filename="app/page.tsx" switcher +'use client' + +import { useOptimistic } from 'react' +import { send } from './actions' + +type Message = { + message: string +} + +export function Thread({ messages }: { messages: Message[] }) { + const [optimisticMessages, addOptimisticMessage] = useOptimistic( + messages, + (state: Message[], newMessage: string) => [ + ...state, + { message: newMessage }, + ] + ) + + return ( +
+ {optimisticMessages.map((m, k) => ( +
{m.message}
+ ))} +
{ + const message = formData.get('message') + addOptimisticMessage(message) + await send(message) + }} + > + + +
+
+ ) +} +``` + +```jsx filename="app/page.jsx" switcher +'use client' + +import { useOptimistic } from 'react' +import { send } from './actions' + +export function Thread({ messages }) { + const [optimisticMessages, addOptimisticMessage] = useOptimistic( + messages, + (state, newMessage) => [...state, { message: newMessage }] + ) + + return ( +
+ {optimisticMessages.map((m) => ( +
{m.message}
+ ))} +
{ + const message = formData.get('message') + addOptimisticMessage(message) + await send(message) + }} + > + + +
+
+ ) +} +``` + +#### ` + + ) +} +``` + +To improve the user experience, we recommend using other React APIs like [`useOptimistic`](https://react.dev/reference/react/useOptimistic) and [`useTransition`](https://react.dev/reference/react/useTransition) to update the UI before the Server Action finishes executing on the server, or to show a pending state. + +You can also add event handlers to form elements, for example, to save a form field `onChange`: + +```tsx filename="app/ui/edit-post.tsx" +'use client' + +import { publishPost, saveDraft } from './actions' + +export default function EditPost() { + return ( + +