diff --git a/Cargo.lock b/Cargo.lock index a4d1c395c5..8e80fa0060 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -412,7 +412,7 @@ dependencies = [ [[package]] name = "auto-hash-map" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "serde", ] @@ -1393,16 +1393,6 @@ dependencies = [ "syn 2.0.18", ] -[[package]] -name = "ctrlc" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04d778600249295e82b6ab12e291ed9029407efee0cfb7baf67157edc65964df" -dependencies = [ - "nix", - "windows-sys 0.48.0", -] - [[package]] name = "curl" version = "0.4.44" @@ -3378,6 +3368,7 @@ dependencies = [ "anyhow", "async-recursion", "async-trait", + "const_format", "futures", "indexmap", "indoc", @@ -3559,7 +3550,7 @@ dependencies = [ [[package]] name = "node-file-trace" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "serde", @@ -7219,7 +7210,7 @@ dependencies = [ [[package]] name = "turbo-tasks" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "auto-hash-map", @@ -7250,7 +7241,7 @@ dependencies = [ [[package]] name = "turbo-tasks-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "cargo-lock", @@ -7262,7 +7253,7 @@ dependencies = [ [[package]] name = "turbo-tasks-bytes" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "bytes", @@ -7277,7 +7268,7 @@ dependencies = [ [[package]] name = "turbo-tasks-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "dotenvy", @@ -7291,7 +7282,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fetch" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "indexmap", @@ -7308,7 +7299,7 @@ dependencies = [ [[package]] name = "turbo-tasks-fs" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "auto-hash-map", @@ -7338,7 +7329,7 @@ dependencies = [ [[package]] name = "turbo-tasks-hash" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "base16", "hex", @@ -7350,7 +7341,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "convert_case 0.6.0", @@ -7364,7 +7355,7 @@ dependencies = [ [[package]] name = "turbo-tasks-macros-shared" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "proc-macro2", "quote", @@ -7374,7 +7365,7 @@ dependencies = [ [[package]] name = "turbo-tasks-malloc" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "mimalloc", ] @@ -7382,7 +7373,7 @@ dependencies = [ [[package]] name = "turbo-tasks-memory" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "auto-hash-map", @@ -7405,7 +7396,7 @@ dependencies = [ [[package]] name = "turbo-tasks-testing" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "auto-hash-map", @@ -7417,7 +7408,7 @@ dependencies = [ [[package]] name = "turbopack" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-recursion", @@ -7447,7 +7438,7 @@ dependencies = [ [[package]] name = "turbopack-bench" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "chromiumoxide", @@ -7477,7 +7468,7 @@ dependencies = [ [[package]] name = "turbopack-binding" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "auto-hash-map", "mdxjs", @@ -7519,7 +7510,7 @@ dependencies = [ [[package]] name = "turbopack-build" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "indexmap", @@ -7539,18 +7530,18 @@ dependencies = [ [[package]] name = "turbopack-cli-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "clap 4.1.11", "crossbeam-channel", "crossterm", - "ctrlc", "once_cell", "owo-colors", "postcard", "serde", "serde_json", + "tokio", "tracing", "tracing-subscriber", "turbo-tasks", @@ -7563,7 +7554,7 @@ dependencies = [ [[package]] name = "turbopack-core" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-trait", @@ -7591,7 +7582,7 @@ dependencies = [ [[package]] name = "turbopack-create-test-app" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "clap 4.1.11", @@ -7604,7 +7595,7 @@ dependencies = [ [[package]] name = "turbopack-css" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-trait", @@ -7626,7 +7617,7 @@ dependencies = [ [[package]] name = "turbopack-dev" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "indexmap", @@ -7650,10 +7641,11 @@ dependencies = [ [[package]] name = "turbopack-dev-server" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-compression", + "auto-hash-map", "futures", "hyper", "hyper-tungstenite", @@ -7685,7 +7677,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-trait", @@ -7718,7 +7710,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-plugins" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-trait", @@ -7741,7 +7733,7 @@ dependencies = [ [[package]] name = "turbopack-ecmascript-runtime" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "indoc", @@ -7758,7 +7750,7 @@ dependencies = [ [[package]] name = "turbopack-env" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "indexmap", @@ -7774,7 +7766,7 @@ dependencies = [ [[package]] name = "turbopack-image" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "base64 0.21.0", @@ -7794,7 +7786,7 @@ dependencies = [ [[package]] name = "turbopack-json" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "serde", @@ -7809,7 +7801,7 @@ dependencies = [ [[package]] name = "turbopack-mdx" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "mdxjs", @@ -7824,7 +7816,7 @@ dependencies = [ [[package]] name = "turbopack-node" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "async-stream", @@ -7859,7 +7851,7 @@ dependencies = [ [[package]] name = "turbopack-static" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "serde", @@ -7875,7 +7867,7 @@ dependencies = [ [[package]] name = "turbopack-swc-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "swc_core", "turbo-tasks", @@ -7886,7 +7878,7 @@ dependencies = [ [[package]] name = "turbopack-test-utils" version = "0.1.0" -source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230628.2#57669dea96ee99b7e68da01ec7b7d286bc81b083" +source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230630.2#b36c4140a11fb2530b5a70f5c44d8a95206f9ef1" dependencies = [ "anyhow", "once_cell", @@ -7905,7 +7897,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if 1.0.0", - "rand 0.4.6", + "rand 0.8.5", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index b8aa46d681..77922464d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,11 +42,11 @@ swc_core = { version = "0.78.24" } testing = { version = "0.33.19" } # Turbo crates -turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230628.2" } +turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230630.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-230628.2" } +turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230630.2" } # [TODO]: need to refactor embed_directory! macro usage in next-core -turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230628.2" } +turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230630.2" } # General Deps diff --git a/packages/next-swc/crates/next-build/src/next_pages/page_chunks.rs b/packages/next-swc/crates/next-build/src/next_pages/page_chunks.rs index 44ac379a8d..e5da8658e9 100644 --- a/packages/next-swc/crates/next-build/src/next_pages/page_chunks.rs +++ b/packages/next-swc/crates/next-build/src/next_pages/page_chunks.rs @@ -274,7 +274,6 @@ async fn get_page_chunks_for_directory( let PagesStructureItem { project_path, next_router_path, - specificity: _, } = *item.await?; chunks.push(get_page_chunk_for_file( node_build_context, diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 59120a6ec7..fae5a56ebf 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -12,6 +12,7 @@ bench = false anyhow = { workspace = true } async-recursion = "1.0.2" async-trait = { workspace = true } +const_format = "0.2.30" once_cell = { workspace = true } qstring = { workspace = true } regex = { workspace = true } diff --git a/packages/next-swc/crates/next-core/js/package.json b/packages/next-swc/crates/next-core/js/package.json index cec038935b..95af8717a7 100644 --- a/packages/next-swc/crates/next-core/js/package.json +++ b/packages/next-swc/crates/next-core/js/package.json @@ -10,8 +10,8 @@ "check": "tsc --noEmit" }, "dependencies": { - "@vercel/turbopack-ecmascript-runtime": "https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230628.2", - "@vercel/turbopack-node": "https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230628.2", + "@vercel/turbopack-ecmascript-runtime": "https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230630.2", + "@vercel/turbopack-node": "https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230630.2", "anser": "^2.1.1", "css.escape": "^1.5.1", "next": "*", diff --git a/packages/next-swc/crates/next-core/src/app_segment_config.rs b/packages/next-swc/crates/next-core/src/app_segment_config.rs index 5bbd1c6a48..e5ba843396 100644 --- a/packages/next-swc/crates/next-core/src/app_segment_config.rs +++ b/packages/next-swc/crates/next-core/src/app_segment_config.rs @@ -281,23 +281,23 @@ fn parse_config_value( "dynamic" => { let value = eval_context.eval(init); let Some(val) = value.as_str() else { - return invalid_config("`dynamic` needs to be a static string", &value); + invalid_config("`dynamic` needs to be a static string", &value); + return; }; config.dynamic = match serde_json::from_value(Value::String(val.to_string())) { Ok(dynamic) => Some(dynamic), Err(err) => { - return invalid_config( - &format!("`dynamic` has an invalid value: {}", err), - &value, - ) + invalid_config(&format!("`dynamic` has an invalid value: {}", err), &value); + return; } }; } "dynamicParams" => { let value = eval_context.eval(init); let Some(val) = value.as_bool() else { - return invalid_config("`dynamicParams` needs to be a static boolean", &value); + invalid_config("`dynamicParams` needs to be a static boolean", &value); + return }; config.dynamic_params = Some(val); @@ -326,39 +326,41 @@ fn parse_config_value( "fetchCache" => { let value = eval_context.eval(init); let Some(val) = value.as_str() else { - return invalid_config("`fetchCache` needs to be a static string", &value); + invalid_config("`fetchCache` needs to be a static string", &value); + return; }; config.fetch_cache = match serde_json::from_value(Value::String(val.to_string())) { Ok(fetch_cache) => Some(fetch_cache), Err(err) => { - return invalid_config( + invalid_config( &format!("`fetchCache` has an invalid value: {}", err), &value, - ) + ); + return; } }; } "runtime" => { let value = eval_context.eval(init); let Some(val) = value.as_str() else { - return invalid_config("`runtime` needs to be a static string", &value); + invalid_config("`runtime` needs to be a static string", &value); + return; }; config.runtime = match serde_json::from_value(Value::String(val.to_string())) { Ok(runtime) => Some(runtime), Err(err) => { - return invalid_config( - &format!("`runtime` has an invalid value: {}", err), - &value, - ) + invalid_config(&format!("`runtime` has an invalid value: {}", err), &value); + return; } }; } "preferredRegion" => { let value = eval_context.eval(init); let Some(val) = value.as_str() else { - return invalid_config("`preferredRegion` needs to be a static string", &value); + invalid_config("`preferredRegion` needs to be a static string", &value); + return; }; config.preferred_region = Some(val.to_string()); diff --git a/packages/next-swc/crates/next-core/src/app_source.rs b/packages/next-swc/crates/next-core/src/app_source.rs index 5d8f680732..7fd06bdb60 100644 --- a/packages/next-swc/crates/next-core/src/app_source.rs +++ b/packages/next-swc/crates/next-core/src/app_source.rs @@ -32,7 +32,7 @@ use turbopack_binding::{ source::{ asset_graph::AssetGraphContentSourceVc, combined::CombinedContentSource, - specificity::{Specificity, SpecificityElementType, SpecificityVc}, + route_tree::{BaseSegment, RouteType}, ContentSourceData, ContentSourceVc, NoContentSourceVc, }, }, @@ -99,31 +99,34 @@ use crate::{ util::{render_data, NextRuntime}, }; -#[turbo_tasks::function] -fn pathname_to_specificity(pathname: &str) -> SpecificityVc { - let mut current = Specificity::new(); - let mut position = 0; - for segment in pathname.split('/') { - if segment.starts_with('(') && segment.ends_with(')') || segment.starts_with('@') { +fn pathname_to_segments(pathname: &str) -> Result<(Vec, RouteType)> { + let mut segments = Vec::new(); + let mut split = pathname.split('/'); + while let Some(segment) = split.next() { + if segment.is_empty() + || (segment.starts_with('(') && segment.ends_with(')') || segment.starts_with('@')) + { // ignore } else if segment.starts_with("[[...") && segment.ends_with("]]") || segment.starts_with("[...") && segment.ends_with(']') { - // optional catch all segment - current.add(position - 1, SpecificityElementType::CatchAll); - position += 1; - } else if segment.starts_with("[[") || segment.ends_with("]]") { - // optional segment - position += 1; + // (optional) catch all segment + if split.remainder().is_some() { + bail!( + "Invalid route {}, catch all segment must be the last segment", + pathname + ) + } + return Ok((segments, RouteType::CatchAll)); } else if segment.starts_with('[') || segment.ends_with(']') { - current.add(position - 1, SpecificityElementType::DynamicSegment); - position += 1; + // dynamic segment + segments.push(BaseSegment::Dynamic); } else { // normal segment - position += 1; + segments.push(BaseSegment::Static(segment.to_string())); } } - SpecificityVc::cell(current) + Ok((segments, RouteType::Exact)) } #[turbo_tasks::function] @@ -666,10 +669,13 @@ async fn create_app_page_source_for_route( let params_matcher = NextParamsMatcherVc::new(pathname_vc); + let (base_segments, route_type) = pathname_to_segments(pathname)?; + let source = create_node_rendered_source( project_path, env, - pathname_to_specificity(pathname), + base_segments, + route_type, server_root, params_matcher.into(), pathname_vc, @@ -713,7 +719,8 @@ async fn create_app_not_found_page_source( let source = create_node_rendered_source( project_path, env, - SpecificityVc::not_found(), + Vec::new(), + RouteType::NotFound, server_root, NextFallbackMatcherVc::new().into(), pathname_vc, @@ -755,10 +762,13 @@ async fn create_app_route_source_for_route( let params_matcher = NextParamsMatcherVc::new(pathname_vc); + let (base_segments, route_type) = pathname_to_segments(pathname)?; + let source = create_node_api_source( project_path, env, - pathname_to_specificity(pathname), + base_segments, + route_type, server_root, params_matcher.into(), pathname_vc, diff --git a/packages/next-swc/crates/next-core/src/lib.rs b/packages/next-swc/crates/next-core/src/lib.rs index 03f2a530af..b8d6ff96ea 100644 --- a/packages/next-swc/crates/next-core/src/lib.rs +++ b/packages/next-swc/crates/next-core/src/lib.rs @@ -1,6 +1,7 @@ #![feature(async_closure)] #![feature(min_specialization)] #![feature(box_syntax)] +#![feature(str_split_remainder)] mod app_render; mod app_segment_config; diff --git a/packages/next-swc/crates/next-core/src/manifest.rs b/packages/next-swc/crates/next-core/src/manifest.rs index 21858e6642..5d414de2b9 100644 --- a/packages/next-swc/crates/next-core/src/manifest.rs +++ b/packages/next-swc/crates/next-core/src/manifest.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use indexmap::IndexMap; use mime::{APPLICATION_JAVASCRIPT_UTF_8, APPLICATION_JSON}; use serde::Serialize; @@ -14,8 +14,9 @@ use turbopack_binding::{ introspect::{Introspectable, IntrospectableVc}, }, dev_server::source::{ - ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceResultVc, - ContentSourceVc, + route_tree::{BaseSegment, RouteTreeVc, RouteTreesVc, RouteType}, + ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceVc, + GetContentSourceContent, GetContentSourceContentVc, }, node::render::{ node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc, @@ -151,16 +152,46 @@ struct BuildManifest<'a> { routes: IndexMap<&'a String, Vec>, } +const DEV_MANIFEST_PATHNAME: &str = "_next/static/development/_devPagesManifest.json"; +const BUILD_MANIFEST_PATHNAME: &str = "_next/static/development/_buildManifest.js"; +const DEV_MIDDLEWARE_MANIFEST_PATHNAME: &str = + "_next/static/development/_devMiddlewareManifest.json"; + #[turbo_tasks::value_impl] impl ContentSource for DevManifestContentSource { + #[turbo_tasks::function] + fn get_routes(self_vc: DevManifestContentSourceVc) -> RouteTreeVc { + RouteTreesVc::cell(vec![ + RouteTreeVc::new_route( + BaseSegment::from_static_pathname(DEV_MANIFEST_PATHNAME).collect(), + RouteType::Exact, + self_vc.into(), + ), + RouteTreeVc::new_route( + BaseSegment::from_static_pathname(BUILD_MANIFEST_PATHNAME).collect(), + RouteType::Exact, + self_vc.into(), + ), + RouteTreeVc::new_route( + BaseSegment::from_static_pathname(DEV_MIDDLEWARE_MANIFEST_PATHNAME).collect(), + RouteType::Exact, + self_vc.into(), + ), + ]) + .merge() + } +} + +#[turbo_tasks::value_impl] +impl GetContentSourceContent for DevManifestContentSource { #[turbo_tasks::function] async fn get( self_vc: DevManifestContentSourceVc, path: &str, _data: turbo_tasks::Value, - ) -> Result { + ) -> Result { let manifest_file = match path { - "_next/static/development/_devPagesManifest.json" => { + DEV_MANIFEST_PATHNAME => { let pages = &*self_vc.find_routes().await?; File::from(serde_json::to_string(&serde_json::json!({ @@ -168,12 +199,12 @@ impl ContentSource for DevManifestContentSource { }))?) .with_content_type(APPLICATION_JSON) } - "_next/static/development/_buildManifest.js" => { + BUILD_MANIFEST_PATHNAME => { let build_manifest = &*self_vc.create_build_manifest().await?; File::from(build_manifest.as_str()).with_content_type(APPLICATION_JAVASCRIPT_UTF_8) } - "_next/static/development/_devMiddlewareManifest.json" => { + DEV_MIDDLEWARE_MANIFEST_PATHNAME => { // If there is actual middleware, this request will have been handled by the // node router in next-core/js/src/entry/router.ts and // next/src/server/lib/route-resolver.ts. @@ -181,12 +212,11 @@ impl ContentSource for DevManifestContentSource { // respond with an empty `MiddlewareMatcher[]`. File::from("[]").with_content_type(APPLICATION_JSON) } - _ => return Ok(ContentSourceResultVc::not_found()), + _ => bail!("unknown path: {}", path), }; - Ok(ContentSourceResultVc::exact( - ContentSourceContentVc::static_content(AssetContentVc::from(manifest_file).into()) - .into(), + Ok(ContentSourceContentVc::static_content( + AssetContentVc::from(manifest_file).into(), )) } } diff --git a/packages/next-swc/crates/next-core/src/next_image/content_source.rs b/packages/next-swc/crates/next-core/src/next_image/content_source.rs index b3e1601e89..4d137b42d0 100644 --- a/packages/next-swc/crates/next-core/src/next_image/content_source.rs +++ b/packages/next-swc/crates/next-core/src/next_image/content_source.rs @@ -1,6 +1,4 @@ -use std::collections::BTreeSet; - -use anyhow::Result; +use anyhow::{bail, Result}; use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks_fs::FileSystem; use turbopack_binding::turbopack::{ @@ -13,13 +11,14 @@ use turbopack_binding::turbopack::{ }, dev_server::source::{ query::QueryValue, + route_tree::{RouteTreeVc, RouteType}, wrapping_source::{ - encode_pathname_to_url, ContentSourceProcessor, ContentSourceProcessorVc, - WrappedContentSourceVc, + ContentSourceProcessor, ContentSourceProcessorVc, WrappedGetContentSourceContentVc, }, ContentSource, ContentSourceContent, ContentSourceContentVc, ContentSourceData, - ContentSourceDataFilter, ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, - NeededData, ProxyResult, RewriteBuilder, + ContentSourceDataFilter, ContentSourceDataVary, ContentSourceDataVaryVc, ContentSourceVc, + GetContentSourceContent, GetContentSourceContentVc, GetContentSourceContentsVc, + ProxyResult, RewriteBuilder, }, image::process::optimize, }; @@ -41,85 +40,92 @@ impl NextImageContentSourceVc { #[turbo_tasks::value_impl] impl ContentSource for NextImageContentSource { + #[turbo_tasks::function] + fn get_routes(self_vc: NextImageContentSourceVc) -> RouteTreeVc { + RouteTreeVc::new_route(Vec::new(), RouteType::Exact, self_vc.into()) + } +} + +#[turbo_tasks::value_impl] +impl GetContentSourceContent for NextImageContentSource { + #[turbo_tasks::function] + async fn vary(&self) -> ContentSourceDataVaryVc { + ContentSourceDataVary { + query: Some(ContentSourceDataFilter::Subset( + ["url".to_string(), "w".to_string(), "q".to_string()].into(), + )), + ..Default::default() + } + .cell() + } + #[turbo_tasks::function] async fn get( self_vc: NextImageContentSourceVc, - path: &str, + _path: &str, data: Value, - ) -> Result { + ) -> Result { let this = self_vc.await?; let Some(query) = &data.query else { - let queries = ["url".to_string(), "w".to_string(), "q".to_string()] - .into_iter() - .collect::>(); - - return Ok(ContentSourceResultVc::need_data(Value::new(NeededData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - url: true, - query: Some(ContentSourceDataFilter::Subset(queries)), - ..Default::default() - }, - }))); + bail!("missing query"); }; let Some(QueryValue::String(url)) = query.get("url") else { - return Ok(ContentSourceResultVc::not_found()); + bail!("missing url"); }; let q = match query.get("q") { None => 75, Some(QueryValue::String(s)) => { let Ok(q) = s.parse::() else { - return Ok(ContentSourceResultVc::not_found()); + bail!("invalid q query argument") }; q } - _ => return Ok(ContentSourceResultVc::not_found()), + _ => bail!("missing q query argument"), }; let w = match query.get("w") { Some(QueryValue::String(s)) => { let Ok(w) = s.parse::() else { - return Ok(ContentSourceResultVc::not_found()); + bail!("invalid w query argument") }; w } - _ => return Ok(ContentSourceResultVc::not_found()), + _ => bail!("missing w query argument"), }; // TODO: re-encode into next-gen formats. + if let Some(path) = url.strip_prefix('/') { - let wrapped = WrappedContentSourceVc::new( - this.asset_source, - NextImageContentSourceProcessorVc::new(path.to_string(), w, q).into(), + let sources = this.asset_source.get_routes().get(path).await?; + let sources = sources + .iter() + .map(|s| { + WrappedGetContentSourceContentVc::new( + *s, + NextImageContentSourceProcessorVc::new(path.to_string(), w, q).into(), + ) + .into() + }) + .collect(); + let sources = GetContentSourceContentsVc::cell(sources); + return Ok( + ContentSourceContent::Rewrite(RewriteBuilder::new_sources(sources).build()).cell(), ); - return Ok(ContentSourceResultVc::exact( - ContentSourceContent::Rewrite( - RewriteBuilder::new(encode_pathname_to_url(path)) - .content_source(wrapped.as_content_source()) - .build(), - ) - .cell() - .into(), - )); } // TODO: This should be downloaded by the server, and resized, etc. - Ok(ContentSourceResultVc::exact( - ContentSourceContent::HttpProxy( - ProxyResult { - status: 302, - headers: vec![("Location".to_string(), url.clone())], - body: "".into(), - } - .cell(), - ) - .cell() - .into(), - )) + Ok(ContentSourceContent::HttpProxy( + ProxyResult { + status: 302, + headers: vec![("Location".to_string(), url.clone())], + body: "".into(), + } + .cell(), + ) + .cell()) } } diff --git a/packages/next-swc/crates/next-core/src/page_source.rs b/packages/next-swc/crates/next-core/src/page_source.rs index 95329e2400..80c349349a 100644 --- a/packages/next-swc/crates/next-core/src/page_source.rs +++ b/packages/next-swc/crates/next-core/src/page_source.rs @@ -26,7 +26,7 @@ use turbopack_binding::{ source::{ asset_graph::AssetGraphContentSourceVc, combined::{CombinedContentSource, CombinedContentSourceVc}, - specificity::SpecificityVc, + route_tree::{BaseSegment, RouteType}, ContentSourceData, ContentSourceVc, }, }, @@ -291,7 +291,8 @@ pub async fn create_page_source( fallback_page, client_root, node_root.join("force_not_found"), - SpecificityVc::exact(), + BaseSegment::from_static_pathname("_next/404").collect(), + RouteType::Exact, NextExactMatcherVc::new(StringVc::cell("_next/404".to_string())).into(), render_data, ) @@ -333,7 +334,8 @@ pub async fn create_page_source( fallback_page, client_root, node_root.join("fallback_not_found"), - SpecificityVc::not_found(), + Vec::new(), + RouteType::NotFound, NextFallbackMatcherVc::new().into(), render_data, ) @@ -353,7 +355,6 @@ async fn create_page_source_for_file( server_data_context: AssetContextVc, client_context: AssetContextVc, pages_dir: FileSystemPathVc, - specificity: SpecificityVc, page_asset: AssetVc, runtime_entries: AssetsVc, fallback_page: DevHtmlAssetVc, @@ -402,11 +403,14 @@ async fn create_page_source_for_file( let pathname = pathname_for_path(client_root, client_path, PathType::Page); let route_matcher = NextParamsMatcherVc::new(pathname); + let (base_segments, route_type) = pathname_to_segments(&pathname.await?, "")?; + Ok(if is_api_path { create_node_api_source( project_path, env, - specificity, + base_segments, + route_type, client_root, route_matcher.into(), pathname, @@ -429,6 +433,10 @@ async fn create_page_source_for_file( let data_pathname = pathname_for_path(client_root, client_path, PathType::Data); let data_route_matcher = NextPrefixSuffixParamsMatcherVc::new(data_pathname, "_next/data/development/", ".json"); + let (data_base_segments, data_route_type) = pathname_to_segments( + &format!("_next/data/development/{}", data_pathname.await?), + ".json", + )?; let ssr_entry = SsrEntry { runtime_entries, @@ -460,7 +468,8 @@ async fn create_page_source_for_file( create_node_rendered_source( project_path, env, - specificity, + base_segments.clone(), + route_type.clone(), client_root, route_matcher.into(), pathname, @@ -472,7 +481,8 @@ async fn create_page_source_for_file( create_node_rendered_source( project_path, env, - specificity, + data_base_segments, + data_route_type, client_root, data_route_matcher.into(), pathname, @@ -520,7 +530,8 @@ async fn create_not_found_page_source( fallback_page: DevHtmlAssetVc, client_root: FileSystemPathVc, node_path: FileSystemPathVc, - specificity: SpecificityVc, + base_segments: Vec, + route_type: RouteType, route_matcher: RouteMatcherVc, render_data: JsonValueVc, ) -> Result { @@ -588,7 +599,8 @@ async fn create_not_found_page_source( create_node_rendered_source( project_path, env, - specificity, + base_segments, + route_type, client_root, route_matcher, pathname, @@ -695,7 +707,6 @@ async fn create_page_source_for_directory( for item in items.iter() { let PagesStructureItem { project_path, - specificity, next_router_path, } = *item.await?; let source = create_page_source_for_file( @@ -705,7 +716,6 @@ async fn create_page_source_for_directory( server_data_context, client_context, pages_dir, - specificity, SourceAssetVc::new(project_path).into(), runtime_entries, fallback_page, @@ -748,6 +758,37 @@ async fn create_page_source_for_directory( Ok(CombinedContentSource { sources }.cell().into()) } +fn pathname_to_segments(pathname: &str, extension: &str) -> Result<(Vec, RouteType)> { + let mut segments = Vec::new(); + let mut split = pathname.split('/'); + while let Some(segment) = split.next() { + if segment.is_empty() { + // ignore + } else if segment.starts_with("[[...") && segment.ends_with("]]") + || segment.starts_with("[...") && segment.ends_with(']') + { + // (optional) catch all segment + if split.remainder().is_some() { + bail!( + "Invalid route {}, catch all segment must be the last segment", + pathname + ) + } + return Ok((segments, RouteType::CatchAll)); + } else if segment.starts_with('[') || segment.ends_with(']') { + // dynamic segment + segments.push(BaseSegment::Dynamic); + } else { + // normal segment + segments.push(BaseSegment::Static(segment.to_string())); + } + } + if let Some(BaseSegment::Static(s)) = segments.last_mut() { + s.push_str(extension); + } + Ok((segments, RouteType::Exact)) +} + /// The node.js renderer for SSR of pages. #[turbo_tasks::value] pub struct SsrEntry { diff --git a/packages/next-swc/crates/next-core/src/pages_structure.rs b/packages/next-swc/crates/next-core/src/pages_structure.rs index 7d1bcb5c1b..cd5524064a 100644 --- a/packages/next-swc/crates/next-core/src/pages_structure.rs +++ b/packages/next-swc/crates/next-core/src/pages_structure.rs @@ -1,8 +1,7 @@ use anyhow::Result; use turbo_tasks::{primitives::StringsVc, CompletionVc}; -use turbopack_binding::{ - turbo::tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}, - turbopack::dev_server::source::specificity::SpecificityVc, +use turbopack_binding::turbo::tasks_fs::{ + DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc, }; use crate::{embed_js::next_js_file_path, next_config::NextConfigVc}; @@ -12,7 +11,6 @@ use crate::{embed_js::next_js_file_path, next_config::NextConfigVc}; pub struct PagesStructureItem { pub project_path: FileSystemPathVc, pub next_router_path: FileSystemPathVc, - pub specificity: SpecificityVc, } #[turbo_tasks::value_impl] @@ -21,12 +19,10 @@ impl PagesStructureItemVc { async fn new( project_path: FileSystemPathVc, next_router_path: FileSystemPathVc, - specificity: SpecificityVc, ) -> Result { Ok(PagesStructureItem { project_path, next_router_path, - specificity, } .cell()) } @@ -179,7 +175,6 @@ async fn get_pages_structure_for_root_directory( let mut document_item = None; let mut error_item = None; let mut api_directory = None; - let specificity = SpecificityVc::exact(); let dir_content = project_path.read_dir().await?; if let DirectoryContent::Entries(entries) = &*dir_content { for (name, entry) in entries.iter() { @@ -193,34 +188,26 @@ async fn get_pages_structure_for_root_directory( let _ = app_item.insert(PagesStructureItemVc::new( *file_project_path, next_router_path.join("_app"), - specificity, )); } "_document" => { let _ = document_item.insert(PagesStructureItemVc::new( *file_project_path, next_router_path.join("_document"), - specificity, )); } "_error" => { let _ = error_item.insert(PagesStructureItemVc::new( *file_project_path, next_router_path.join("_error"), - specificity, )); } basename => { - let specificity = entry_specificity(specificity, name, 0); let next_router_path = next_router_path_for_basename(next_router_path, basename); items.push(( basename, - PagesStructureItemVc::new( - *file_project_path, - next_router_path, - specificity, - ), + PagesStructureItemVc::new(*file_project_path, next_router_path), )); } } @@ -230,19 +217,16 @@ async fn get_pages_structure_for_root_directory( let _ = api_directory.insert(get_pages_structure_for_directory( *dir_project_path, next_router_path.join(name), - specificity, 1, page_extensions, )); } _ => { - let specificity = entry_specificity(SpecificityVc::exact(), name, 0); children.push(( name, get_pages_structure_for_directory( *dir_project_path, next_router_path.join(name), - specificity, 1, page_extensions, ), @@ -264,7 +248,6 @@ async fn get_pages_structure_for_root_directory( PagesStructureItemVc::new( next_js_file_path("entry/pages/_app.tsx"), next_router_path.join("_app"), - specificity, ) }; @@ -274,7 +257,6 @@ async fn get_pages_structure_for_root_directory( PagesStructureItemVc::new( next_js_file_path("entry/pages/_document.tsx"), next_router_path.join("_document"), - specificity, ) }; @@ -284,7 +266,6 @@ async fn get_pages_structure_for_root_directory( PagesStructureItemVc::new( next_js_file_path("entry/pages/_error.tsx"), next_router_path.join("_error"), - specificity, ) }; @@ -311,7 +292,6 @@ async fn get_pages_structure_for_root_directory( async fn get_pages_structure_for_directory( project_path: FileSystemPathVc, next_router_path: FileSystemPathVc, - specificity: SpecificityVc, position: u32, page_extensions: StringsVc, ) -> Result { @@ -322,7 +302,6 @@ async fn get_pages_structure_for_directory( let dir_content = project_path.read_dir().await?; if let DirectoryContent::Entries(entries) = &*dir_content { for (name, entry) in entries.iter() { - let specificity = entry_specificity(specificity, name, position); match entry { DirectoryEntry::File(file_project_path) => { let Some(basename) = page_basename(name, page_extensions_raw) else { @@ -334,11 +313,7 @@ async fn get_pages_structure_for_directory( }; items.push(( basename, - PagesStructureItemVc::new( - *file_project_path, - next_router_path, - specificity, - ), + PagesStructureItemVc::new(*file_project_path, next_router_path), )); } DirectoryEntry::Directory(dir_project_path) => { @@ -347,7 +322,6 @@ async fn get_pages_structure_for_directory( get_pages_structure_for_directory( *dir_project_path, next_router_path.join(name), - specificity, position + 1, page_extensions, ), @@ -373,16 +347,6 @@ async fn get_pages_structure_for_directory( .cell()) } -fn entry_specificity(specificity: SpecificityVc, name: &str, position: u32) -> SpecificityVc { - if name.starts_with("[[") || name.starts_with("[...") { - specificity.with_catch_all(position) - } else if name.starts_with('[') { - specificity.with_dynamic_segment(position) - } else { - specificity - } -} - fn page_basename<'a>(name: &'a str, page_extensions: &'a [String]) -> Option<&'a str> { if let Some((basename, extension)) = name.rsplit_once('.') { if page_extensions.iter().any(|allowed| allowed == extension) { diff --git a/packages/next-swc/crates/next-core/src/router_source.rs b/packages/next-swc/crates/next-core/src/router_source.rs index 076dc688b4..e66bdc324b 100644 --- a/packages/next-swc/crates/next-core/src/router_source.rs +++ b/packages/next-swc/crates/next-core/src/router_source.rs @@ -1,4 +1,4 @@ -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use futures::{Stream, TryStreamExt}; use indexmap::IndexSet; use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, Value}; @@ -8,9 +8,10 @@ use turbopack_binding::turbopack::{ introspect::{Introspectable, IntrospectableChildrenVc, IntrospectableVc}, }, dev_server::source::{ - Body, ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataVary, - ContentSourceResultVc, ContentSourceVc, HeaderListVc, NeededData, ProxyResult, - RewriteBuilder, + route_tree::{RouteTreeVc, RouteType}, + Body, ContentSource, ContentSourceContent, ContentSourceContentVc, ContentSourceData, + ContentSourceDataVary, ContentSourceDataVaryVc, ContentSourceVc, GetContentSourceContent, + GetContentSourceContentVc, HeaderListVc, ProxyResult, RewriteBuilder, }, node::execution_context::ExecutionContextVc, }; @@ -56,24 +57,6 @@ impl NextRouterContentSourceVc { } } -#[turbo_tasks::function] -fn need_data(source: ContentSourceVc, path: &str) -> ContentSourceResultVc { - ContentSourceResultVc::need_data( - NeededData { - source, - path: path.to_string(), - vary: ContentSourceDataVary { - method: true, - raw_headers: true, - raw_query: true, - body: true, - ..Default::default() - }, - } - .into(), - ) -} - #[turbo_tasks::function] fn routes_changed( app_dir: OptionAppDirVc, @@ -89,22 +72,48 @@ fn routes_changed( #[turbo_tasks::value_impl] impl ContentSource for NextRouterContentSource { #[turbo_tasks::function] - async fn get( - self_vc: NextRouterContentSourceVc, - path: &str, - data: Value, - ) -> Result { + async fn get_routes(self_vc: NextRouterContentSourceVc) -> Result { let this = self_vc.await?; - // The next-dev server can currently run against projects as simple as // `index.js`. If this isn't a Next.js project, don't try to use the Next.js // router. if this.app_dir.await?.is_none() && this.pages_structure.await?.is_none() { - return Ok(this - .inner - .get(path, Value::new(ContentSourceData::default()))); + return Ok(this.inner.get_routes()); } + // Prefetch get_routes from inner + let _ = this.inner.get_routes(); + + Ok(RouteTreeVc::new_route( + Vec::new(), + RouteType::CatchAll, + self_vc.into(), + )) + } +} + +#[turbo_tasks::value_impl] +impl GetContentSourceContent for NextRouterContentSource { + #[turbo_tasks::function] + fn vary(&self) -> ContentSourceDataVaryVc { + ContentSourceDataVary { + method: true, + raw_headers: true, + raw_query: true, + body: true, + ..Default::default() + } + .cell() + } + + #[turbo_tasks::function] + async fn get( + self_vc: NextRouterContentSourceVc, + path: &str, + data: Value, + ) -> Result { + let this = self_vc.await?; + let ContentSourceData { method: Some(method), raw_headers: Some(raw_headers), @@ -112,7 +121,7 @@ impl ContentSource for NextRouterContentSource { body: Some(body), .. } = &*data else { - return Ok(need_data(self_vc.into(), path)) + bail!("missing data for router"); }; // TODO: change router so we can stream the request body to it @@ -151,30 +160,28 @@ impl ContentSource for NextRouterContentSource { formated_query(raw_query) ))) } - RouterResult::None => this - .inner - .get(path, Value::new(ContentSourceData::default())), + RouterResult::None => { + let rewrite = + RewriteBuilder::new_source_with_path_and_query(this.inner, format!("/{path}")); + ContentSourceContent::Rewrite(rewrite.build()).cell() + } RouterResult::Rewrite(data) => { - let mut rewrite = RewriteBuilder::new(data.url.clone()).content_source(this.inner); + let mut rewrite = + RewriteBuilder::new_source_with_path_and_query(this.inner, data.url.clone()); if !data.headers.is_empty() { rewrite = rewrite.response_headers(HeaderListVc::new(data.headers.clone())); } - ContentSourceResultVc::exact( - ContentSourceContent::Rewrite(rewrite.build()).cell().into(), - ) + ContentSourceContent::Rewrite(rewrite.build()).cell() } - RouterResult::Middleware(data) => ContentSourceResultVc::exact( - ContentSourceContent::HttpProxy( - ProxyResult { - status: data.status_code, - headers: data.headers.clone(), - body: Body::from_stream(data.body.read()), - } - .cell(), - ) - .cell() - .into(), - ), + RouterResult::Middleware(data) => ContentSourceContent::HttpProxy( + ProxyResult { + status: data.status_code, + headers: data.headers.clone(), + body: Body::from_stream(data.body.read()), + } + .cell(), + ) + .cell(), }) } } diff --git a/packages/next-swc/crates/next-dev-tests/test-harness/harness.ts b/packages/next-swc/crates/next-dev-tests/test-harness/harness.ts index 78d7efbb11..38deb45c34 100644 --- a/packages/next-swc/crates/next-dev-tests/test-harness/harness.ts +++ b/packages/next-swc/crates/next-dev-tests/test-harness/harness.ts @@ -133,7 +133,8 @@ export function waitForLoaded(iframe: HTMLIFrameElement): Promise { return new Promise((resolve) => { if ( iframe.contentDocument != null && - iframe.contentDocument.readyState === 'complete' + iframe.contentDocument.readyState === 'complete' && + iframe.contentDocument.documentURI !== 'about:blank' ) { resolve() } else { @@ -147,11 +148,12 @@ export function waitForLoaded(iframe: HTMLIFrameElement): Promise { } export function waitForSelector( - node: ParentNode | HTMLIFrameElement | ShadowRoot, + node: HTMLIFrameElement | ShadowRoot, selector: string ): Promise { return new Promise((resolve, reject) => { - const document = 'contentDocument' in node ? node.contentDocument! : node + const document = + 'contentDocument' in node ? node.contentDocument!.documentElement : node const timeout = 30000 let element = document.querySelector(selector) if (element) { @@ -168,14 +170,20 @@ export function waitForSelector( if (timeout) { setTimeout(() => { observer.disconnect() - reject(new Error(`Timed out waiting for selector "${selector}"`)) + reject( + new Error( + `Timed out waiting for selector "${selector}" in "${document}"\n\nNode content: "${ + 'innerHTML' in document ? document.innerHTML : 'no innerHTML' + }"` + ) + ) }, timeout) } }) } export async function waitForErrorOverlay( - node: ParentNode | HTMLIFrameElement + node: HTMLIFrameElement ): Promise { let element = await waitForSelector(node, 'nextjs-portal') return element.shadowRoot! diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/app/layout.tsx b/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/app/layout.tsx index 12c8468088..a0bd20efce 100644 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/app/layout.tsx +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/app/layout.tsx @@ -1,7 +1,10 @@ export default function RootLayout({ children }: { children: any }) { return ( - {children} + +

RootLayout

+ {children} + ) } diff --git a/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/pages/index.tsx b/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/pages/index.tsx index 4ef1adc65f..82d2595809 100644 --- a/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/pages/index.tsx +++ b/packages/next-swc/crates/next-dev-tests/tests/integration/next/error/ssr/input/pages/index.tsx @@ -33,7 +33,7 @@ function runTests( const TIMEOUT = 40000 it( - 'returns a 500 status code', + 'returns a 500 status code for a broken page', async () => { const res = await fetch('/broken') expect(res.status).toBe(500) @@ -41,6 +41,17 @@ function runTests( TIMEOUT ) + // The existance of this test case fixes the error overlay later. + // I think it's related to streaming the result. + it( + 'returns a 200 status code for a broken app page', + async () => { + const res = await fetch('/broken-app') + expect(res.status).toBe(200) + }, + TIMEOUT + ) + it( 'should show error overlay for a broken page', async () => { diff --git a/packages/next-swc/crates/next-dev/src/lib.rs b/packages/next-swc/crates/next-dev/src/lib.rs index c2135e3163..fab1fd6c46 100644 --- a/packages/next-swc/crates/next-dev/src/lib.rs +++ b/packages/next-swc/crates/next-dev/src/lib.rs @@ -29,6 +29,7 @@ use once_cell::sync::Lazy; use owo_colors::OwoColorize; use tracing_subscriber::{prelude::*, EnvFilter, Registry}; use turbo_tasks::{ + primitives::StringVc, util::{FormatBytes, FormatDuration}, StatsType, TransientInstance, TurboTasks, TurboTasksBackendApi, UpdateInfo, Value, }; @@ -60,7 +61,7 @@ use turbopack_binding::{ dev_server::{ introspect::IntrospectionSource, source::{ - combined::CombinedContentSourceVc, router::RouterContentSource, + combined::CombinedContentSourceVc, router::PrefixedRouterContentSource, source_maps::SourceMapContentSourceVc, static_assets::StaticAssetsContentSourceVc, ContentSourceVc, }, @@ -413,17 +414,18 @@ async fn source( pages_structure, ) .into(); - let source = RouterContentSource { + let source = PrefixedRouterContentSource { + prefix: StringVc::empty(), routes: vec![ - ("__turbopack__/".to_string(), introspect), - ("__turbo_tasks__/".to_string(), viz), + ("__turbopack__".to_string(), introspect), + ("__turbo_tasks__".to_string(), viz), ( "__nextjs_original-stack-frame".to_string(), source_map_trace, ), // TODO: Load path from next.config.js ("_next/image".to_string(), img_source), - ("__turbopack_sourcemap__/".to_string(), source_maps), + ("__turbopack_sourcemap__".to_string(), source_maps), ], fallback: router_source, } diff --git a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs index 897598e860..d1a83e3840 100644 --- a/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs +++ b/packages/next-swc/crates/next-dev/src/turbo_tasks_viz.rs @@ -1,6 +1,6 @@ use std::{sync::Arc, time::Duration}; -use anyhow::Result; +use anyhow::{bail, Result}; use mime::TEXT_HTML_UTF_8; use turbo_tasks::{get_invalidator, TurboTasks, TurboTasksBackendApi, Value}; use turbopack_binding::{ @@ -14,8 +14,10 @@ use turbopack_binding::{ turbopack::{ core::asset::AssetContentVc, dev_server::source::{ + route_tree::{BaseSegment, RouteTreeVc, RouteTreesVc, RouteType}, ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceDataFilter, - ContentSourceDataVary, ContentSourceResultVc, ContentSourceVc, NeededData, + ContentSourceDataVary, ContentSourceDataVaryVc, ContentSourceVc, + GetContentSourceContent, GetContentSourceContentVc, }, }, }; @@ -34,14 +36,58 @@ impl TurboTasksSourceVc { const INVALIDATION_INTERVAL: Duration = Duration::from_secs(3); +const GRAPH_PATH: &str = "graph"; +const CALL_GRAPH_PATH: &str = "call-graph"; +const TABLE_PATH: &str = "table"; +const RESET_PATH: &str = "reset"; + #[turbo_tasks::value_impl] impl ContentSource for TurboTasksSource { + #[turbo_tasks::function] + fn get_routes(self_vc: TurboTasksSourceVc) -> RouteTreeVc { + RouteTreesVc::cell(vec![ + RouteTreeVc::new_route( + vec![BaseSegment::Static(GRAPH_PATH.to_string())], + RouteType::Exact, + self_vc.into(), + ), + RouteTreeVc::new_route( + vec![BaseSegment::Static(CALL_GRAPH_PATH.to_string())], + RouteType::Exact, + self_vc.into(), + ), + RouteTreeVc::new_route( + vec![BaseSegment::Static(TABLE_PATH.to_string())], + RouteType::Exact, + self_vc.into(), + ), + RouteTreeVc::new_route( + vec![BaseSegment::Static(RESET_PATH.to_string())], + RouteType::Exact, + self_vc.into(), + ), + ]) + .merge() + } +} + +#[turbo_tasks::value_impl] +impl GetContentSourceContent for TurboTasksSource { + #[turbo_tasks::function] + fn vary(&self) -> ContentSourceDataVaryVc { + ContentSourceDataVary { + query: Some(ContentSourceDataFilter::All), + ..Default::default() + } + .cell() + } + #[turbo_tasks::function] async fn get( self_vc: TurboTasksSourceVc, path: &str, data: Value, - ) -> Result { + ) -> Result { let this = self_vc.await?; let tt = &this.turbo_tasks; let invalidator = get_invalidator(); @@ -52,7 +98,7 @@ impl ContentSource for TurboTasksSource { } }); let html = match path { - "graph" => { + GRAPH_PATH => { let mut stats = Stats::new(); let b = tt.backend(); b.with_all_cached_tasks(|task| { @@ -66,7 +112,7 @@ impl ContentSource for TurboTasksSource { ); viz::graph::wrap_html(&graph) } - "call-graph" => { + CALL_GRAPH_PATH => { let mut stats = Stats::new(); let b = tt.backend(); b.with_all_cached_tasks(|task| { @@ -77,45 +123,34 @@ impl ContentSource for TurboTasksSource { viz::graph::visualize_stats_tree(tree, ReferenceType::Child, tt.stats_type()); viz::graph::wrap_html(&graph) } - "table" => { - if let Some(query) = &data.query { - let mut stats = Stats::new(); - let b = tt.backend(); - let active_only = query.contains_key("active"); - let include_unloaded = query.contains_key("unloaded"); - b.with_all_cached_tasks(|task| { - stats.add_id_conditional(b, task, |_, info| { - (include_unloaded || !info.unloaded) && (!active_only || info.active) - }); + TABLE_PATH => { + let Some(query) = &data.query else { + bail!("Missing query"); + }; + let mut stats = Stats::new(); + let b = tt.backend(); + let active_only = query.contains_key("active"); + let include_unloaded = query.contains_key("unloaded"); + b.with_all_cached_tasks(|task| { + stats.add_id_conditional(b, task, |_, info| { + (include_unloaded || !info.unloaded) && (!active_only || info.active) }); - let tree = stats.treeify(ReferenceType::Dependency); - let table = viz::table::create_table(tree, tt.stats_type()); - viz::table::wrap_html(&table) - } else { - return Ok(ContentSourceResultVc::need_data(Value::new(NeededData { - source: self_vc.into(), - path: path.to_string(), - vary: ContentSourceDataVary { - query: Some(ContentSourceDataFilter::All), - ..Default::default() - }, - }))); - } + }); + let tree = stats.treeify(ReferenceType::Dependency); + let table = viz::table::create_table(tree, tt.stats_type()); + viz::table::wrap_html(&table) } - "reset" => { + RESET_PATH => { let b = tt.backend(); b.with_all_cached_tasks(|task| { b.with_task(task, |task| task.reset_stats()); }); "Done".to_string() } - _ => return Ok(ContentSourceResultVc::not_found()), + _ => bail!("Unknown path: {}", path), }; - Ok(ContentSourceResultVc::exact( - ContentSourceContentVc::static_content( - AssetContentVc::from(File::from(html).with_content_type(TEXT_HTML_UTF_8)).into(), - ) - .into(), + Ok(ContentSourceContentVc::static_content( + AssetContentVc::from(File::from(html).with_content_type(TEXT_HTML_UTF_8)).into(), )) } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 49e0263f17..0d26888d53 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -992,8 +992,8 @@ importers: '@types/react': 18.2.7 '@types/react-dom': 18.2.4 '@vercel/ncc': ^0.36.0 - '@vercel/turbopack-ecmascript-runtime': https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230628.2 - '@vercel/turbopack-node': https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230628.2 + '@vercel/turbopack-ecmascript-runtime': https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230630.2 + '@vercel/turbopack-node': https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230630.2 anser: ^2.1.1 css.escape: ^1.5.1 find-up: ^6.3.0 @@ -1005,8 +1005,8 @@ importers: stacktrace-parser: ^0.1.10 strip-ansi: ^7.0.1 dependencies: - '@vercel/turbopack-ecmascript-runtime': '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230628.2_react-refresh@0.12.0' - '@vercel/turbopack-node': '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230628.2' + '@vercel/turbopack-ecmascript-runtime': '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230630.2_react-refresh@0.12.0' + '@vercel/turbopack-node': '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230630.2' anser: 2.1.1 css.escape: 1.5.1 next: link:../../../../next @@ -6136,7 +6136,7 @@ packages: dependencies: '@mdx-js/mdx': 2.2.1 source-map: 0.7.3 - webpack: 5.86.0 + webpack: 5.86.0_@swc+core@1.3.55 transitivePeerDependencies: - supports-color @@ -6810,7 +6810,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: true optional: true /@swc/core-darwin-x64/1.3.55: @@ -6819,7 +6818,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: true optional: true /@swc/core-linux-arm-gnueabihf/1.3.55: @@ -6828,7 +6826,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-arm64-gnu/1.3.55: @@ -6837,7 +6834,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-arm64-musl/1.3.55: @@ -6846,7 +6842,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-x64-gnu/1.3.55: @@ -6855,7 +6850,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-linux-x64-musl/1.3.55: @@ -6864,7 +6858,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@swc/core-win32-arm64-msvc/1.3.55: @@ -6873,7 +6866,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: true optional: true /@swc/core-win32-ia32-msvc/1.3.55: @@ -6882,7 +6874,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: true optional: true /@swc/core-win32-x64-msvc/1.3.55: @@ -6891,7 +6882,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: true optional: true /@swc/core/1.3.55_@swc+helpers@0.5.1: @@ -6916,7 +6906,6 @@ packages: '@swc/core-win32-arm64-msvc': 1.3.55 '@swc/core-win32-ia32-msvc': 1.3.55 '@swc/core-win32-x64-msvc': 1.3.55 - dev: true /@swc/helpers/0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} @@ -23819,7 +23808,6 @@ packages: serialize-javascript: 6.0.1 terser: 5.17.7 webpack: 5.86.0_@swc+core@1.3.55 - dev: true /terser/5.10.0: resolution: {integrity: sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA==} @@ -25177,7 +25165,6 @@ packages: - '@swc/core' - esbuild - uglify-js - dev: true /websocket-driver/0.7.3: resolution: {integrity: sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==} @@ -25586,9 +25573,9 @@ packages: /zwitch/2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230628.2_react-refresh@0.12.0': - resolution: {tarball: https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230628.2} - id: '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230628.2' + '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230630.2_react-refresh@0.12.0': + resolution: {tarball: https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230630.2} + id: '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230630.2' name: '@vercel/turbopack-ecmascript-runtime' version: 0.0.0 dependencies: @@ -25599,8 +25586,8 @@ packages: - webpack dev: false - '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230628.2': - resolution: {tarball: https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230628.2} + '@gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230630.2': + resolution: {tarball: https://gitpkg.vercel.app/vercel/turbo/crates/turbopack-node/js?turbopack-230630.2} name: '@vercel/turbopack-node' version: 0.0.0 dependencies: