Turbopack: Vc<T> and Turbo Engine type system improvements (#51792)

This is the Next.js side of https://github.com/vercel/turbo/pull/4587, which makes changes to Turbo Engine to allow expressing value cells as `Vc<Type>` instead of `TypeVc`, leveraging the type system to bring a slew of other improvements to writing Turbo Engine code.

## Turbopack updates

* https://github.com/vercel/turbo/pull/4587
This commit is contained in:
Alex Kirszenberg 2023-07-16 15:56:20 +02:00 committed by GitHub
parent 7ce663ed52
commit 5964b289e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
127 changed files with 4326 additions and 4239 deletions

71
Cargo.lock generated
View file

@ -412,7 +412,7 @@ dependencies = [
[[package]] [[package]]
name = "auto-hash-map" name = "auto-hash-map"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -3599,7 +3599,7 @@ dependencies = [
[[package]] [[package]]
name = "node-file-trace" name = "node-file-trace"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@ -7259,9 +7259,10 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks" name = "turbo-tasks"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait",
"auto-hash-map", "auto-hash-map",
"concurrent-queue", "concurrent-queue",
"dashmap", "dashmap",
@ -7290,7 +7291,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-build" name = "turbo-tasks-build"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo-lock", "cargo-lock",
@ -7302,7 +7303,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-bytes" name = "turbo-tasks-bytes"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -7317,7 +7318,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-env" name = "turbo-tasks-env"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"dotenvs", "dotenvs",
@ -7331,7 +7332,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-fetch" name = "turbo-tasks-fetch"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap",
@ -7348,7 +7349,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-fs" name = "turbo-tasks-fs"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"auto-hash-map", "auto-hash-map",
@ -7378,7 +7379,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-hash" name = "turbo-tasks-hash"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"base16", "base16",
"hex", "hex",
@ -7390,7 +7391,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-macros" name = "turbo-tasks-macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"convert_case 0.6.0", "convert_case 0.6.0",
@ -7404,7 +7405,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-macros-shared" name = "turbo-tasks-macros-shared"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -7414,7 +7415,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-malloc" name = "turbo-tasks-malloc"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"mimalloc", "mimalloc",
] ]
@ -7422,7 +7423,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-memory" name = "turbo-tasks-memory"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"auto-hash-map", "auto-hash-map",
@ -7445,7 +7446,7 @@ dependencies = [
[[package]] [[package]]
name = "turbo-tasks-testing" name = "turbo-tasks-testing"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"auto-hash-map", "auto-hash-map",
@ -7458,7 +7459,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack" name = "turbopack"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-recursion", "async-recursion",
@ -7488,7 +7489,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-bench" name = "turbopack-bench"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chromiumoxide", "chromiumoxide",
@ -7518,7 +7519,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-binding" name = "turbopack-binding"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"auto-hash-map", "auto-hash-map",
"mdxjs", "mdxjs",
@ -7560,7 +7561,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-build" name = "turbopack-build"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap",
@ -7580,7 +7581,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-cli-utils" name = "turbopack-cli-utils"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 4.1.11", "clap 4.1.11",
@ -7604,7 +7605,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-core" name = "turbopack-core"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -7632,7 +7633,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-create-test-app" name = "turbopack-create-test-app"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"clap 4.1.11", "clap 4.1.11",
@ -7645,7 +7646,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-css" name = "turbopack-css"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -7667,7 +7668,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-dev" name = "turbopack-dev"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap",
@ -7691,7 +7692,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-dev-server" name = "turbopack-dev-server"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-compression", "async-compression",
@ -7727,7 +7728,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-ecmascript" name = "turbopack-ecmascript"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -7760,7 +7761,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-ecmascript-plugins" name = "turbopack-ecmascript-plugins"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-trait", "async-trait",
@ -7783,7 +7784,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-ecmascript-runtime" name = "turbopack-ecmascript-runtime"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indoc", "indoc",
@ -7800,7 +7801,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-env" name = "turbopack-env"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"indexmap", "indexmap",
@ -7816,7 +7817,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-image" name = "turbopack-image"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.21.0", "base64 0.21.0",
@ -7836,7 +7837,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-json" name = "turbopack-json"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@ -7851,7 +7852,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-mdx" name = "turbopack-mdx"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"mdxjs", "mdxjs",
@ -7866,7 +7867,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-node" name = "turbopack-node"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-stream", "async-stream",
@ -7901,7 +7902,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-static" name = "turbopack-static"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"serde", "serde",
@ -7917,7 +7918,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-swc-utils" name = "turbopack-swc-utils"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"swc_core", "swc_core",
"turbo-tasks", "turbo-tasks",
@ -7928,7 +7929,7 @@ dependencies = [
[[package]] [[package]]
name = "turbopack-test-utils" name = "turbopack-test-utils"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230713.3#e3c68fac81352b24bfcfa1f14b56c0ef0a391917" source = "git+https://github.com/vercel/turbo.git?tag=turbopack-230716.2#8433a321545de30374b5374320625b92c663f5dc"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"once_cell", "once_cell",

View file

@ -44,11 +44,11 @@ swc_core = { version = "0.79.13" }
testing = { version = "0.33.20" } testing = { version = "0.33.20" }
# Turbo crates # Turbo crates
turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.3" } turbopack-binding = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230716.2" }
# [TODO]: need to refactor embed_directory! macro usages, as well as resolving turbo_tasks::function, macros.. # [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-230713.3" } turbo-tasks = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230716.2" }
# [TODO]: need to refactor embed_directory! macro usage in next-core # [TODO]: need to refactor embed_directory! macro usage in next-core
turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230713.3" } turbo-tasks-fs = { git = "https://github.com/vercel/turbo.git", tag = "turbopack-230716.2" }
# General Deps # General Deps

View file

@ -5,7 +5,9 @@ use next_swc::{
next_dynamic::next_dynamic, next_dynamic::next_dynamic,
next_ssg::next_ssg, next_ssg::next_ssg,
react_server_components::server_components, react_server_components::server_components,
server_actions::{self, server_actions}, server_actions::{
server_actions, {self},
},
}; };
use next_transform_font::{next_font_loaders, Config as FontLoaderConfig}; use next_transform_font::{next_font_loaders, Config as FontLoaderConfig};
use turbopack_binding::swc::{ use turbopack_binding::swc::{

View file

@ -9,7 +9,9 @@ use next_swc::{
react_remove_properties::remove_properties, react_remove_properties::remove_properties,
react_server_components::server_components, react_server_components::server_components,
remove_console::remove_console, remove_console::remove_console,
server_actions::{self, server_actions}, server_actions::{
server_actions, {self},
},
shake_exports::{shake_exports, Config as ShakeExportsConfig}, shake_exports::{shake_exports, Config as ShakeExportsConfig},
}; };
use next_transform_font::{next_font_loaders, Config as FontLoaderConfig}; use next_transform_font::{next_font_loaders, Config as FontLoaderConfig};

View file

@ -7,17 +7,17 @@ use napi::{
JsFunction, JsFunction,
}; };
use next_core::app_structure::{ use next_core::app_structure::{
find_app_dir, get_entrypoints as get_entrypoints_impl, Components, ComponentsVc, Entrypoint, find_app_dir, get_entrypoints as get_entrypoints_impl, Components, Entrypoint, Entrypoints,
EntrypointsVc, LoaderTree, LoaderTreeVc, MetadataWithAltItem, LoaderTree, MetadataWithAltItem,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbo_tasks::{unit, ReadRef, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{
tasks::{ tasks::{
debug::ValueDebugFormat, primitives::StringsVc, trace::TraceRawVcs, NothingVc, debug::ValueDebugFormat, trace::TraceRawVcs, TryJoinIterExt, TurboTasks, ValueToString,
TryJoinIterExt, TurboTasks, ValueToString,
}, },
tasks_fs::{DiskFileSystemVc, FileSystem, FileSystemPathVc, FileSystemVc}, tasks_fs::{DiskFileSystem, FileSystem, FileSystemPath},
tasks_memory::MemoryBackend, tasks_memory::MemoryBackend,
}, },
turbopack::core::PROJECT_FILESYSTEM_NAME, turbopack::core::PROJECT_FILESYSTEM_NAME,
@ -26,20 +26,19 @@ use turbopack_binding::{
use crate::register; use crate::register;
#[turbo_tasks::function] #[turbo_tasks::function]
async fn project_fs(project_dir: &str, watching: bool) -> Result<FileSystemVc> { async fn project_fs(project_dir: String, watching: bool) -> Result<Vc<Box<dyn FileSystem>>> {
let disk_fs = let disk_fs = DiskFileSystem::new(PROJECT_FILESYSTEM_NAME.to_string(), project_dir.to_string());
DiskFileSystemVc::new(PROJECT_FILESYSTEM_NAME.to_string(), project_dir.to_string());
if watching { if watching {
disk_fs.await?.start_watching_with_invalidation_reason()?; disk_fs.await?.start_watching_with_invalidation_reason()?;
} }
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }
#[turbo_tasks::value] #[turbo_tasks::value]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct LoaderTreeForJs { struct LoaderTreeForJs {
segment: String, segment: String,
parallel_routes: HashMap<String, LoaderTreeForJsReadRef>, parallel_routes: HashMap<String, ReadRef<LoaderTreeForJs>>,
#[turbo_tasks(trace_ignore)] #[turbo_tasks(trace_ignore)]
components: ComponentsForJs, components: ComponentsForJs,
} }
@ -47,8 +46,12 @@ struct LoaderTreeForJs {
#[derive(PartialEq, Eq, Serialize, Deserialize, ValueDebugFormat, TraceRawVcs)] #[derive(PartialEq, Eq, Serialize, Deserialize, ValueDebugFormat, TraceRawVcs)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
enum EntrypointForJs { enum EntrypointForJs {
AppPage { loader_tree: LoaderTreeForJsReadRef }, AppPage {
AppRoute { path: String }, loader_tree: ReadRef<LoaderTreeForJs>,
},
AppRoute {
path: String,
},
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
@ -56,9 +59,12 @@ enum EntrypointForJs {
struct EntrypointsForJs(HashMap<String, EntrypointForJs>); struct EntrypointsForJs(HashMap<String, EntrypointForJs>);
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
struct OptionEntrypointsForJs(Option<EntrypointsForJsVc>); struct OptionEntrypointsForJs(Option<Vc<EntrypointsForJs>>);
async fn fs_path_to_path(project_path: FileSystemPathVc, path: FileSystemPathVc) -> Result<String> { async fn fs_path_to_path(
project_path: Vc<FileSystemPath>,
path: Vc<FileSystemPath>,
) -> Result<String> {
match project_path.await?.get_path_to(&*path.await?) { match project_path.await?.get_path_to(&*path.await?) {
None => Err(anyhow!( None => Err(anyhow!(
"Path {} is not inside of the project path {}", "Path {} is not inside of the project path {}",
@ -119,8 +125,8 @@ enum MetadataForJsItem {
} }
async fn prepare_components_for_js( async fn prepare_components_for_js(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
components: ComponentsVc, components: Vc<Components>,
) -> Result<ComponentsForJs> { ) -> Result<ComponentsForJs> {
let Components { let Components {
page, page,
@ -136,8 +142,8 @@ async fn prepare_components_for_js(
let mut result = ComponentsForJs::default(); let mut result = ComponentsForJs::default();
async fn add( async fn add(
result: &mut Option<String>, result: &mut Option<String>,
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
value: &Option<FileSystemPathVc>, value: &Option<Vc<FileSystemPath>>,
) -> Result<()> { ) -> Result<()> {
if let Some(value) = value { if let Some(value) = value {
*result = Some(fs_path_to_path(project_path, *value).await?); *result = Some(fs_path_to_path(project_path, *value).await?);
@ -154,7 +160,7 @@ async fn prepare_components_for_js(
add(&mut result.route, project_path, route).await?; add(&mut result.route, project_path, route).await?;
async fn add_meta<'a>( async fn add_meta<'a>(
meta: &mut Vec<MetadataForJsItem>, meta: &mut Vec<MetadataForJsItem>,
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
value: impl Iterator<Item = &'a MetadataWithAltItem>, value: impl Iterator<Item = &'a MetadataWithAltItem>,
) -> Result<()> { ) -> Result<()> {
let mut value = value.peekable(); let mut value = value.peekable();
@ -198,9 +204,9 @@ async fn prepare_components_for_js(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn prepare_loader_tree_for_js( async fn prepare_loader_tree_for_js(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
loader_tree: LoaderTreeVc, loader_tree: Vc<LoaderTree>,
) -> Result<LoaderTreeForJsVc> { ) -> Result<Vc<LoaderTreeForJs>> {
let LoaderTree { let LoaderTree {
segment, segment,
parallel_routes, parallel_routes,
@ -229,9 +235,9 @@ async fn prepare_loader_tree_for_js(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn prepare_entrypoints_for_js( async fn prepare_entrypoints_for_js(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
entrypoints: EntrypointsVc, entrypoints: Vc<Entrypoints>,
) -> Result<EntrypointsForJsVc> { ) -> Result<Vc<EntrypointsForJs>> {
let entrypoints = entrypoints let entrypoints = entrypoints
.await? .await?
.iter() .iter()
@ -253,24 +259,24 @@ async fn prepare_entrypoints_for_js(
.await? .await?
.into_iter() .into_iter()
.collect(); .collect();
Ok(EntrypointsForJsVc::cell(entrypoints)) Ok(Vc::cell(entrypoints))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get_value( async fn get_value(
root_dir: &str, root_dir: String,
project_dir: &str, project_dir: String,
page_extensions: Vec<String>, page_extensions: Vec<String>,
watching: bool, watching: bool,
) -> Result<OptionEntrypointsForJsVc> { ) -> Result<Vc<OptionEntrypointsForJs>> {
let page_extensions = StringsVc::cell(page_extensions); let page_extensions = Vc::cell(page_extensions);
let fs = project_fs(root_dir, watching); let fs = project_fs(root_dir.clone(), watching);
let project_relative = project_dir.strip_prefix(root_dir).unwrap(); let project_relative = project_dir.strip_prefix(&root_dir).unwrap();
let project_relative = project_relative let project_relative = project_relative
.strip_prefix(MAIN_SEPARATOR) .strip_prefix(MAIN_SEPARATOR)
.unwrap_or(project_relative) .unwrap_or(project_relative)
.replace(MAIN_SEPARATOR, "/"); .replace(MAIN_SEPARATOR, "/");
let project_path = fs.root().join(&project_relative); let project_path = fs.root().join(project_relative);
let app_dir = find_app_dir(project_path); let app_dir = find_app_dir(project_path);
@ -283,7 +289,7 @@ async fn get_value(
None None
}; };
Ok(OptionEntrypointsForJsVc::cell(result)) Ok(Vc::cell(result))
} }
#[napi] #[napi]
@ -295,7 +301,7 @@ pub fn stream_entrypoints(
func: JsFunction, func: JsFunction,
) -> napi::Result<()> { ) -> napi::Result<()> {
register(); register();
let func: ThreadsafeFunction<Option<EntrypointsForJsReadRef>, ErrorStrategy::CalleeHandled> = let func: ThreadsafeFunction<Option<ReadRef<EntrypointsForJs>>, ErrorStrategy::CalleeHandled> =
func.create_threadsafe_function(0, |ctx| { func.create_threadsafe_function(0, |ctx| {
let value = ctx.value; let value = ctx.value;
let value = serde_json::to_value(value)?; let value = serde_json::to_value(value)?;
@ -305,16 +311,14 @@ pub fn stream_entrypoints(
let project_dir = Arc::new(project_dir); let project_dir = Arc::new(project_dir);
let page_extensions = Arc::new(page_extensions); let page_extensions = Arc::new(page_extensions);
turbo_tasks.spawn_root_task(move || { turbo_tasks.spawn_root_task(move || {
let func: ThreadsafeFunction< let func: ThreadsafeFunction<Option<ReadRef<EntrypointsForJs>>> = func.clone();
Option<turbo_tasks::ReadRef<EntrypointsForJs, HashMap<String, EntrypointForJs>>>,
> = func.clone();
let project_dir = project_dir.clone(); let project_dir = project_dir.clone();
let root_dir = root_dir.clone(); let root_dir = root_dir.clone();
let page_extensions: Arc<Vec<String>> = page_extensions.clone(); let page_extensions: Arc<Vec<String>> = page_extensions.clone();
Box::pin(async move { Box::pin(async move {
if let Some(entrypoints) = &*get_value( if let Some(entrypoints) = &*get_value(
&root_dir, (*root_dir).clone(),
&project_dir, (*project_dir).clone(),
page_extensions.iter().map(|s| s.to_string()).collect(), page_extensions.iter().map(|s| s.to_string()).collect(),
true, true,
) )
@ -328,7 +332,7 @@ pub fn stream_entrypoints(
func.call(Ok(None), ThreadsafeFunctionCallMode::NonBlocking); func.call(Ok(None), ThreadsafeFunctionCallMode::NonBlocking);
} }
Ok(NothingVc::new().into()) Ok(unit().node)
}) })
}); });
Ok(()) Ok(())
@ -345,8 +349,8 @@ pub async fn get_entrypoints(
let result = turbo_tasks let result = turbo_tasks
.run_once(async move { .run_once(async move {
let value = if let Some(entrypoints) = &*get_value( let value = if let Some(entrypoints) = &*get_value(
&root_dir, root_dir,
&project_dir, project_dir,
page_extensions.iter().map(|s| s.to_string()).collect(), page_extensions.iter().map(|s| s.to_string()).collect(),
false, false,
) )

View file

@ -28,6 +28,8 @@ DEALINGS IN THE SOFTWARE.
#![recursion_limit = "2048"] #![recursion_limit = "2048"]
//#![deny(clippy::all)] //#![deny(clippy::all)]
#![feature(arbitrary_self_types)]
#![feature(async_fn_in_trait)]
#[macro_use] #[macro_use]
extern crate napi_derive; extern crate napi_derive;

View file

@ -1,5 +1,8 @@
use std::ops::Deref;
use napi::{bindgen_prelude::External, JsFunction}; use napi::{bindgen_prelude::External, JsFunction};
use next_api::route::{Endpoint, EndpointVc, WrittenEndpoint}; use next_api::route::{Endpoint, WrittenEndpoint};
use turbo_tasks::Vc;
use turbopack_binding::turbopack::core::error::PrettyPrintError; use turbopack_binding::turbopack::core::error::PrettyPrintError;
use super::utils::{subscribe, NapiDiagnostic, NapiIssue, RootTask, VcArc}; use super::utils::{subscribe, NapiDiagnostic, NapiIssue, RootTask, VcArc};
@ -23,12 +26,28 @@ impl From<&WrittenEndpoint> for NapiWrittenEndpoint {
} }
} }
// NOTE(alexkirsz) We go through an extra layer of indirection here because of
// two factors:
// 1. rustc currently has a bug where using a dyn trait as a type argument to
// some async functions (in this case `endpoint_write_to_disk`) can cause
// higher-ranked lifetime errors. See https://github.com/rust-lang/rust/issues/102211
// 2. the type_complexity clippy lint.
pub struct ExternalEndpoint(pub VcArc<Vc<Box<dyn Endpoint>>>);
impl Deref for ExternalEndpoint {
type Target = VcArc<Vc<Box<dyn Endpoint>>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[napi] #[napi]
pub async fn endpoint_write_to_disk( pub async fn endpoint_write_to_disk(
#[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<VcArc<EndpointVc>>, #[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<ExternalEndpoint>,
) -> napi::Result<NapiWrittenEndpoint> { ) -> napi::Result<NapiWrittenEndpoint> {
let turbo_tasks = endpoint.turbo_tasks().clone(); let turbo_tasks = endpoint.turbo_tasks().clone();
let endpoint = **endpoint; let endpoint = ***endpoint;
let written = turbo_tasks let written = turbo_tasks
.run_once(async move { endpoint.write_to_disk().strongly_consistent().await }) .run_once(async move { endpoint.write_to_disk().strongly_consistent().await })
.await .await
@ -39,7 +58,9 @@ pub async fn endpoint_write_to_disk(
#[napi(ts_return_type = "{ __napiType: \"RootTask\" }")] #[napi(ts_return_type = "{ __napiType: \"RootTask\" }")]
pub fn endpoint_changed_subscribe( pub fn endpoint_changed_subscribe(
#[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<VcArc<EndpointVc>>, #[napi(ts_arg_type = "{ __napiType: \"Endpoint\" }")] endpoint: External<
VcArc<Vc<Box<dyn Endpoint>>>,
>,
func: JsFunction, func: JsFunction,
) -> napi::Result<External<RootTask>> { ) -> napi::Result<External<RootTask>> {
let turbo_tasks = endpoint.turbo_tasks().clone(); let turbo_tasks = endpoint.turbo_tasks().clone();

View file

@ -3,15 +3,18 @@ use std::sync::Arc;
use anyhow::Result; use anyhow::Result;
use napi::{bindgen_prelude::External, JsFunction}; use napi::{bindgen_prelude::External, JsFunction};
use next_api::{ use next_api::{
project::{Middleware, ProjectOptions, ProjectVc}, project::{Middleware, Project, ProjectOptions},
route::{EndpointVc, Route}, route::{Endpoint, Route},
}; };
use turbo_tasks::TurboTasks; use turbo_tasks::{TurboTasks, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_memory::MemoryBackend, turbopack::core::error::PrettyPrintError, turbo::tasks_memory::MemoryBackend, turbopack::core::error::PrettyPrintError,
}; };
use super::utils::{serde_enum_to_string, subscribe, NapiDiagnostic, NapiIssue, RootTask, VcArc}; use super::{
endpoint::ExternalEndpoint,
utils::{serde_enum_to_string, subscribe, NapiDiagnostic, NapiIssue, RootTask, VcArc},
};
use crate::register; use crate::register;
#[napi(object)] #[napi(object)]
@ -46,7 +49,9 @@ impl From<NapiProjectOptions> for ProjectOptions {
} }
#[napi(ts_return_type = "{ __napiType: \"Project\" }")] #[napi(ts_return_type = "{ __napiType: \"Project\" }")]
pub async fn project_new(options: NapiProjectOptions) -> napi::Result<External<VcArc<ProjectVc>>> { pub async fn project_new(
options: NapiProjectOptions,
) -> napi::Result<External<VcArc<Vc<Project>>>> {
register(); register();
let turbo_tasks = TurboTasks::new(MemoryBackend::new( let turbo_tasks = TurboTasks::new(MemoryBackend::new(
options options
@ -56,7 +61,7 @@ pub async fn project_new(options: NapiProjectOptions) -> napi::Result<External<V
)); ));
let options = options.into(); let options = options.into();
let project = turbo_tasks let project = turbo_tasks
.run_once(async move { ProjectVc::new(options).resolve().await }) .run_once(async move { Project::new(options).resolve().await })
.await .await
.map_err(|e| napi::Error::from_reason(PrettyPrintError(&e).to_string()))?; .map_err(|e| napi::Error::from_reason(PrettyPrintError(&e).to_string()))?;
Ok(External::new_with_size_hint( Ok(External::new_with_size_hint(
@ -75,10 +80,10 @@ struct NapiRoute {
pub r#type: &'static str, pub r#type: &'static str,
// Different representations of the endpoint // Different representations of the endpoint
pub endpoint: Option<External<VcArc<EndpointVc>>>, pub endpoint: Option<External<ExternalEndpoint>>,
pub html_endpoint: Option<External<VcArc<EndpointVc>>>, pub html_endpoint: Option<External<ExternalEndpoint>>,
pub rsc_endpoint: Option<External<VcArc<EndpointVc>>>, pub rsc_endpoint: Option<External<ExternalEndpoint>>,
pub data_endpoint: Option<External<VcArc<EndpointVc>>>, pub data_endpoint: Option<External<ExternalEndpoint>>,
} }
impl NapiRoute { impl NapiRoute {
@ -87,8 +92,12 @@ impl NapiRoute {
value: Route, value: Route,
turbo_tasks: &Arc<TurboTasks<MemoryBackend>>, turbo_tasks: &Arc<TurboTasks<MemoryBackend>>,
) -> Self { ) -> Self {
let convert_endpoint = let convert_endpoint = |endpoint: Vc<Box<dyn Endpoint>>| {
|endpoint: EndpointVc| Some(External::new(VcArc::new(turbo_tasks.clone(), endpoint))); Some(External::new(ExternalEndpoint(VcArc::new(
turbo_tasks.clone(),
endpoint,
))))
};
match value { match value {
Route::Page { Route::Page {
html_endpoint, html_endpoint,
@ -133,7 +142,7 @@ impl NapiRoute {
#[napi(object)] #[napi(object)]
struct NapiMiddleware { struct NapiMiddleware {
pub endpoint: External<VcArc<EndpointVc>>, pub endpoint: External<VcArc<Vc<Box<dyn Endpoint>>>>,
pub runtime: String, pub runtime: String,
pub matcher: Option<Vec<String>>, pub matcher: Option<Vec<String>>,
} }
@ -161,7 +170,7 @@ struct NapiEntrypoints {
#[napi(ts_return_type = "{ __napiType: \"RootTask\" }")] #[napi(ts_return_type = "{ __napiType: \"RootTask\" }")]
pub fn project_entrypoints_subscribe( pub fn project_entrypoints_subscribe(
#[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External<VcArc<ProjectVc>>, #[napi(ts_arg_type = "{ __napiType: \"Project\" }")] project: External<VcArc<Vc<Project>>>,
func: JsFunction, func: JsFunction,
) -> napi::Result<External<RootTask>> { ) -> napi::Result<External<RootTask>> {
let turbo_tasks = project.turbo_tasks().clone(); let turbo_tasks = project.turbo_tasks().clone();

View file

@ -7,7 +7,7 @@ use napi::{
JsFunction, JsObject, NapiRaw, NapiValue, Status, JsFunction, JsObject, NapiRaw, NapiValue, Status,
}; };
use serde::Serialize; use serde::Serialize;
use turbo_tasks::{NothingVc, TaskId, TurboTasks}; use turbo_tasks::{unit, TaskId, TurboTasks};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_memory::MemoryBackend, turbopack::core::error::PrettyPrintError, turbo::tasks_memory::MemoryBackend, turbopack::core::error::PrettyPrintError,
}; };
@ -127,7 +127,7 @@ pub fn subscribe<T: 'static + Send + Sync, F: Future<Output = Result<T>> + Send,
eprintln!("{}", error); eprintln!("{}", error);
return Err(error); return Err(error);
} }
Ok(NothingVc::new().into()) Ok(unit().node)
}) })
}); });
Ok(External::new(RootTask { Ok(External::new(RootTask {

View file

@ -31,7 +31,13 @@ use std::{cell::RefCell, env, path::PathBuf};
use anyhow::anyhow; use anyhow::anyhow;
use napi::bindgen_prelude::{External, Status}; use napi::bindgen_prelude::{External, Status};
#[cfg(feature = "crash-report")] #[cfg(feature = "crash-report")]
use sentry::{init, types::Dsn, ClientInitGuard, ClientOptions}; use sentry::init;
#[cfg(feature = "crash-report")]
use sentry::types::Dsn;
#[cfg(feature = "crash-report")]
use sentry::ClientInitGuard;
#[cfg(feature = "crash-report")]
use sentry::ClientOptions;
use tracing_chrome::{ChromeLayerBuilder, FlushGuard}; use tracing_chrome::{ChromeLayerBuilder, FlushGuard};
use tracing_subscriber::{filter, prelude::*, util::SubscriberInitExt, Layer}; use tracing_subscriber::{filter, prelude::*, util::SubscriberInitExt, Layer};

View file

@ -1,26 +1,28 @@
use next_core::app_structure::Entrypoint; use next_core::app_structure::Entrypoint;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbo_tasks::{trace::TraceRawVcs, CompletionVc}; use turbo_tasks::{trace::TraceRawVcs, Completion, Vc};
use crate::route::{Endpoint, EndpointVc, Route, RouteVc, WrittenEndpointVc}; use crate::route::{Endpoint, Route, WrittenEndpoint};
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn app_entry_point_to_route(entrypoint: Entrypoint) -> RouteVc { pub async fn app_entry_point_to_route(entrypoint: Entrypoint) -> Vc<Route> {
match entrypoint { match entrypoint {
Entrypoint::AppPage { .. } => Route::AppPage { Entrypoint::AppPage { .. } => Route::AppPage {
html_endpoint: AppPageEndpoint { html_endpoint: Vc::upcast(
ty: AppPageEndpointType::Html, AppPageEndpoint {
} ty: AppPageEndpointType::Html,
.cell() }
.into(), .cell(),
rsc_endpoint: AppPageEndpoint { ),
ty: AppPageEndpointType::Rsc, rsc_endpoint: Vc::upcast(
} AppPageEndpoint {
.cell() ty: AppPageEndpointType::Rsc,
.into(), }
.cell(),
),
}, },
Entrypoint::AppRoute { .. } => Route::AppRoute { Entrypoint::AppRoute { .. } => Route::AppRoute {
endpoint: AppRouteEndpoint.cell().into(), endpoint: Vc::upcast(AppRouteEndpoint.cell()),
}, },
} }
.cell() .cell()
@ -40,12 +42,12 @@ struct AppPageEndpoint {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Endpoint for AppPageEndpoint { impl Endpoint for AppPageEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
fn write_to_disk(&self) -> WrittenEndpointVc { fn write_to_disk(&self) -> Vc<WrittenEndpoint> {
todo!() todo!()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn changed(&self) -> CompletionVc { fn changed(&self) -> Vc<Completion> {
todo!() todo!()
} }
} }
@ -56,12 +58,12 @@ struct AppRouteEndpoint;
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Endpoint for AppRouteEndpoint { impl Endpoint for AppRouteEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
fn write_to_disk(&self) -> WrittenEndpointVc { fn write_to_disk(&self) -> Vc<WrittenEndpoint> {
todo!() todo!()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn changed(&self) -> CompletionVc { fn changed(&self) -> Vc<Completion> {
todo!() todo!()
} }
} }

View file

@ -1,5 +1,6 @@
#![feature(future_join)] #![feature(future_join)]
#![feature(min_specialization)] #![feature(arbitrary_self_types)]
#![feature(async_fn_in_trait)]
mod app; mod app;
mod pages; mod pages;

View file

@ -2,45 +2,42 @@ use anyhow::{bail, Context, Result};
use indexmap::IndexMap; use indexmap::IndexMap;
use next_core::{ use next_core::{
create_page_loader_entry_module, emit_all_assets, get_asset_path_from_pathname, create_page_loader_entry_module, emit_all_assets, get_asset_path_from_pathname,
pages_structure::{ pages_structure::{PagesDirectoryStructure, PagesStructure, PagesStructureItem},
PagesDirectoryStructure, PagesDirectoryStructureVc, PagesStructure, PagesStructureItem,
PagesStructureVc,
},
}; };
use turbo_tasks::{primitives::StringVc, CompletionVc, CompletionsVc, Value}; use turbo_tasks::{Completion, Completions, Value, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{ core::{
asset::Asset, asset::Asset,
changed::{any_content_changed, any_content_changed_of_output_assets}, changed::{any_content_changed, any_content_changed_of_output_assets},
chunk::{ChunkableModule, ChunkingContext}, chunk::{ChunkableModule, ChunkingContext},
context::AssetContext, context::AssetContext,
file_source::FileSourceVc, file_source::FileSource,
output::{OutputAssetVc, OutputAssetsVc}, output::{OutputAsset, OutputAssets},
reference_type::{EntryReferenceSubType, ReferenceType}, reference_type::{EntryReferenceSubType, ReferenceType},
source::SourceVc, source::Source,
}, },
ecmascript::EcmascriptModuleAssetVc, ecmascript::EcmascriptModuleAsset,
}, },
}; };
use crate::{ use crate::{
project::ProjectVc, project::Project,
route::{Endpoint, EndpointVc, Route, RoutesVc, WrittenEndpoint, WrittenEndpointVc}, route::{Endpoint, Route, Routes, WrittenEndpoint},
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_pages_routes( pub async fn get_pages_routes(
project: ProjectVc, project: Vc<Project>,
page_structure: PagesStructureVc, page_structure: Vc<PagesStructure>,
) -> Result<RoutesVc> { ) -> Result<Vc<Routes>> {
let PagesStructure { api, pages, .. } = *page_structure.await?; let PagesStructure { api, pages, .. } = *page_structure.await?;
let mut routes = IndexMap::new(); let mut routes = IndexMap::new();
async fn add_dir_to_routes( async fn add_dir_to_routes(
routes: &mut IndexMap<String, Route>, routes: &mut IndexMap<String, Route>,
dir: PagesDirectoryStructureVc, dir: Vc<PagesDirectoryStructure>,
make_route: impl Fn(StringVc, StringVc, FileSystemPathVc) -> Route, make_route: impl Fn(Vc<String>, Vc<String>, Vc<FileSystemPath>) -> Route,
) -> Result<()> { ) -> Result<()> {
let mut queue = vec![dir]; let mut queue = vec![dir];
while let Some(dir) = queue.pop() { while let Some(dir) = queue.pop() {
@ -57,8 +54,8 @@ pub async fn get_pages_routes(
original_path, original_path,
} = *item.await?; } = *item.await?;
let pathname = format!("/{}", next_router_path.await?.path); let pathname = format!("/{}", next_router_path.await?.path);
let pathname_vc = StringVc::cell(pathname.clone()); let pathname_vc = Vc::cell(pathname.clone());
let original_name = StringVc::cell(format!("/{}", original_path.await?.path)); let original_name = Vc::cell(format!("/{}", original_path.await?.path));
let route = make_route(pathname_vc, original_name, project_path); let route = make_route(pathname_vc, original_name, project_path);
routes.insert(pathname, route); routes.insert(pathname, route);
} }
@ -71,7 +68,7 @@ pub async fn get_pages_routes(
if let Some(api) = api { if let Some(api) = api {
add_dir_to_routes(&mut routes, api, |pathname, original_name, path| { add_dir_to_routes(&mut routes, api, |pathname, original_name, path| {
Route::PageApi { Route::PageApi {
endpoint: ApiEndpointVc::new(project, pathname, original_name, path).into(), endpoint: Vc::upcast(ApiEndpoint::new(project, pathname, original_name, path)),
} }
}) })
.await?; .await?;
@ -79,34 +76,42 @@ pub async fn get_pages_routes(
if let Some(page) = pages { if let Some(page) = pages {
add_dir_to_routes(&mut routes, page, |pathname, original_name, path| { add_dir_to_routes(&mut routes, page, |pathname, original_name, path| {
Route::Page { Route::Page {
html_endpoint: PageHtmlEndpointVc::new(project, pathname, original_name, path) html_endpoint: Vc::upcast(PageHtmlEndpoint::new(
.into(), project,
data_endpoint: PageDataEndpointVc::new(project, pathname, original_name, path) pathname,
.into(), original_name,
path,
)),
data_endpoint: Vc::upcast(PageDataEndpoint::new(
project,
pathname,
original_name,
path,
)),
} }
}) })
.await?; .await?;
} }
Ok(RoutesVc::cell(routes)) Ok(Vc::cell(routes))
} }
#[turbo_tasks::value] #[turbo_tasks::value]
struct PageHtmlEndpoint { struct PageHtmlEndpoint {
project: ProjectVc, project: Vc<Project>,
pathname: StringVc, pathname: Vc<String>,
original_name: StringVc, original_name: Vc<String>,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl PageHtmlEndpointVc { impl PageHtmlEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
fn new( fn new(
project: ProjectVc, project: Vc<Project>,
pathname: StringVc, pathname: Vc<String>,
original_name: StringVc, original_name: Vc<String>,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
) -> Self { ) -> Vc<Self> {
PageHtmlEndpoint { PageHtmlEndpoint {
project, project,
pathname, pathname,
@ -117,13 +122,13 @@ impl PageHtmlEndpointVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn source(self) -> Result<SourceVc> { async fn source(self: Vc<Self>) -> Result<Vc<Box<dyn Source>>> {
let this = self.await?; let this = self.await?;
Ok(FileSourceVc::new(this.path).into()) Ok(Vc::upcast(FileSource::new(this.path)))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn client_chunks(self) -> Result<OutputAssetsVc> { async fn client_chunks(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
let this = self.await?; let this = self.await?;
let client_module = create_page_loader_entry_module( let client_module = create_page_loader_entry_module(
@ -132,27 +137,28 @@ impl PageHtmlEndpointVc {
this.pathname, this.pathname,
); );
let Some(client_module) = EcmascriptModuleAssetVc::resolve_from(client_module).await? let Some(client_module) =
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(client_module).await?
else { else {
bail!("expected an ECMAScript module asset"); bail!("expected an ECMAScript module asset");
}; };
let client_chunking_context = this.project.client_chunking_context(); let client_chunking_context = this.project.client_chunking_context();
let client_entry_chunk = client_module.as_root_chunk(client_chunking_context.into()); let client_entry_chunk = client_module.as_root_chunk(Vc::upcast(client_chunking_context));
let client_chunks = client_chunking_context.evaluated_chunk_group( let client_chunks = client_chunking_context.evaluated_chunk_group(
client_entry_chunk, client_entry_chunk,
this.project this.project
.pages_client_runtime_entries() .pages_client_runtime_entries()
.with_entry(client_module.into()), .with_entry(Vc::upcast(client_module)),
); );
Ok(client_chunks) Ok(client_chunks)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn ssr_chunk(self) -> Result<OutputAssetVc> { async fn ssr_chunk(self: Vc<Self>) -> Result<Vc<Box<dyn OutputAsset>>> {
let this = self.await?; let this = self.await?;
let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)); let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page));
@ -161,17 +167,19 @@ impl PageHtmlEndpointVc {
.pages_ssr_module_context() .pages_ssr_module_context()
.process(self.source(), reference_type.clone()); .process(self.source(), reference_type.clone());
let Some(ssr_module) = EcmascriptModuleAssetVc::resolve_from(ssr_module).await? else { let Some(ssr_module) =
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(ssr_module).await?
else {
bail!("expected an ECMAScript module asset"); bail!("expected an ECMAScript module asset");
}; };
let asset_path = get_asset_path_from_pathname(&this.pathname.await?, ".js"); let asset_path = get_asset_path_from_pathname(&this.pathname.await?, ".js");
let ssr_entry_chunk_path_string = format!("server/pages{asset_path}"); let ssr_entry_chunk_path_string = format!("server/pages{asset_path}");
let ssr_entry_chunk_path = this.project.node_root().join(&ssr_entry_chunk_path_string); let ssr_entry_chunk_path = this.project.node_root().join(ssr_entry_chunk_path_string);
let ssr_entry_chunk = this.project.ssr_chunking_context().entry_chunk( let ssr_entry_chunk = this.project.ssr_chunking_context().entry_chunk(
ssr_entry_chunk_path, ssr_entry_chunk_path,
ssr_module.into(), Vc::upcast(ssr_module),
this.project.pages_ssr_runtime_entries(), this.project.pages_ssr_runtime_entries(),
); );
@ -182,19 +190,19 @@ impl PageHtmlEndpointVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Endpoint for PageHtmlEndpoint { impl Endpoint for PageHtmlEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn write_to_disk(self_vc: PageHtmlEndpointVc) -> Result<WrittenEndpointVc> { async fn write_to_disk(self: Vc<Self>) -> Result<Vc<WrittenEndpoint>> {
let this = self_vc.await?; let this = self.await?;
let ssr_chunk = self_vc.ssr_chunk(); let ssr_chunk = self.ssr_chunk();
let ssr_emit = emit_all_assets( let ssr_emit = emit_all_assets(
OutputAssetsVc::cell(vec![ssr_chunk]), Vc::cell(vec![ssr_chunk]),
this.project.node_root(), this.project.node_root(),
this.project.client_root().join("_next"), this.project.client_root().join("_next".to_string()),
this.project.node_root(), this.project.node_root(),
); );
let client_emit = emit_all_assets( let client_emit = emit_all_assets(
self_vc.client_chunks(), self.client_chunks(),
this.project.node_root(), this.project.node_root(),
this.project.client_root().join("_next"), this.project.client_root().join("_next".to_string()),
this.project.node_root(), this.project.node_root(),
); );
@ -215,32 +223,32 @@ impl Endpoint for PageHtmlEndpoint {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn changed(self_vc: PageHtmlEndpointVc) -> CompletionVc { fn changed(self: Vc<Self>) -> Vc<Completion> {
let ssr_chunk = self_vc.ssr_chunk(); let ssr_chunk = self.ssr_chunk();
CompletionsVc::all(vec![ Completions::all(vec![
any_content_changed(ssr_chunk.into()), any_content_changed(Vc::upcast(ssr_chunk)),
any_content_changed_of_output_assets(self_vc.client_chunks()), any_content_changed_of_output_assets(self.client_chunks()),
]) ])
} }
} }
#[turbo_tasks::value] #[turbo_tasks::value]
struct PageDataEndpoint { struct PageDataEndpoint {
project: ProjectVc, project: Vc<Project>,
pathname: StringVc, pathname: Vc<String>,
original_name: StringVc, original_name: Vc<String>,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl PageDataEndpointVc { impl PageDataEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
fn new( fn new(
project: ProjectVc, project: Vc<Project>,
pathname: StringVc, pathname: Vc<String>,
original_name: StringVc, original_name: Vc<String>,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
) -> Self { ) -> Vc<Self> {
PageDataEndpoint { PageDataEndpoint {
project, project,
pathname, pathname,
@ -251,13 +259,13 @@ impl PageDataEndpointVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn source(self) -> Result<SourceVc> { async fn source(self: Vc<Self>) -> Result<Vc<Box<dyn Source>>> {
let this = self.await?; let this = self.await?;
Ok(FileSourceVc::new(this.path).into()) Ok(Vc::upcast(FileSource::new(this.path)))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn ssr_data_chunk(self) -> Result<OutputAssetVc> { async fn ssr_data_chunk(self: Vc<Self>) -> Result<Vc<Box<dyn OutputAsset>>> {
let this = self.await?; let this = self.await?;
let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)); let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page));
@ -266,7 +274,8 @@ impl PageDataEndpointVc {
.pages_ssr_data_module_context() .pages_ssr_data_module_context()
.process(self.source(), reference_type.clone()); .process(self.source(), reference_type.clone());
let Some(ssr_data_module) = EcmascriptModuleAssetVc::resolve_from(ssr_data_module).await? let Some(ssr_data_module) =
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(ssr_data_module).await?
else { else {
bail!("expected an ECMAScript module asset"); bail!("expected an ECMAScript module asset");
}; };
@ -277,10 +286,10 @@ impl PageDataEndpointVc {
let ssr_data_entry_chunk_path = this let ssr_data_entry_chunk_path = this
.project .project
.node_root() .node_root()
.join(&ssr_data_entry_chunk_path_string); .join(ssr_data_entry_chunk_path_string);
let ssr_data_entry_chunk = this.project.ssr_data_chunking_context().entry_chunk( let ssr_data_entry_chunk = this.project.ssr_data_chunking_context().entry_chunk(
ssr_data_entry_chunk_path, ssr_data_entry_chunk_path,
ssr_data_module.into(), Vc::upcast(ssr_data_module),
this.project.pages_ssr_runtime_entries(), this.project.pages_ssr_runtime_entries(),
); );
@ -291,13 +300,13 @@ impl PageDataEndpointVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Endpoint for PageDataEndpoint { impl Endpoint for PageDataEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn write_to_disk(self_vc: PageDataEndpointVc) -> Result<WrittenEndpointVc> { async fn write_to_disk(self: Vc<Self>) -> Result<Vc<WrittenEndpoint>> {
let this = self_vc.await?; let this = self.await?;
let ssr_data_chunk = self_vc.ssr_data_chunk(); let ssr_data_chunk = self.ssr_data_chunk();
emit_all_assets( emit_all_assets(
OutputAssetsVc::cell(vec![ssr_data_chunk]), Vc::cell(vec![ssr_data_chunk]),
this.project.node_root(), this.project.node_root(),
this.project.client_root().join("_next"), this.project.client_root().join("_next".to_string()),
this.project.node_root(), this.project.node_root(),
) )
.await?; .await?;
@ -316,29 +325,29 @@ impl Endpoint for PageDataEndpoint {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn changed(self_vc: PageDataEndpointVc) -> Result<CompletionVc> { async fn changed(self: Vc<Self>) -> Result<Vc<Completion>> {
let ssr_data_chunk = self_vc.ssr_data_chunk(); let ssr_data_chunk = self.ssr_data_chunk();
Ok(any_content_changed(ssr_data_chunk.into())) Ok(any_content_changed(Vc::upcast(ssr_data_chunk)))
} }
} }
#[turbo_tasks::value] #[turbo_tasks::value]
struct ApiEndpoint { struct ApiEndpoint {
project: ProjectVc, project: Vc<Project>,
pathname: StringVc, pathname: Vc<String>,
original_name: StringVc, original_name: Vc<String>,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ApiEndpointVc { impl ApiEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
fn new( fn new(
project: ProjectVc, project: Vc<Project>,
pathname: StringVc, pathname: Vc<String>,
original_name: StringVc, original_name: Vc<String>,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
) -> Self { ) -> Vc<Self> {
ApiEndpoint { ApiEndpoint {
project, project,
pathname, pathname,
@ -352,12 +361,12 @@ impl ApiEndpointVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Endpoint for ApiEndpoint { impl Endpoint for ApiEndpoint {
#[turbo_tasks::function] #[turbo_tasks::function]
fn write_to_disk(&self) -> WrittenEndpointVc { fn write_to_disk(&self) -> Vc<WrittenEndpoint> {
todo!() todo!()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn changed(&self) -> CompletionVc { fn changed(&self) -> Vc<Completion> {
todo!() todo!()
} }
} }

View file

@ -10,47 +10,45 @@ use next_core::{
get_client_module_options_context, get_client_resolve_options_context, get_client_module_options_context, get_client_resolve_options_context,
get_client_runtime_entries, ClientContextType, get_client_runtime_entries, ClientContextType,
}, },
next_config::NextConfigVc, next_config::NextConfig,
next_dynamic::NextDynamicTransitionVc, next_dynamic::NextDynamicTransition,
next_server::{ next_server::{
get_server_chunking_context, get_server_compile_time_info, get_server_chunking_context, get_server_compile_time_info,
get_server_module_options_context, get_server_resolve_options_context, get_server_module_options_context, get_server_resolve_options_context,
get_server_runtime_entries, ServerContextType, get_server_runtime_entries, ServerContextType,
}, },
pages_structure::{find_pages_structure, PagesStructureVc}, pages_structure::{find_pages_structure, PagesStructure},
util::NextSourceConfig, util::NextSourceConfig,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbo_tasks::{ use turbo_tasks::{
debug::ValueDebugFormat, trace::TraceRawVcs, NothingVc, TaskInput, TransientValue, debug::ValueDebugFormat, trace::TraceRawVcs, unit, TaskInput, TransientValue, TryJoinIterExt,
TryJoinIterExt, Value, Value, Vc,
}; };
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{
tasks_env::ProcessEnvVc, tasks_env::ProcessEnv,
tasks_fs::{ tasks_fs::{DiskFileSystem, FileSystem, FileSystemPath, VirtualFileSystem},
DiskFileSystemVc, FileSystem, FileSystemPathVc, FileSystemVc, VirtualFileSystemVc,
},
}, },
turbopack::{ turbopack::{
build::BuildChunkingContextVc, build::BuildChunkingContext,
core::{ core::{
chunk::{ChunkingContext, EvaluatableAssetsVc}, chunk::{ChunkingContext, EvaluatableAssets},
compile_time_info::CompileTimeInfoVc, compile_time_info::CompileTimeInfo,
context::AssetContextVc, context::AssetContext,
environment::ServerAddrVc, environment::ServerAddr,
PROJECT_FILESYSTEM_NAME, PROJECT_FILESYSTEM_NAME,
}, },
dev::DevChunkingContextVc, dev::DevChunkingContext,
ecmascript::chunk::EcmascriptChunkingContextVc, ecmascript::chunk::EcmascriptChunkingContext,
env::dotenv::load_env, env::dotenv::load_env,
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::{ turbopack::{
evaluate_context::node_build_environment, evaluate_context::node_build_environment,
module_options::ModuleOptionsContextVc, module_options::ModuleOptionsContext,
resolve_options_context::ResolveOptionsContextVc, resolve_options_context::ResolveOptionsContext,
transition::{ContextTransitionVc, TransitionsByNameVc}, transition::{ContextTransition, TransitionsByName},
ModuleAssetContextVc, ModuleAssetContext,
}, },
}, },
}; };
@ -58,7 +56,7 @@ use turbopack_binding::{
use crate::{ use crate::{
app::app_entry_point_to_route, app::app_entry_point_to_route,
pages::get_pages_routes, pages::get_pages_routes,
route::{EndpointVc, Route}, route::{Endpoint, Route},
}; };
#[derive(Debug, Serialize, Deserialize, Clone, TaskInput)] #[derive(Debug, Serialize, Deserialize, Clone, TaskInput)]
@ -83,7 +81,7 @@ pub struct ProjectOptions {
#[derive(Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, ValueDebugFormat)] #[derive(Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, ValueDebugFormat)]
pub struct Middleware { pub struct Middleware {
pub endpoint: EndpointVc, pub endpoint: Vc<Box<dyn Endpoint>>,
pub config: NextSourceConfig, pub config: NextSourceConfig,
} }
@ -106,7 +104,7 @@ pub struct Project {
watch: bool, watch: bool,
/// Next config. /// Next config.
next_config: NextConfigVc, next_config: Vc<NextConfig>,
browserslist_query: String, browserslist_query: String,
@ -114,10 +112,10 @@ pub struct Project {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ProjectVc { impl Project {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn new(options: ProjectOptions) -> Result<Self> { pub async fn new(options: ProjectOptions) -> Result<Vc<Self>> {
let next_config = NextConfigVc::from_string(options.next_config); let next_config = NextConfig::from_string(options.next_config);
Ok(Project { Ok(Project {
root_path: options.root_path, root_path: options.root_path,
project_path: options.project_path, project_path: options.project_path,
@ -132,49 +130,49 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn project_fs(self) -> Result<FileSystemVc> { async fn project_fs(self: Vc<Self>) -> Result<Vc<Box<dyn FileSystem>>> {
let this = self.await?; let this = self.await?;
let disk_fs = DiskFileSystemVc::new( let disk_fs = DiskFileSystem::new(
PROJECT_FILESYSTEM_NAME.to_string(), PROJECT_FILESYSTEM_NAME.to_string(),
this.root_path.to_string(), this.root_path.to_string(),
); );
if this.watch { if this.watch {
disk_fs.await?.start_watching_with_invalidation_reason()?; disk_fs.await?.start_watching_with_invalidation_reason()?;
} }
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn client_fs(self) -> Result<FileSystemVc> { async fn client_fs(self: Vc<Self>) -> Result<Vc<Box<dyn FileSystem>>> {
let virtual_fs = VirtualFileSystemVc::new(); let virtual_fs = VirtualFileSystem::new();
Ok(virtual_fs.into()) Ok(Vc::upcast(virtual_fs))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn node_fs(self) -> Result<FileSystemVc> { async fn node_fs(self: Vc<Self>) -> Result<Vc<Box<dyn FileSystem>>> {
let this = self.await?; let this = self.await?;
let disk_fs = DiskFileSystemVc::new("node".to_string(), this.project_path.clone()); let disk_fs = DiskFileSystem::new("node".to_string(), this.project_path.clone());
disk_fs.await?.start_watching_with_invalidation_reason()?; disk_fs.await?.start_watching_with_invalidation_reason()?;
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) fn node_root(self) -> FileSystemPathVc { pub(super) fn node_root(self: Vc<Self>) -> Vc<FileSystemPath> {
self.node_fs().root().join(".next") self.node_fs().root().join(".next".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) fn client_root(self) -> FileSystemPathVc { pub(super) fn client_root(self: Vc<Self>) -> Vc<FileSystemPath> {
self.client_fs().root() self.client_fs().root()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn project_root_path(self) -> FileSystemPathVc { fn project_root_path(self: Vc<Self>) -> Vc<FileSystemPath> {
self.project_fs().root() self.project_fs().root()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn project_path(self) -> Result<FileSystemPathVc> { async fn project_path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
let this = self.await?; let this = self.await?;
let root = self.project_root_path(); let root = self.project_root_path();
let project_relative = this.project_path.strip_prefix(&this.root_path).unwrap(); let project_relative = this.project_path.strip_prefix(&this.root_path).unwrap();
@ -182,13 +180,13 @@ impl ProjectVc {
.strip_prefix(MAIN_SEPARATOR) .strip_prefix(MAIN_SEPARATOR)
.unwrap_or(project_relative) .unwrap_or(project_relative)
.replace(MAIN_SEPARATOR, "/"); .replace(MAIN_SEPARATOR, "/");
Ok(root.join(&project_relative)) Ok(root.join(project_relative))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_structure(self) -> Result<PagesStructureVc> { async fn pages_structure(self: Vc<Self>) -> Result<Vc<PagesStructure>> {
let this: turbo_tasks::ReadRef<Project> = self.await?; let this: turbo_tasks::ReadRef<Project> = self.await?;
let next_router_fs = VirtualFileSystemVc::new().as_file_system(); let next_router_fs = Vc::upcast::<Box<dyn FileSystem>>(VirtualFileSystem::new());
let next_router_root = next_router_fs.root(); let next_router_root = next_router_fs.root();
Ok(find_pages_structure( Ok(find_pages_structure(
self.project_path(), self.project_path(),
@ -198,30 +196,31 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn env(self) -> ProcessEnvVc { fn env(self: Vc<Self>) -> Vc<Box<dyn ProcessEnv>> {
load_env(self.project_path()) load_env(self.project_path())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn next_config(self) -> Result<NextConfigVc> { async fn next_config(self: Vc<Self>) -> Result<Vc<NextConfig>> {
Ok(self.await?.next_config) Ok(self.await?.next_config)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn execution_context(self) -> ExecutionContextVc { fn execution_context(self: Vc<Self>) -> Vc<ExecutionContext> {
let node_root = self.node_root(); let node_root = self.node_root();
let node_execution_chunking_context = DevChunkingContextVc::builder( let node_execution_chunking_context = Vc::upcast(
self.project_path(), DevChunkingContext::builder(
node_root, self.project_path(),
node_root.join("chunks"), node_root,
node_root.join("assets"), node_root.join("chunks".to_string()),
node_build_environment(), node_root.join("assets".to_string()),
) node_build_environment(),
.build() )
.into(); .build(),
);
ExecutionContextVc::new( ExecutionContext::new(
self.project_path(), self.project_path(),
node_execution_chunking_context, node_execution_chunking_context,
self.env(), self.env(),
@ -229,40 +228,40 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn client_compile_time_info(self) -> Result<CompileTimeInfoVc> { async fn client_compile_time_info(self: Vc<Self>) -> Result<Vc<CompileTimeInfo>> {
let this = self.await?; let this = self.await?;
Ok(get_client_compile_time_info( Ok(get_client_compile_time_info(
this.mode, this.mode,
&this.browserslist_query, this.browserslist_query.clone(),
)) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn server_compile_time_info(self) -> Result<CompileTimeInfoVc> { async fn server_compile_time_info(self: Vc<Self>) -> Result<Vc<CompileTimeInfo>> {
let this = self.await?; let this = self.await?;
Ok(get_server_compile_time_info( Ok(get_server_compile_time_info(
this.mode, this.mode,
self.env(), self.env(),
// TODO(alexkirsz) Fill this out. // TODO(alexkirsz) Fill this out.
ServerAddrVc::empty(), ServerAddr::empty(),
)) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_dir(self) -> Result<FileSystemPathVc> { async fn pages_dir(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
Ok(if let Some(pages) = self.pages_structure().await?.pages { Ok(if let Some(pages) = self.pages_structure().await?.pages {
pages.project_path() pages.project_path()
} else { } else {
self.project_path().join("pages") self.project_path().join("pages".to_string())
}) })
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn pages_transitions(self) -> TransitionsByNameVc { fn pages_transitions(self: Vc<Self>) -> Vc<TransitionsByName> {
TransitionsByNameVc::cell( Vc::cell(
[( [(
"next-dynamic".to_string(), "next-dynamic".to_string(),
NextDynamicTransitionVc::new(self.pages_client_transition()).into(), Vc::upcast(NextDynamicTransition::new(self.pages_client_transition())),
)] )]
.into_iter() .into_iter()
.collect(), .collect(),
@ -270,8 +269,8 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn pages_client_transition(self) -> ContextTransitionVc { fn pages_client_transition(self: Vc<Self>) -> Vc<ContextTransition> {
ContextTransitionVc::new( ContextTransition::new(
self.client_compile_time_info(), self.client_compile_time_info(),
self.pages_client_module_options_context(), self.pages_client_module_options_context(),
self.pages_client_resolve_options_context(), self.pages_client_resolve_options_context(),
@ -279,7 +278,9 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_client_module_options_context(self) -> Result<ModuleOptionsContextVc> { async fn pages_client_module_options_context(
self: Vc<Self>,
) -> Result<Vc<ModuleOptionsContext>> {
let this = self.await?; let this = self.await?;
Ok(get_client_module_options_context( Ok(get_client_module_options_context(
self.project_path(), self.project_path(),
@ -294,7 +295,9 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_client_resolve_options_context(self) -> Result<ResolveOptionsContextVc> { async fn pages_client_resolve_options_context(
self: Vc<Self>,
) -> Result<Vc<ResolveOptionsContext>> {
let this = self.await?; let this = self.await?;
Ok(get_client_resolve_options_context( Ok(get_client_resolve_options_context(
self.project_path(), self.project_path(),
@ -308,40 +311,37 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) fn pages_client_module_context(self) -> AssetContextVc { pub(super) fn pages_client_module_context(self: Vc<Self>) -> Vc<Box<dyn AssetContext>> {
ModuleAssetContextVc::new( Vc::upcast(ModuleAssetContext::new(
self.pages_transitions(), self.pages_transitions(),
self.client_compile_time_info(), self.client_compile_time_info(),
self.pages_client_module_options_context(), self.pages_client_module_options_context(),
self.pages_client_resolve_options_context(), self.pages_client_resolve_options_context(),
) ))
.into()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) fn pages_ssr_module_context(self) -> AssetContextVc { pub(super) fn pages_ssr_module_context(self: Vc<Self>) -> Vc<Box<dyn AssetContext>> {
ModuleAssetContextVc::new( Vc::upcast(ModuleAssetContext::new(
self.pages_transitions(), self.pages_transitions(),
self.server_compile_time_info(), self.server_compile_time_info(),
self.pages_ssr_module_options_context(), self.pages_ssr_module_options_context(),
self.pages_ssr_resolve_options_context(), self.pages_ssr_resolve_options_context(),
) ))
.into()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) fn pages_ssr_data_module_context(self) -> AssetContextVc { pub(super) fn pages_ssr_data_module_context(self: Vc<Self>) -> Vc<Box<dyn AssetContext>> {
ModuleAssetContextVc::new( Vc::upcast(ModuleAssetContext::new(
self.pages_transitions(), self.pages_transitions(),
self.server_compile_time_info(), self.server_compile_time_info(),
self.pages_ssr_data_module_options_context(), self.pages_ssr_data_module_options_context(),
self.pages_ssr_resolve_options_context(), self.pages_ssr_resolve_options_context(),
) ))
.into()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_ssr_module_options_context(self) -> Result<ModuleOptionsContextVc> { async fn pages_ssr_module_options_context(self: Vc<Self>) -> Result<Vc<ModuleOptionsContext>> {
let this = self.await?; let this = self.await?;
Ok(get_server_module_options_context( Ok(get_server_module_options_context(
self.project_path(), self.project_path(),
@ -355,7 +355,9 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_ssr_data_module_options_context(self) -> Result<ModuleOptionsContextVc> { async fn pages_ssr_data_module_options_context(
self: Vc<Self>,
) -> Result<Vc<ModuleOptionsContext>> {
let this = self.await?; let this = self.await?;
Ok(get_server_module_options_context( Ok(get_server_module_options_context(
self.project_path(), self.project_path(),
@ -369,7 +371,9 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pages_ssr_resolve_options_context(self) -> Result<ResolveOptionsContextVc> { async fn pages_ssr_resolve_options_context(
self: Vc<Self>,
) -> Result<Vc<ResolveOptionsContext>> {
let this = self.await?; let this = self.await?;
Ok(get_server_resolve_options_context( Ok(get_server_resolve_options_context(
self.project_path(), self.project_path(),
@ -383,7 +387,9 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn pages_client_runtime_entries(self) -> Result<EvaluatableAssetsVc> { pub(super) async fn pages_client_runtime_entries(
self: Vc<Self>,
) -> Result<Vc<EvaluatableAssets>> {
let this = self.await?; let this = self.await?;
let client_runtime_entries = get_client_runtime_entries( let client_runtime_entries = get_client_runtime_entries(
self.project_path(), self.project_path(),
@ -399,7 +405,7 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn pages_ssr_runtime_entries(self) -> Result<EvaluatableAssetsVc> { pub(super) async fn pages_ssr_runtime_entries(self: Vc<Self>) -> Result<Vc<EvaluatableAssets>> {
let this = self.await?; let this = self.await?;
let ssr_runtime_entries = get_server_runtime_entries( let ssr_runtime_entries = get_server_runtime_entries(
self.project_path(), self.project_path(),
@ -414,7 +420,9 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn client_chunking_context(self) -> Result<EcmascriptChunkingContextVc> { pub(super) async fn client_chunking_context(
self: Vc<Self>,
) -> Result<Vc<Box<dyn EcmascriptChunkingContext>>> {
let this = self.await?; let this = self.await?;
Ok(get_client_chunking_context( Ok(get_client_chunking_context(
self.project_path(), self.project_path(),
@ -425,7 +433,7 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) fn server_chunking_context(self) -> BuildChunkingContextVc { pub(super) fn server_chunking_context(self: Vc<Self>) -> Vc<BuildChunkingContext> {
get_server_chunking_context( get_server_chunking_context(
self.project_path(), self.project_path(),
self.node_root(), self.node_root(),
@ -435,25 +443,29 @@ impl ProjectVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn ssr_chunking_context(self) -> Result<BuildChunkingContextVc> { pub(super) async fn ssr_chunking_context(self: Vc<Self>) -> Result<Vc<BuildChunkingContext>> {
let ssr_chunking_context = self.server_chunking_context().with_layer("ssr"); let ssr_chunking_context = self.server_chunking_context().with_layer("ssr".to_string());
BuildChunkingContextVc::resolve_from(ssr_chunking_context) Vc::try_resolve_downcast_type::<BuildChunkingContext>(ssr_chunking_context)
.await? .await?
.context("with_layer should not change the type of the chunking context") .context("with_layer should not change the type of the chunking context")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn ssr_data_chunking_context(self) -> Result<BuildChunkingContextVc> { pub(super) async fn ssr_data_chunking_context(
let ssr_chunking_context = self.server_chunking_context().with_layer("ssr data"); self: Vc<Self>,
BuildChunkingContextVc::resolve_from(ssr_chunking_context) ) -> Result<Vc<BuildChunkingContext>> {
let ssr_chunking_context = self
.server_chunking_context()
.with_layer("ssr data".to_string());
Vc::try_resolve_downcast_type::<BuildChunkingContext>(ssr_chunking_context)
.await? .await?
.context("with_layer should not change the type of the chunking context") .context("with_layer should not change the type of the chunking context")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn rsc_chunking_context(self) -> Result<BuildChunkingContextVc> { pub(super) async fn rsc_chunking_context(self: Vc<Self>) -> Result<Vc<BuildChunkingContext>> {
let rsc_chunking_context = self.server_chunking_context().with_layer("rsc"); let rsc_chunking_context = self.server_chunking_context().with_layer("rsc".to_string());
BuildChunkingContextVc::resolve_from(rsc_chunking_context) Vc::try_resolve_downcast_type::<BuildChunkingContext>(rsc_chunking_context)
.await? .await?
.context("with_layer should not change the type of the chunking context") .context("with_layer should not change the type of the chunking context")
} }
@ -461,7 +473,7 @@ impl ProjectVc {
/// Scans the app/pages directories for entry points files (matching the /// Scans the app/pages directories for entry points files (matching the
/// provided page_extensions). /// provided page_extensions).
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn entrypoints(self) -> Result<EntrypointsVc> { pub async fn entrypoints(self: Vc<Self>) -> Result<Vc<Entrypoints>> {
let this = self.await?; let this = self.await?;
let mut routes = IndexMap::new(); let mut routes = IndexMap::new();
if let Some(app_dir) = *find_app_dir(self.project_path()).await? { if let Some(app_dir) = *find_app_dir(self.project_path()).await? {
@ -501,17 +513,16 @@ impl ProjectVc {
/// Emits opaque HMR events whenever a change is detected in the chunk group /// Emits opaque HMR events whenever a change is detected in the chunk group
/// internally known as `identifier`. /// internally known as `identifier`.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn hmr_events(self, _identifier: String, _sender: TransientValue<()>) -> NothingVc { pub fn hmr_events(self: Vc<Self>, _identifier: String, _sender: TransientValue<()>) -> Vc<()> {
NothingVc::new() unit()
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn project_fs(project_dir: &str, watching: bool) -> Result<FileSystemVc> { async fn project_fs(project_dir: String, watching: bool) -> Result<Vc<Box<dyn FileSystem>>> {
let disk_fs = let disk_fs = DiskFileSystem::new(PROJECT_FILESYSTEM_NAME.to_string(), project_dir.to_string());
DiskFileSystemVc::new(PROJECT_FILESYSTEM_NAME.to_string(), project_dir.to_string());
if watching { if watching {
disk_fs.await?.start_watching_with_invalidation_reason()?; disk_fs.await?.start_watching_with_invalidation_reason()?;
} }
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }

View file

@ -1,31 +1,30 @@
use anyhow::Result;
use indexmap::IndexMap; use indexmap::IndexMap;
use turbo_tasks::CompletionVc; use turbo_tasks::{Completion, Vc};
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
pub enum Route { pub enum Route {
Page { Page {
html_endpoint: EndpointVc, html_endpoint: Vc<Box<dyn Endpoint>>,
data_endpoint: EndpointVc, data_endpoint: Vc<Box<dyn Endpoint>>,
}, },
PageApi { PageApi {
endpoint: EndpointVc, endpoint: Vc<Box<dyn Endpoint>>,
}, },
AppPage { AppPage {
html_endpoint: EndpointVc, html_endpoint: Vc<Box<dyn Endpoint>>,
rsc_endpoint: EndpointVc, rsc_endpoint: Vc<Box<dyn Endpoint>>,
}, },
AppRoute { AppRoute {
endpoint: EndpointVc, endpoint: Vc<Box<dyn Endpoint>>,
}, },
Conflict, Conflict,
} }
#[turbo_tasks::value_trait] #[turbo_tasks::value_trait]
pub trait Endpoint { pub trait Endpoint {
fn write_to_disk(&self) -> WrittenEndpointVc; fn write_to_disk(self: Vc<Self>) -> Vc<WrittenEndpoint>;
fn changed(&self) -> CompletionVc; fn changed(self: Vc<Self>) -> Vc<Completion>;
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]

View file

@ -1,4 +1,6 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
#![feature(arbitrary_self_types)]
#![feature(async_fn_in_trait)]
use turbopack_binding::turbo::{ use turbopack_binding::turbo::{
tasks::{run_once, TransientInstance, TurboTasks}, tasks::{run_once, TransientInstance, TurboTasks},

View file

@ -1,3 +1,6 @@
#![feature(arbitrary_self_types)]
#![feature(async_fn_in_trait)]
use std::path::PathBuf; use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;

View file

@ -2,15 +2,18 @@ use std::collections::HashSet;
use anyhow::Result; use anyhow::Result;
use indexmap::IndexMap; use indexmap::IndexMap;
use next_core::{self, next_client_reference::ClientReferenceType}; use next_core::{
use turbo_tasks::TryJoinIterExt; next_client_reference::ClientReferenceType,
{self},
};
use turbo_tasks::{TryJoinIterExt, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
build::BuildChunkingContextVc, build::BuildChunkingContext,
core::{ core::{
chunk::{ChunkableModule, ChunkingContext}, chunk::{ChunkableModule, ChunkingContext},
output::{OutputAssetVc, OutputAssetsVc}, output::{OutputAsset, OutputAssets},
}, },
ecmascript::chunk::EcmascriptChunkingContextVc, ecmascript::chunk::EcmascriptChunkingContext,
}; };
/// Computes all client references chunks, and adds them to the relevant /// Computes all client references chunks, and adds them to the relevant
@ -20,9 +23,9 @@ use turbopack_binding::turbopack::{
/// type needs to load. /// type needs to load.
pub async fn compute_app_client_references_chunks( pub async fn compute_app_client_references_chunks(
app_client_reference_types: &HashSet<ClientReferenceType>, app_client_reference_types: &HashSet<ClientReferenceType>,
client_chunking_context: EcmascriptChunkingContextVc, client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
ssr_chunking_context: BuildChunkingContextVc, ssr_chunking_context: Vc<BuildChunkingContext>,
all_chunks: &mut Vec<OutputAssetVc>, all_chunks: &mut Vec<Vc<Box<dyn OutputAsset>>>,
) -> Result<IndexMap<ClientReferenceType, ClientReferenceChunks>> { ) -> Result<IndexMap<ClientReferenceType, ClientReferenceChunks>> {
let app_client_references_chunks: IndexMap<_, _> = app_client_reference_types let app_client_references_chunks: IndexMap<_, _> = app_client_reference_types
.iter() .iter()
@ -34,10 +37,10 @@ pub async fn compute_app_client_references_chunks(
let ecmascript_client_reference_ref = ecmascript_client_reference.await?; let ecmascript_client_reference_ref = ecmascript_client_reference.await?;
let client_entry_chunk = ecmascript_client_reference_ref let client_entry_chunk = ecmascript_client_reference_ref
.client_module .client_module
.as_root_chunk(client_chunking_context.into()); .as_root_chunk(Vc::upcast(client_chunking_context));
let ssr_entry_chunk = ecmascript_client_reference_ref let ssr_entry_chunk = ecmascript_client_reference_ref
.ssr_module .ssr_module
.as_root_chunk(ssr_chunking_context.into()); .as_root_chunk(Vc::upcast(ssr_chunking_context));
ClientReferenceChunks { ClientReferenceChunks {
client_chunks: client_chunking_context.chunk_group(client_entry_chunk), client_chunks: client_chunking_context.chunk_group(client_entry_chunk),
ssr_chunks: ssr_chunking_context.chunk_group(ssr_entry_chunk), ssr_chunks: ssr_chunking_context.chunk_group(ssr_entry_chunk),
@ -47,10 +50,10 @@ pub async fn compute_app_client_references_chunks(
let css_client_reference_ref = css_client_reference.await?; let css_client_reference_ref = css_client_reference.await?;
let client_entry_chunk = css_client_reference_ref let client_entry_chunk = css_client_reference_ref
.client_module .client_module
.as_root_chunk(client_chunking_context.into()); .as_root_chunk(Vc::upcast(client_chunking_context));
ClientReferenceChunks { ClientReferenceChunks {
client_chunks: client_chunking_context.chunk_group(client_entry_chunk), client_chunks: client_chunking_context.chunk_group(client_entry_chunk),
ssr_chunks: OutputAssetsVc::empty(), ssr_chunks: OutputAssets::empty(),
} }
} }
}, },
@ -82,7 +85,7 @@ pub async fn compute_app_client_references_chunks(
/// Contains the chunks corresponding to a client reference. /// Contains the chunks corresponding to a client reference.
pub struct ClientReferenceChunks { pub struct ClientReferenceChunks {
/// Chunks to be loaded on the client. /// Chunks to be loaded on the client.
pub client_chunks: OutputAssetsVc, pub client_chunks: Vc<OutputAssets>,
/// Chunks to be loaded on the server for SSR. /// Chunks to be loaded on the server for SSR.
pub ssr_chunks: OutputAssetsVc, pub ssr_chunks: Vc<OutputAssets>,
} }

View file

@ -11,47 +11,44 @@ use next_core::{
get_client_runtime_entries, ClientContextType, get_client_runtime_entries, ClientContextType,
}, },
next_client_reference::{ next_client_reference::{
ClientReference, ClientReferenceType, NextEcmascriptClientReferenceTransitionVc, ClientReference, ClientReferenceType, NextEcmascriptClientReferenceTransition,
}, },
next_config::NextConfigVc, next_config::NextConfig,
next_dynamic::NextDynamicTransitionVc, next_dynamic::NextDynamicTransition,
next_server::{ next_server::{
get_server_module_options_context, get_server_resolve_options_context, get_server_module_options_context, get_server_resolve_options_context,
get_server_runtime_entries, ServerContextType, get_server_runtime_entries, ServerContextType,
}, },
}; };
use turbo_tasks::{primitives::StringVc, TryJoinIterExt, Value, ValueToString}; use turbo_tasks::{TryJoinIterExt, Value, ValueToString, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{
tasks_env::{CustomProcessEnvVc, ProcessEnvVc}, tasks_env::{CustomProcessEnv, ProcessEnv},
tasks_fs::{File, FileSystemPath, FileSystemPathVc}, tasks_fs::{File, FileSystemPath},
}, },
turbopack::{ turbopack::{
build::BuildChunkingContextVc, build::BuildChunkingContext,
core::{ core::{
asset::{Asset, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{
availability_info::AvailabilityInfo, ChunkingContext, EvaluatableAssetsVc, availability_info::AvailabilityInfo, ChunkingContext, EvaluatableAssets,
ModuleId as TurbopackModuleId, ModuleId as TurbopackModuleId,
}, },
compile_time_info::CompileTimeInfoVc, compile_time_info::CompileTimeInfo,
file_source::FileSourceVc, file_source::FileSource,
output::{OutputAssetVc, OutputAssetsVc}, output::{OutputAsset, OutputAssets},
raw_output::RawOutputVc, raw_output::RawOutput,
virtual_source::VirtualSourceVc, virtual_source::VirtualSource,
}, },
ecmascript::{ ecmascript::{
chunk::{ chunk::{
EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkPlaceablesVc, EcmascriptChunk, EcmascriptChunkItemExt, EcmascriptChunkPlaceable,
EcmascriptChunkVc, EcmascriptChunkingContextVc, EcmascriptChunkingContext,
}, },
utils::StringifyJs, utils::StringifyJs,
}, },
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::{ turbopack::{transition::ContextTransition, ModuleAssetContext},
transition::{ContextTransitionVc, TransitionsByNameVc},
ModuleAssetContextVc,
},
}, },
}; };
@ -73,38 +70,38 @@ pub struct AppEntry {
/// the pathname to refer to this entry. /// the pathname to refer to this entry.
pub original_name: String, pub original_name: String,
/// The RSC module asset for the route or page. /// The RSC module asset for the route or page.
pub rsc_entry: EcmascriptChunkPlaceableVc, pub rsc_entry: Vc<Box<dyn EcmascriptChunkPlaceable>>,
} }
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct AppEntries { pub struct AppEntries {
/// All app entries. /// All app entries.
pub entries: Vec<AppEntryVc>, pub entries: Vec<Vc<AppEntry>>,
/// The RSC runtime entries that should be evaluated before any app entry /// The RSC runtime entries that should be evaluated before any app entry
/// module when server rendering. /// module when server rendering.
pub rsc_runtime_entries: EvaluatableAssetsVc, pub rsc_runtime_entries: Vc<EvaluatableAssets>,
/// The client runtime entries that should be evaluated before any app entry /// The client runtime entries that should be evaluated before any app entry
/// module when client rendering. /// module when client rendering.
pub client_runtime_entries: EvaluatableAssetsVc, pub client_runtime_entries: Vc<EvaluatableAssets>,
} }
/// Computes all app entries found under the given project root. /// Computes all app entries found under the given project root.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_app_entries( pub async fn get_app_entries(
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
env: ProcessEnvVc, env: Vc<Box<dyn ProcessEnv>>,
client_compile_time_info: CompileTimeInfoVc, client_compile_time_info: Vc<CompileTimeInfo>,
server_compile_time_info: CompileTimeInfoVc, server_compile_time_info: Vc<CompileTimeInfo>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<AppEntriesVc> { ) -> Result<Vc<AppEntries>> {
let app_dir = find_app_dir_if_enabled(project_root, next_config); let app_dir = find_app_dir_if_enabled(project_root, next_config);
let Some(&app_dir) = app_dir.await?.as_ref() else { let Some(&app_dir) = app_dir.await?.as_ref() else {
return Ok(AppEntriesVc::cell(AppEntries { return Ok(AppEntries::cell(AppEntries {
entries: vec![], entries: vec![],
rsc_runtime_entries: EvaluatableAssetsVc::empty(), rsc_runtime_entries: EvaluatableAssets::empty(),
client_runtime_entries: EvaluatableAssetsVc::empty(), client_runtime_entries: EvaluatableAssets::empty(),
})); }));
}; };
@ -124,7 +121,7 @@ pub async fn get_app_entries(
// app_source? // app_source?
let runtime_entries = get_server_runtime_entries(project_root, env, rsc_ty, mode, next_config); let runtime_entries = get_server_runtime_entries(project_root, env, rsc_ty, mode, next_config);
let env = CustomProcessEnvVc::new(env, next_config.env()).as_process_env(); let env = Vc::upcast(CustomProcessEnv::new(env, next_config.env()));
let ssr_ty: Value<ServerContextType> = Value::new(ServerContextType::AppSSR { app_dir }); let ssr_ty: Value<ServerContextType> = Value::new(ServerContextType::AppSSR { app_dir });
@ -147,7 +144,7 @@ pub async fn get_app_entries(
execution_context, execution_context,
); );
let client_transition = ContextTransitionVc::new( let client_transition = ContextTransition::new(
client_compile_time_info, client_compile_time_info,
client_module_options_context, client_module_options_context,
client_resolve_options_context, client_resolve_options_context,
@ -169,7 +166,7 @@ pub async fn get_app_entries(
next_config, next_config,
); );
let ssr_transition = ContextTransitionVc::new( let ssr_transition = ContextTransition::new(
server_compile_time_info, server_compile_time_info,
ssr_module_options_context, ssr_module_options_context,
ssr_resolve_options_context, ssr_resolve_options_context,
@ -179,19 +176,22 @@ pub async fn get_app_entries(
transitions.insert( transitions.insert(
ECMASCRIPT_CLIENT_TRANSITION_NAME.to_string(), ECMASCRIPT_CLIENT_TRANSITION_NAME.to_string(),
NextEcmascriptClientReferenceTransitionVc::new(client_transition, ssr_transition).into(), Vc::upcast(NextEcmascriptClientReferenceTransition::new(
client_transition,
ssr_transition,
)),
); );
let client_ty = Value::new(ClientContextType::App { app_dir }); let client_ty = Value::new(ClientContextType::App { app_dir });
transitions.insert( transitions.insert(
"next-dynamic".to_string(), "next-dynamic".to_string(),
NextDynamicTransitionVc::new(client_transition).into(), Vc::upcast(NextDynamicTransition::new(client_transition)),
); );
let rsc_ty = Value::new(ServerContextType::AppRSC { let rsc_ty = Value::new(ServerContextType::AppRSC {
app_dir, app_dir,
client_transition: Some(client_transition.into()), client_transition: Some(Vc::upcast(client_transition)),
ecmascript_client_reference_transition_name: Some(StringVc::cell( ecmascript_client_reference_transition_name: Some(Vc::cell(
ECMASCRIPT_CLIENT_TRANSITION_NAME.to_string(), ECMASCRIPT_CLIENT_TRANSITION_NAME.to_string(),
)), )),
}); });
@ -211,8 +211,8 @@ pub async fn get_app_entries(
execution_context, execution_context,
); );
let rsc_context = ModuleAssetContextVc::new( let rsc_context = ModuleAssetContext::new(
TransitionsByNameVc::cell(transitions), Vc::cell(transitions),
server_compile_time_info, server_compile_time_info,
rsc_module_options_context, rsc_module_options_context,
rsc_resolve_options_context, rsc_resolve_options_context,
@ -230,7 +230,7 @@ pub async fn get_app_entries(
Entrypoint::AppRoute { path } => { Entrypoint::AppRoute { path } => {
get_app_route_entry( get_app_route_entry(
rsc_context, rsc_context,
FileSourceVc::new(*path).into(), Vc::upcast(FileSource::new(*path)),
pathname, pathname,
project_root, project_root,
) )
@ -248,8 +248,8 @@ pub async fn get_app_entries(
entries.push(get_app_route_favicon_entry(rsc_context, favicon, project_root).await?); entries.push(get_app_route_favicon_entry(rsc_context, favicon, project_root).await?);
} }
let client_context = ModuleAssetContextVc::new( let client_context = ModuleAssetContext::new(
TransitionsByNameVc::cell(Default::default()), Vc::cell(Default::default()),
client_compile_time_info, client_compile_time_info,
client_module_options_context, client_module_options_context,
client_resolve_options_context, client_resolve_options_context,
@ -264,10 +264,10 @@ pub async fn get_app_entries(
execution_context, execution_context,
); );
Ok(AppEntriesVc::cell(AppEntries { Ok(AppEntries::cell(AppEntries {
entries, entries,
rsc_runtime_entries: runtime_entries.resolve_entries(rsc_context.into()), rsc_runtime_entries: runtime_entries.resolve_entries(Vc::upcast(rsc_context)),
client_runtime_entries: client_runtime_entries.resolve_entries(client_context.into()), client_runtime_entries: client_runtime_entries.resolve_entries(Vc::upcast(client_context)),
})) }))
} }
@ -276,18 +276,18 @@ pub async fn get_app_entries(
/// manifests. /// manifests.
pub async fn compute_app_entries_chunks( pub async fn compute_app_entries_chunks(
app_entries: &AppEntries, app_entries: &AppEntries,
app_client_references_by_entry: &IndexMap<AssetVc, Vec<ClientReference>>, app_client_references_by_entry: &IndexMap<Vc<Box<dyn Asset>>, Vec<ClientReference>>,
app_client_references_chunks: &IndexMap<ClientReferenceType, ClientReferenceChunks>, app_client_references_chunks: &IndexMap<ClientReferenceType, ClientReferenceChunks>,
rsc_chunking_context: BuildChunkingContextVc, rsc_chunking_context: Vc<BuildChunkingContext>,
client_chunking_context: EcmascriptChunkingContextVc, client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
ssr_chunking_context: EcmascriptChunkingContextVc, ssr_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
node_root: FileSystemPathVc, node_root: Vc<FileSystemPath>,
client_relative_path: &FileSystemPath, client_relative_path: &FileSystemPath,
app_paths_manifest_dir_path: &FileSystemPath, app_paths_manifest_dir_path: &FileSystemPath,
app_build_manifest: &mut AppBuildManifest, app_build_manifest: &mut AppBuildManifest,
build_manifest: &mut BuildManifest, build_manifest: &mut BuildManifest,
app_paths_manifest: &mut AppPathsManifest, app_paths_manifest: &mut AppPathsManifest,
all_chunks: &mut Vec<OutputAssetVc>, all_chunks: &mut Vec<Vc<Box<dyn OutputAsset>>>,
) -> Result<()> { ) -> Result<()> {
let node_root_ref = node_root.await?; let node_root_ref = node_root.await?;
@ -299,7 +299,7 @@ pub async fn compute_app_entries_chunks(
all_chunks.push(chunk); all_chunks.push(chunk);
let chunk_path = chunk.ident().path().await?; let chunk_path = chunk.ident().path().await?;
if chunk_path.extension() == Some("js") { if chunk_path.extension_ref() == Some("js") {
if let Some(chunk_path) = client_relative_path.get_path_to(&chunk_path) { if let Some(chunk_path) = client_relative_path.get_path_to(&chunk_path) {
app_shared_client_chunks_paths.push(chunk_path.to_string()); app_shared_client_chunks_paths.push(chunk_path.to_string());
build_manifest.root_main_files.push(chunk_path.to_string()); build_manifest.root_main_files.push(chunk_path.to_string());
@ -311,11 +311,11 @@ pub async fn compute_app_entries_chunks(
let app_entry = app_entry.await?; let app_entry = app_entry.await?;
let app_entry_client_references = app_client_references_by_entry let app_entry_client_references = app_client_references_by_entry
.get(&app_entry.rsc_entry.as_asset()) .get(&Vc::upcast(app_entry.rsc_entry))
.expect("app entry should have a corresponding client references list"); .expect("app entry should have a corresponding client references list");
let rsc_chunk = rsc_chunking_context.entry_chunk( let rsc_chunk = rsc_chunking_context.entry_chunk(
node_root.join(&format!( node_root.join(format!(
"server/app/{original_name}.js", "server/app/{original_name}.js",
original_name = app_entry.original_name original_name = app_entry.original_name
)), )),
@ -388,7 +388,7 @@ pub async fn compute_app_entries_chunks(
if let Some(server_component) = app_client_reference.server_component() { if let Some(server_component) = app_client_reference.server_component() {
let server_component_name = server_component let server_component_name = server_component
.server_path() .server_path()
.with_extension("") .with_extension("".to_string())
.to_string() .to_string()
.await?; .await?;
@ -414,7 +414,7 @@ pub async fn compute_app_entries_chunks(
client_chunks_paths client_chunks_paths
.iter() .iter()
.filter_map(|chunk_path| { .filter_map(|chunk_path| {
if chunk_path.extension() == Some("css") { if chunk_path.extension_ref() == Some("css") {
client_relative_path.get_path_to(chunk_path) client_relative_path.get_path_to(chunk_path)
} else { } else {
None None
@ -506,22 +506,26 @@ pub async fn compute_app_entries_chunks(
} }
let client_reference_manifest_json = serde_json::to_string(&entry_manifest).unwrap(); let client_reference_manifest_json = serde_json::to_string(&entry_manifest).unwrap();
let client_reference_manifest_source = VirtualSourceVc::new( let client_reference_manifest_source = VirtualSource::new(
node_root.join(&format!( node_root.join(format!(
"server/app/{original_name}_client-reference-manifest.js", "server/app/{original_name}_client-reference-manifest.js",
original_name = app_entry.original_name original_name = app_entry.original_name
)), )),
File::from(formatdoc! { AssetContent::file(
r#" File::from(formatdoc! {
r#"
globalThis.__RSC_MANIFEST = globalThis.__RSC_MANIFEST || {{}}; globalThis.__RSC_MANIFEST = globalThis.__RSC_MANIFEST || {{}};
globalThis.__RSC_MANIFEST[{original_name}] = {manifest} globalThis.__RSC_MANIFEST[{original_name}] = {manifest}
"#, "#,
original_name = StringifyJs(&app_entry.original_name), original_name = StringifyJs(&app_entry.original_name),
manifest = StringifyJs(&client_reference_manifest_json) manifest = StringifyJs(&client_reference_manifest_json)
}) })
.into(), .into(),
),
); );
all_chunks.push(RawOutputVc::new(client_reference_manifest_source.into()).into()); all_chunks.push(Vc::upcast(RawOutput::new(Vc::upcast(
client_reference_manifest_source,
))));
} }
Ok(()) Ok(())
@ -529,23 +533,25 @@ pub async fn compute_app_entries_chunks(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_app_shared_client_chunk( pub async fn get_app_shared_client_chunk(
app_client_runtime_entries: EvaluatableAssetsVc, app_client_runtime_entries: Vc<EvaluatableAssets>,
client_chunking_context: EcmascriptChunkingContextVc, client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<EcmascriptChunkVc> { ) -> Result<Vc<EcmascriptChunk>> {
let client_runtime_entries: Vec<_> = app_client_runtime_entries let client_runtime_entries: Vec<_> = app_client_runtime_entries
.await? .await?
.iter() .iter()
.map(|entry| async move { Ok(EcmascriptChunkPlaceableVc::resolve_from(*entry).await?) }) .map(|entry| async move {
Ok(Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(*entry).await?)
})
.try_join() .try_join()
.await? .await?
.into_iter() .into_iter()
.flatten() .flatten()
.collect(); .collect();
Ok(EcmascriptChunkVc::new_normalized( Ok(EcmascriptChunk::new_normalized(
client_chunking_context, client_chunking_context,
// TODO(alexkirsz) Should this accept Evaluatable instead? // TODO(alexkirsz) Should this accept Evaluatable instead?
EcmascriptChunkPlaceablesVc::cell(client_runtime_entries), Vc::cell(client_runtime_entries),
None, None,
Value::new(AvailabilityInfo::Untracked), Value::new(AvailabilityInfo::Untracked),
)) ))
@ -553,18 +559,20 @@ pub async fn get_app_shared_client_chunk(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_app_client_shared_chunks( pub async fn get_app_client_shared_chunks(
app_client_runtime_entries: EvaluatableAssetsVc, app_client_runtime_entries: Vc<EvaluatableAssets>,
client_chunking_context: EcmascriptChunkingContextVc, client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<OutputAssetsVc> { ) -> Result<Vc<OutputAssets>> {
if app_client_runtime_entries.await?.is_empty() { if app_client_runtime_entries.await?.is_empty() {
return Ok(OutputAssetsVc::empty()); return Ok(OutputAssets::empty());
} }
let app_client_shared_chunk = let app_client_shared_chunk =
get_app_shared_client_chunk(app_client_runtime_entries, client_chunking_context); get_app_shared_client_chunk(app_client_runtime_entries, client_chunking_context);
let app_client_shared_chunks = client_chunking_context let app_client_shared_chunks = client_chunking_context.evaluated_chunk_group(
.evaluated_chunk_group(app_client_shared_chunk.into(), app_client_runtime_entries); Vc::upcast(app_client_shared_chunk),
app_client_runtime_entries,
);
Ok(app_client_shared_chunks) Ok(app_client_shared_chunks)
} }

View file

@ -3,37 +3,36 @@ use std::io::Write;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indoc::writedoc; use indoc::writedoc;
use next_core::{ use next_core::{
app_structure::LoaderTreeVc, app_structure::LoaderTree,
loader_tree::{LoaderTreeModule, ServerComponentTransition}, loader_tree::{LoaderTreeModule, ServerComponentTransition},
mode::NextMode, mode::NextMode,
next_server_component::NextServerComponentTransitionVc, next_server_component::NextServerComponentTransition,
UnsupportedDynamicMetadataIssue, UnsupportedDynamicMetadataIssue,
}; };
use turbo_tasks::{TryJoinIterExt, Value, ValueToString}; use turbo_tasks::{TryJoinIterExt, Value, ValueToString, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPathVc}, turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
context::AssetContext, asset::AssetContent, context::AssetContext, issue::IssueExt,
reference_type::{InnerAssetsVc, ReferenceType}, reference_type::ReferenceType, virtual_source::VirtualSource,
virtual_source::VirtualSourceVc,
}, },
ecmascript::{chunk::EcmascriptChunkPlaceableVc, utils::StringifyJs}, ecmascript::{chunk::EcmascriptChunkPlaceable, utils::StringifyJs},
turbopack::ModuleAssetContextVc, turbopack::ModuleAssetContext,
}, },
}; };
use super::app_entries::{AppEntry, AppEntryVc}; use super::app_entries::AppEntry;
/// Computes the entry for a Next.js app page. /// Computes the entry for a Next.js app page.
pub(super) async fn get_app_page_entry( pub(super) async fn get_app_page_entry(
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
loader_tree: LoaderTreeVc, loader_tree: Vc<LoaderTree>,
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
pathname: &str, pathname: &str,
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
) -> Result<AppEntryVc> { ) -> Result<Vc<AppEntry>> {
let server_component_transition = NextServerComponentTransitionVc::new().into(); let server_component_transition = Vc::upcast(NextServerComponentTransition::new());
let loader_tree = LoaderTreeModule::build( let loader_tree = LoaderTreeModule::build(
loader_tree, loader_tree,
@ -57,7 +56,6 @@ pub(super) async fn get_app_page_entry(
files: unsupported_metadata, files: unsupported_metadata,
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
} }
@ -95,14 +93,16 @@ pub(super) async fn get_app_page_entry(
let file = File::from(result.build()); let file = File::from(result.build());
let source = let source =
// TODO(alexkirsz) Figure out how to name this virtual asset. // TODO(alexkirsz) Figure out how to name this virtual asset.
VirtualSourceVc::new(project_root.join("todo.tsx"), file.into()); VirtualSource::new(project_root.join("todo.tsx".to_string()), AssetContent::file(file.into()));
let rsc_entry = context.process( let rsc_entry = context.process(
source.into(), Vc::upcast(source),
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(inner_assets))), Value::new(ReferenceType::Internal(Vc::cell(inner_assets))),
); );
let Some(rsc_entry) = EcmascriptChunkPlaceableVc::resolve_from(rsc_entry).await? else { let Some(rsc_entry) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(rsc_entry).await?
else {
bail!("expected an ECMAScript chunk placeable asset"); bail!("expected an ECMAScript chunk placeable asset");
}; };

View file

@ -4,31 +4,31 @@ use anyhow::{bail, Result};
use indexmap::indexmap; use indexmap::indexmap;
use indoc::writedoc; use indoc::writedoc;
use serde::Serialize; use serde::Serialize;
use turbo_tasks::{Value, ValueToString}; use turbo_tasks::{Value, ValueToString, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPathVc}, turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
asset::Asset, asset::{Asset, AssetContent},
context::AssetContext, context::AssetContext,
reference_type::{EcmaScriptModulesReferenceSubType, InnerAssetsVc, ReferenceType}, reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType},
source::SourceVc, source::Source,
virtual_source::VirtualSourceVc, virtual_source::VirtualSource,
}, },
ecmascript::{chunk::EcmascriptChunkPlaceableVc, utils::StringifyJs}, ecmascript::{chunk::EcmascriptChunkPlaceable, utils::StringifyJs},
turbopack::ModuleAssetContextVc, turbopack::ModuleAssetContext,
}, },
}; };
use super::app_entries::{AppEntry, AppEntryVc}; use super::app_entries::AppEntry;
/// Computes the entry for a Next.js app route. /// Computes the entry for a Next.js app route.
pub(super) async fn get_app_route_entry( pub(super) async fn get_app_route_entry(
rsc_context: ModuleAssetContextVc, rsc_context: Vc<ModuleAssetContext>,
source: SourceVc, source: Vc<Box<dyn Source>>,
pathname: &str, pathname: &str,
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
) -> Result<AppEntryVc> { ) -> Result<Vc<AppEntry>> {
let mut result = RopeBuilder::default(); let mut result = RopeBuilder::default();
let kind = "app-route"; let kind = "app-route";
@ -99,7 +99,10 @@ pub(super) async fn get_app_route_entry(
let file = File::from(result.build()); let file = File::from(result.build());
// TODO(alexkirsz) Figure out how to name this virtual asset. // TODO(alexkirsz) Figure out how to name this virtual asset.
let virtual_source = VirtualSourceVc::new(project_root.join("todo.tsx"), file.into()); let virtual_source = VirtualSource::new(
project_root.join("todo.tsx".to_string()),
AssetContent::file(file.into()),
);
let entry = rsc_context.process( let entry = rsc_context.process(
source, source,
@ -109,15 +112,17 @@ pub(super) async fn get_app_route_entry(
); );
let inner_assets = indexmap! { let inner_assets = indexmap! {
"ENTRY".to_string() => entry.into() "ENTRY".to_string() => Vc::upcast(entry)
}; };
let rsc_entry = rsc_context.process( let rsc_entry = rsc_context.process(
virtual_source.into(), Vc::upcast(virtual_source),
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(inner_assets))), Value::new(ReferenceType::Internal(Vc::cell(inner_assets))),
); );
let Some(rsc_entry) = EcmascriptChunkPlaceableVc::resolve_from(rsc_entry).await? else { let Some(rsc_entry) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(rsc_entry).await?
else {
bail!("expected an ECMAScript chunk placeable asset"); bail!("expected an ECMAScript chunk placeable asset");
}; };

View file

@ -4,23 +4,24 @@ use anyhow::{bail, Result};
use base64::{display::Base64Display, engine::general_purpose::STANDARD}; use base64::{display::Base64Display, engine::general_purpose::STANDARD};
use indoc::writedoc; use indoc::writedoc;
use next_core::app_structure::MetadataItem; use next_core::app_structure::MetadataItem;
use turbo_tasks::ValueToString; use turbo_tasks::{ValueToString, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{rope::RopeBuilder, File, FileContent, FileSystemPathVc}, turbo::tasks_fs::{rope::RopeBuilder, File, FileContent, FileSystemPath},
turbopack::{ turbopack::{
core::virtual_source::VirtualSourceVc, ecmascript::utils::StringifyJs, core::{asset::AssetContent, virtual_source::VirtualSource},
turbopack::ModuleAssetContextVc, ecmascript::utils::StringifyJs,
turbopack::ModuleAssetContext,
}, },
}; };
use super::{app_entries::AppEntryVc, app_route_entry::get_app_route_entry}; use super::{app_entries::AppEntry, app_route_entry::get_app_route_entry};
/// Computes the entry for a Next.js favicon file. /// Computes the entry for a Next.js favicon file.
pub(super) async fn get_app_route_favicon_entry( pub(super) async fn get_app_route_favicon_entry(
rsc_context: ModuleAssetContextVc, rsc_context: Vc<ModuleAssetContext>,
favicon: MetadataItem, favicon: MetadataItem,
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
) -> Result<AppEntryVc> { ) -> Result<Vc<AppEntry>> {
let path = match favicon { let path = match favicon {
// TODO(alexkirsz) Is there a difference here? // TODO(alexkirsz) Is there a difference here?
MetadataItem::Static { path } => path, MetadataItem::Static { path } => path,
@ -74,11 +75,11 @@ pub(super) async fn get_app_route_favicon_entry(
let file = File::from(code.build()); let file = File::from(code.build());
let source = let source =
// TODO(alexkirsz) Figure out how to name this virtual source. // TODO(alexkirsz) Figure out how to name this virtual source.
VirtualSourceVc::new(project_root.join("todo.tsx"), file.into()); VirtualSource::new(project_root.join("todo.tsx".to_string()), AssetContent::file(file.into()));
get_app_route_entry( get_app_route_entry(
rsc_context, rsc_context,
source.into(), Vc::upcast(source),
// TODO(alexkirsz) Get this from the metadata? // TODO(alexkirsz) Get this from the metadata?
"/favicon.ico", "/favicon.ico",
project_root, project_root,

View file

@ -7,42 +7,38 @@ use std::{
use anyhow::{anyhow, bail, Context, Result}; use anyhow::{anyhow, bail, Context, Result};
use dunce::canonicalize; use dunce::canonicalize;
use next_core::{ use next_core::{
self,
mode::NextMode, mode::NextMode,
next_client::{get_client_chunking_context, get_client_compile_time_info}, next_client::{get_client_chunking_context, get_client_compile_time_info},
next_client_reference::{ClientReferenceType, ClientReferencesByEntryVc}, next_client_reference::{ClientReferenceType, ClientReferencesByEntry},
next_config::load_next_config, next_config::load_next_config,
next_dynamic::NextDynamicEntriesVc, next_dynamic::NextDynamicEntries,
next_server::{get_server_chunking_context, get_server_compile_time_info}, next_server::{get_server_chunking_context, get_server_compile_time_info},
url_node::get_sorted_routes, url_node::get_sorted_routes,
{self},
}; };
use serde::Serialize; use serde::Serialize;
use turbo_tasks::{ use turbo_tasks::{
graph::{AdjacencyMap, GraphTraversal}, graph::{AdjacencyMap, GraphTraversal},
CollectiblesSource, CompletionVc, CompletionsVc, RawVc, TransientInstance, TransientValue, Completion, Completions, TransientInstance, TransientValue, TryJoinIterExt, Vc,
TryJoinIterExt,
}; };
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{ turbo::tasks_fs::{rebase, DiskFileSystem, FileContent, FileSystem, FileSystemPath},
rebase, DiskFileSystemVc, FileContent, FileSystem, FileSystemPath, FileSystemPathVc,
FileSystemVc,
},
turbopack::{ turbopack::{
build::BuildChunkingContextVc, build::BuildChunkingContext,
cli_utils::issue::{ConsoleUiVc, LogOptions}, cli_utils::issue::{ConsoleUi, LogOptions},
core::{ core::{
asset::{Asset, AssetVc, AssetsVc}, asset::{Asset, Assets},
chunk::ChunkingContext, chunk::ChunkingContext,
environment::ServerAddrVc, environment::ServerAddr,
issue::{IssueReporter, IssueReporterVc, IssueSeverity, IssueVc}, issue::{IssueContextExt, IssueReporter, IssueSeverity},
output::{OutputAssetVc, OutputAssetsVc}, output::{OutputAsset, OutputAssets},
reference::AssetReference, reference::AssetReference,
virtual_fs::VirtualFileSystemVc, virtual_fs::VirtualFileSystem,
}, },
dev::DevChunkingContextVc, dev::DevChunkingContext,
ecmascript::utils::StringifyJs, ecmascript::utils::StringifyJs,
env::dotenv::load_env, env::dotenv::load_env,
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::evaluate_context::node_build_environment, turbopack::evaluate_context::node_build_environment,
}, },
}; };
@ -62,7 +58,7 @@ use crate::{
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Result<CompletionVc> { pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Result<Vc<Completion>> {
let project_root = options let project_root = options
.dir .dir
.as_ref() .as_ref()
@ -84,7 +80,8 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
}; };
let browserslist_query = "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \ let browserslist_query = "last 1 Chrome versions, last 1 Firefox versions, last 1 Safari \
versions, last 1 Edge versions"; versions, last 1 Edge versions"
.to_string();
let log_options = LogOptions { let log_options = LogOptions {
project_dir: PathBuf::from(project_root.clone()), project_dir: PathBuf::from(project_root.clone()),
@ -94,47 +91,48 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
log_level: options.log_level.unwrap_or(IssueSeverity::Warning), log_level: options.log_level.unwrap_or(IssueSeverity::Warning),
}; };
let issue_reporter: IssueReporterVc = let issue_reporter: Vc<Box<dyn IssueReporter>> =
ConsoleUiVc::new(TransientInstance::new(log_options)).into(); Vc::upcast(ConsoleUi::new(TransientInstance::new(log_options)));
let node_fs = node_fs(&project_root, issue_reporter); let node_fs = node_fs(project_root.clone(), issue_reporter);
let node_root = node_fs.root().join(".next"); let node_root = node_fs.root().join(".next".to_string());
let client_fs = client_fs(&project_root, issue_reporter); let client_fs = client_fs(project_root.clone(), issue_reporter);
let client_root = client_fs.root().join(".next"); let client_root = client_fs.root().join(".next".to_string());
// TODO(alexkirsz) This should accept a URL for assetPrefix. // TODO(alexkirsz) This should accept a URL for assetPrefix.
// let client_public_fs = VirtualFileSystemVc::new(); // let client_public_fs = VirtualFileSystem::new();
// let client_public_root = client_public_fs.root(); // let client_public_root = client_public_fs.root();
let workspace_fs = workspace_fs(&workspace_root, issue_reporter); let workspace_fs = workspace_fs(workspace_root.clone(), issue_reporter);
let project_relative = project_root.strip_prefix(&workspace_root).unwrap(); let project_relative = project_root.strip_prefix(&workspace_root).unwrap();
let project_relative = project_relative let project_relative = project_relative
.strip_prefix(MAIN_SEPARATOR) .strip_prefix(MAIN_SEPARATOR)
.unwrap_or(project_relative) .unwrap_or(project_relative)
.replace(MAIN_SEPARATOR, "/"); .replace(MAIN_SEPARATOR, "/");
let project_root = workspace_fs.root().join(&project_relative); let project_root = workspace_fs.root().join(project_relative);
let node_root_ref = node_root.await?; let node_root_ref = node_root.await?;
let node_execution_chunking_context = DevChunkingContextVc::builder( let node_execution_chunking_context = Vc::upcast(
project_root, DevChunkingContext::builder(
node_root, project_root,
node_root.join("chunks"), node_root,
node_root.join("assets"), node_root.join("chunks".to_string()),
node_build_environment(), node_root.join("assets".to_string()),
) node_build_environment(),
.build() )
.into(); .build(),
);
let env = load_env(project_root); let env = load_env(project_root);
let execution_context = let execution_context =
ExecutionContextVc::new(project_root, node_execution_chunking_context, env); ExecutionContext::new(project_root, node_execution_chunking_context, env);
let next_config = load_next_config(execution_context.with_layer("next_config")); let next_config = load_next_config(execution_context.with_layer("next_config".to_string()));
let mode = NextMode::Build; let mode = NextMode::Build;
let client_compile_time_info = get_client_compile_time_info(mode, browserslist_query); let client_compile_time_info = get_client_compile_time_info(mode, browserslist_query);
let server_compile_time_info = get_server_compile_time_info(mode, env, ServerAddrVc::empty()); let server_compile_time_info = get_server_compile_time_info(mode, env, ServerAddr::empty());
// TODO(alexkirsz) Pages should build their own routes, outside of a FS. // TODO(alexkirsz) Pages should build their own routes, outside of a FS.
let next_router_fs = VirtualFileSystemVc::new().as_file_system(); let next_router_fs = Vc::upcast::<Box<dyn FileSystem>>(VirtualFileSystem::new());
let next_router_root = next_router_fs.root(); let next_router_root = next_router_fs.root();
let page_entries = get_page_entries( let page_entries = get_page_entries(
next_router_root, next_router_root,
@ -169,12 +167,8 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
.try_join() .try_join()
.await?; .await?;
let app_client_references_by_entry = ClientReferencesByEntryVc::new(AssetsVc::cell( let app_client_references_by_entry = ClientReferencesByEntry::new(Vc::cell(
app_rsc_entries app_rsc_entries.iter().copied().map(Vc::upcast).collect(),
.iter()
.copied()
.map(|entry| entry.into())
.collect(),
)) ))
.await?; .await?;
@ -228,12 +222,8 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
.collect(); .collect();
// TODO(alexkirsz) Handle dynamic entries and dynamic chunks. // TODO(alexkirsz) Handle dynamic entries and dynamic chunks.
let _dynamic_entries = NextDynamicEntriesVc::from_entries(AssetsVc::cell( let _dynamic_entries = NextDynamicEntries::from_entries(Vc::cell(
all_node_entries all_node_entries.iter().copied().map(Vc::upcast).collect(),
.iter()
.copied()
.map(|entry| entry.into())
.collect(),
)) ))
.await?; .await?;
@ -258,11 +248,11 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
); );
// TODO(alexkirsz) This should be the same chunking context. The layer should // TODO(alexkirsz) This should be the same chunking context. The layer should
// be applied on the AssetContext level instead. // be applied on the AssetContext level instead.
let rsc_chunking_context = server_chunking_context.with_layer("rsc"); let rsc_chunking_context = server_chunking_context.with_layer("rsc".to_string());
let ssr_chunking_context = server_chunking_context.with_layer("ssr"); let ssr_chunking_context = server_chunking_context.with_layer("ssr".to_string());
let (Some(rsc_chunking_context), Some(ssr_chunking_context)) = ( let (Some(rsc_chunking_context), Some(ssr_chunking_context)) = (
BuildChunkingContextVc::resolve_from(rsc_chunking_context).await?, Vc::try_resolve_downcast_type::<BuildChunkingContext>(rsc_chunking_context).await?,
BuildChunkingContextVc::resolve_from(ssr_chunking_context).await?, Vc::try_resolve_downcast_type::<BuildChunkingContext>(ssr_chunking_context).await?,
) else { ) else {
bail!("with_layer should not change the type of the chunking context"); bail!("with_layer should not change the type of the chunking context");
}; };
@ -270,18 +260,18 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
let mut all_chunks = vec![]; let mut all_chunks = vec![];
let mut build_manifest: BuildManifest = Default::default(); let mut build_manifest: BuildManifest = Default::default();
let build_manifest_path = client_root.join("build-manifest.json"); let build_manifest_path = client_root.join("build-manifest.json".to_string());
// This ensures that the _next prefix is properly stripped from all client paths // This ensures that the _next prefix is properly stripped from all client paths
// in manifests. It will be added back on the client through the chunk_base_path // in manifests. It will be added back on the client through the chunk_base_path
// mechanism. // mechanism.
let client_relative_path = client_root.join("_next"); let client_relative_path = client_root.join("_next".to_string());
let client_relative_path_ref = client_relative_path.await?; let client_relative_path_ref = client_relative_path.await?;
// PAGE CHUNKING // PAGE CHUNKING
let mut pages_manifest: PagesManifest = Default::default(); let mut pages_manifest: PagesManifest = Default::default();
let pages_manifest_path = node_root.join("server/pages-manifest.json"); let pages_manifest_path = node_root.join("server/pages-manifest.json".to_string());
let pages_manifest_dir_path = pages_manifest_path.parent().await?; let pages_manifest_dir_path = pages_manifest_path.parent().await?;
compute_page_entries_chunks( compute_page_entries_chunks(
@ -300,10 +290,10 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
// APP CHUNKING // APP CHUNKING
let mut app_build_manifest = AppBuildManifest::default(); let mut app_build_manifest = AppBuildManifest::default();
let app_build_manifest_path = client_root.join("app-build-manifest.json"); let app_build_manifest_path = client_root.join("app-build-manifest.json".to_string());
let mut app_paths_manifest = AppPathsManifest::default(); let mut app_paths_manifest = AppPathsManifest::default();
let app_paths_manifest_path = node_root.join("server/app-paths-manifest.json"); let app_paths_manifest_path = node_root.join("server/app-paths-manifest.json".to_string());
let app_paths_manifest_dir_path = app_paths_manifest_path.parent().await?; let app_paths_manifest_dir_path = app_paths_manifest_path.parent().await?;
// APP CLIENT REFERENCES CHUNKING // APP CLIENT REFERENCES CHUNKING
@ -325,7 +315,7 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
&app_client_references_chunks, &app_client_references_chunks,
rsc_chunking_context, rsc_chunking_context,
client_chunking_context, client_chunking_context,
ssr_chunking_context.into(), Vc::upcast(ssr_chunking_context),
node_root, node_root,
&client_relative_path_ref, &client_relative_path_ref,
&app_paths_manifest_dir_path, &app_paths_manifest_dir_path,
@ -343,7 +333,7 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
let ssg_manifest_path = format!("static/{build_id}/_ssgManifest.js"); let ssg_manifest_path = format!("static/{build_id}/_ssgManifest.js");
let ssg_manifest_fs_path = node_root.join(&ssg_manifest_path); let ssg_manifest_fs_path = node_root.join(ssg_manifest_path.clone());
completions.push( completions.push(
ssg_manifest_fs_path.write( ssg_manifest_fs_path.write(
FileContent::Content( FileContent::Content(
@ -393,7 +383,7 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
let client_manifest_path = format!("static/{build_id}/_buildManifest.js"); let client_manifest_path = format!("static/{build_id}/_buildManifest.js");
let client_manifest_fs_path = node_root.join(&client_manifest_path); let client_manifest_fs_path = node_root.join(client_manifest_path.clone());
completions.push( completions.push(
client_manifest_fs_path.write( client_manifest_fs_path.write(
FileContent::Content( FileContent::Content(
@ -422,23 +412,23 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
// experimental-edge pages? // experimental-edge pages?
completions.push(write_manifest( completions.push(write_manifest(
MiddlewaresManifest::default(), MiddlewaresManifest::default(),
node_root.join("server/middleware-manifest.json"), node_root.join("server/middleware-manifest.json".to_string()),
)?); )?);
completions.push(write_manifest( completions.push(write_manifest(
NextFontManifest::default(), NextFontManifest::default(),
node_root.join("server/next-font-manifest.json"), node_root.join("server/next-font-manifest.json".to_string()),
)?); )?);
completions.push(write_manifest( completions.push(write_manifest(
FontManifest::default(), FontManifest::default(),
node_root.join("server/font-manifest.json"), node_root.join("server/font-manifest.json".to_string()),
)?); )?);
completions.push(write_manifest( completions.push(write_manifest(
ServerReferenceManifest::default(), ServerReferenceManifest::default(),
node_root.join("server/server-reference-manifest.json"), node_root.join("server/server-reference-manifest.json".to_string()),
)?); )?);
completions.push(write_manifest( completions.push(write_manifest(
ReactLoadableManifest::default(), ReactLoadableManifest::default(),
node_root.join("react-loadable-manifest.json"), node_root.join("react-loadable-manifest.json".to_string()),
)?); )?);
completions.push( completions.push(
@ -451,45 +441,49 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
.await?, .await?,
); );
Ok(CompletionsVc::all(completions)) Ok(Completions::all(completions))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn workspace_fs( async fn workspace_fs(
workspace_root: &str, workspace_root: String,
issue_reporter: IssueReporterVc, issue_reporter: Vc<Box<dyn IssueReporter>>,
) -> Result<FileSystemVc> { ) -> Result<Vc<Box<dyn FileSystem>>> {
let disk_fs = DiskFileSystemVc::new("workspace".to_string(), workspace_root.to_string()); let disk_fs = DiskFileSystem::new("workspace".to_string(), workspace_root.to_string());
handle_issues(disk_fs, issue_reporter).await?; handle_issues(disk_fs, issue_reporter).await?;
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn node_fs(node_root: &str, issue_reporter: IssueReporterVc) -> Result<FileSystemVc> { async fn node_fs(
let disk_fs = DiskFileSystemVc::new("node".to_string(), node_root.to_string()); node_root: String,
issue_reporter: Vc<Box<dyn IssueReporter>>,
) -> Result<Vc<Box<dyn FileSystem>>> {
let disk_fs = DiskFileSystem::new("node".to_string(), node_root.to_string());
handle_issues(disk_fs, issue_reporter).await?; handle_issues(disk_fs, issue_reporter).await?;
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn client_fs(client_root: &str, issue_reporter: IssueReporterVc) -> Result<FileSystemVc> { async fn client_fs(
let disk_fs = DiskFileSystemVc::new("client".to_string(), client_root.to_string()); client_root: String,
issue_reporter: Vc<Box<dyn IssueReporter>>,
) -> Result<Vc<Box<dyn FileSystem>>> {
let disk_fs = DiskFileSystem::new("client".to_string(), client_root.to_string());
handle_issues(disk_fs, issue_reporter).await?; handle_issues(disk_fs, issue_reporter).await?;
Ok(disk_fs.into()) Ok(Vc::upcast(disk_fs))
} }
async fn handle_issues<T: Into<RawVc> + CollectiblesSource + Copy>( async fn handle_issues<T>(source: Vc<T>, issue_reporter: Vc<Box<dyn IssueReporter>>) -> Result<()> {
source: T, let issues = source
issue_reporter: IssueReporterVc, .peek_issues_with_path()
) -> Result<()> {
let issues = IssueVc::peek_issues_with_path(source)
.await? .await?
.strongly_consistent() .strongly_consistent()
.await?; .await?;
let has_fatal = issue_reporter.report_issues( let has_fatal = issue_reporter.report_issues(
TransientInstance::new(issues.clone()), TransientInstance::new(issues.clone()),
TransientValue::new(source.into()), TransientValue::new(source.node),
); );
if *has_fatal.await? { if *has_fatal.await? {
@ -502,31 +496,31 @@ async fn handle_issues<T: Into<RawVc> + CollectiblesSource + Copy>(
/// Emits all assets transitively reachable from the given chunks, that are /// Emits all assets transitively reachable from the given chunks, that are
/// inside the node root or the client root. /// inside the node root or the client root.
async fn emit_all_assets( async fn emit_all_assets(
chunks: Vec<OutputAssetVc>, chunks: Vec<Vc<Box<dyn OutputAsset>>>,
node_root: &FileSystemPath, node_root: &FileSystemPath,
client_relative_path: FileSystemPathVc, client_relative_path: Vc<FileSystemPath>,
client_output_path: FileSystemPathVc, client_output_path: Vc<FileSystemPath>,
) -> Result<CompletionVc> { ) -> Result<Vc<Completion>> {
let all_assets = all_assets_from_entries(OutputAssetsVc::cell(chunks)).await?; let all_assets = all_assets_from_entries(Vc::cell(chunks)).await?;
Ok(CompletionsVc::all( Ok(Completions::all(
all_assets all_assets
.iter() .iter()
.copied() .copied()
.map(|asset| async move { .map(|asset| async move {
if asset.ident().path().await?.is_inside(node_root) { if asset.ident().path().await?.is_inside_ref(node_root) {
return Ok(emit(asset)); return Ok(emit(asset));
} else if asset } else if asset
.ident() .ident()
.path() .path()
.await? .await?
.is_inside(&*client_relative_path.await?) .is_inside_ref(&*client_relative_path.await?)
{ {
// Client assets are emitted to the client output path, which is prefixed with // Client assets are emitted to the client output path, which is prefixed with
// _next. We need to rebase them to remove that prefix. // _next. We need to rebase them to remove that prefix.
return Ok(emit_rebase(asset, client_relative_path, client_output_path)); return Ok(emit_rebase(asset, client_relative_path, client_output_path));
} }
Ok(CompletionVc::immutable()) Ok(Completion::immutable())
}) })
.try_join() .try_join()
.await?, .await?,
@ -534,12 +528,16 @@ async fn emit_all_assets(
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn emit(asset: AssetVc) -> CompletionVc { fn emit(asset: Vc<Box<dyn Asset>>) -> Vc<Completion> {
asset.content().write(asset.ident().path()) asset.content().write(asset.ident().path())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn emit_rebase(asset: AssetVc, from: FileSystemPathVc, to: FileSystemPathVc) -> CompletionVc { fn emit_rebase(
asset: Vc<Box<dyn Asset>>,
from: Vc<FileSystemPath>,
to: Vc<FileSystemPath>,
) -> Vc<Completion> {
asset asset
.content() .content()
.write(rebase(asset.ident().path(), from, to)) .write(rebase(asset.ident().path(), from, to))
@ -548,12 +546,12 @@ fn emit_rebase(asset: AssetVc, from: FileSystemPathVc, to: FileSystemPathVc) ->
/// Walks the asset graph from multiple assets and collect all referenced /// Walks the asset graph from multiple assets and collect all referenced
/// assets. /// assets.
#[turbo_tasks::function] #[turbo_tasks::function]
async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<AssetsVc> { async fn all_assets_from_entries(entries: Vc<OutputAssets>) -> Result<Vc<Assets>> {
Ok(AssetsVc::cell( Ok(Vc::cell(
AdjacencyMap::new() AdjacencyMap::new()
.skip_duplicates() .skip_duplicates()
.visit( .visit(
entries.await?.iter().copied().map(Into::into), entries.await?.iter().copied().map(Vc::upcast),
get_referenced_assets, get_referenced_assets,
) )
.await .await
@ -565,7 +563,9 @@ async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<AssetsVc> {
} }
/// Computes the list of all chunk children of a given chunk. /// Computes the list of all chunk children of a given chunk.
async fn get_referenced_assets(asset: AssetVc) -> Result<impl Iterator<Item = AssetVc> + Send> { async fn get_referenced_assets(
asset: Vc<Box<dyn Asset>>,
) -> Result<impl Iterator<Item = Vc<Box<dyn Asset>>> + Send> {
Ok(asset Ok(asset
.references() .references()
.await? .await?
@ -582,7 +582,7 @@ async fn get_referenced_assets(asset: AssetVc) -> Result<impl Iterator<Item = As
/// Writes a manifest to disk. This consumes the manifest to ensure we don't /// Writes a manifest to disk. This consumes the manifest to ensure we don't
/// write to it afterwards. /// write to it afterwards.
fn write_manifest<T>(manifest: T, manifest_path: FileSystemPathVc) -> Result<CompletionVc> fn write_manifest<T>(manifest: T, manifest_path: Vc<FileSystemPath>) -> Result<Vc<Completion>>
where where
T: Serialize, T: Serialize,
{ {

View file

@ -6,45 +6,38 @@ use next_core::{
get_client_module_options_context, get_client_resolve_options_context, get_client_module_options_context, get_client_resolve_options_context,
get_client_runtime_entries, ClientContextType, get_client_runtime_entries, ClientContextType,
}, },
next_config::NextConfigVc, next_config::NextConfig,
next_dynamic::NextDynamicTransitionVc, next_dynamic::NextDynamicTransition,
next_server::{ next_server::{
get_server_module_options_context, get_server_resolve_options_context, get_server_module_options_context, get_server_resolve_options_context,
get_server_runtime_entries, ServerContextType, get_server_runtime_entries, ServerContextType,
}, },
pages_structure::{ pages_structure::{
find_pages_structure, PagesDirectoryStructure, PagesDirectoryStructureVc, PagesStructure, find_pages_structure, PagesDirectoryStructure, PagesStructure, PagesStructureItem,
PagesStructureItem, PagesStructureVc,
}, },
pathname_for_path, PathType, pathname_for_path, PathType,
}; };
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{tasks::Value, tasks_env::ProcessEnv, tasks_fs::FileSystemPath},
tasks::{primitives::StringVc, Value},
tasks_env::ProcessEnvVc,
tasks_fs::{FileSystemPath, FileSystemPathVc},
},
turbopack::{ turbopack::{
build::BuildChunkingContextVc, build::BuildChunkingContext,
core::{ core::{
asset::Asset, asset::Asset,
chunk::{ChunkableModule, ChunkingContext, EvaluatableAssetsVc}, chunk::{ChunkableModule, ChunkingContext, EvaluatableAssets},
compile_time_info::CompileTimeInfoVc, compile_time_info::CompileTimeInfo,
context::{AssetContext, AssetContextVc}, context::AssetContext,
file_source::FileSourceVc, file_source::FileSource,
output::OutputAssetVc, output::OutputAsset,
reference_type::{EntryReferenceSubType, ReferenceType}, reference_type::{EntryReferenceSubType, ReferenceType},
source::SourceVc, source::Source,
}, },
ecmascript::{ ecmascript::{
chunk::{EcmascriptChunkPlaceableVc, EcmascriptChunkingContextVc}, chunk::{EcmascriptChunkPlaceable, EcmascriptChunkingContext},
EcmascriptModuleAssetVc, EcmascriptModuleAsset,
},
node::execution_context::ExecutionContextVc,
turbopack::{
transition::{ContextTransitionVc, TransitionsByNameVc},
ModuleAssetContextVc,
}, },
node::execution_context::ExecutionContext,
turbopack::{transition::ContextTransition, ModuleAssetContext},
}, },
}; };
@ -52,22 +45,22 @@ use crate::manifests::{BuildManifest, PagesManifest};
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct PageEntries { pub struct PageEntries {
pub entries: Vec<PageEntryVc>, pub entries: Vec<Vc<PageEntry>>,
pub ssr_runtime_entries: EvaluatableAssetsVc, pub ssr_runtime_entries: Vc<EvaluatableAssets>,
pub client_runtime_entries: EvaluatableAssetsVc, pub client_runtime_entries: Vc<EvaluatableAssets>,
} }
/// Computes all the page entries within the given project root. /// Computes all the page entries within the given project root.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_page_entries( pub async fn get_page_entries(
next_router_root: FileSystemPathVc, next_router_root: Vc<FileSystemPath>,
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
env: ProcessEnvVc, env: Vc<Box<dyn ProcessEnv>>,
client_compile_time_info: CompileTimeInfoVc, client_compile_time_info: Vc<CompileTimeInfo>,
server_compile_time_info: CompileTimeInfoVc, server_compile_time_info: Vc<CompileTimeInfo>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<PageEntriesVc> { ) -> Result<Vc<PageEntries>> {
let pages_structure = find_pages_structure( let pages_structure = find_pages_structure(
project_root, project_root,
next_router_root, next_router_root,
@ -77,7 +70,7 @@ pub async fn get_page_entries(
let pages_dir = if let Some(pages) = pages_structure.await?.pages { let pages_dir = if let Some(pages) = pages_structure.await?.pages {
pages.project_path().resolve().await? pages.project_path().resolve().await?
} else { } else {
project_root.join("pages") project_root.join("pages".to_string())
}; };
let mode = NextMode::Build; let mode = NextMode::Build;
@ -102,28 +95,27 @@ pub async fn get_page_entries(
execution_context, execution_context,
); );
let client_transition = ContextTransitionVc::new( let client_transition = ContextTransition::new(
client_compile_time_info, client_compile_time_info,
client_module_options_context, client_module_options_context,
client_resolve_options_context, client_resolve_options_context,
); );
let transitions = TransitionsByNameVc::cell( let transitions = Vc::cell(
[( [(
"next-dynamic".to_string(), "next-dynamic".to_string(),
NextDynamicTransitionVc::new(client_transition).into(), Vc::upcast(NextDynamicTransition::new(client_transition)),
)] )]
.into_iter() .into_iter()
.collect(), .collect(),
); );
let client_module_context: AssetContextVc = ModuleAssetContextVc::new( let client_module_context: Vc<Box<dyn AssetContext>> = Vc::upcast(ModuleAssetContext::new(
transitions, transitions,
client_compile_time_info, client_compile_time_info,
client_module_options_context, client_module_options_context,
client_resolve_options_context, client_resolve_options_context,
) ));
.into();
let client_runtime_entries = get_client_runtime_entries( let client_runtime_entries = get_client_runtime_entries(
project_root, project_root,
@ -150,13 +142,12 @@ pub async fn get_page_entries(
next_config, next_config,
); );
let ssr_module_context = ModuleAssetContextVc::new( let ssr_module_context = Vc::upcast(ModuleAssetContext::new(
transitions, transitions,
server_compile_time_info, server_compile_time_info,
ssr_module_options_context, ssr_module_options_context,
ssr_resolve_options_context, ssr_resolve_options_context,
) ));
.into();
let ssr_runtime_entries = let ssr_runtime_entries =
get_server_runtime_entries(project_root, env, ssr_ty, mode, next_config); get_server_runtime_entries(project_root, env, ssr_ty, mode, next_config);
@ -179,11 +170,11 @@ pub async fn get_page_entries(
} }
async fn get_page_entries_for_root_directory( async fn get_page_entries_for_root_directory(
ssr_module_context: AssetContextVc, ssr_module_context: Vc<Box<dyn AssetContext>>,
client_module_context: AssetContextVc, client_module_context: Vc<Box<dyn AssetContext>>,
pages_structure: PagesStructureVc, pages_structure: Vc<PagesStructure>,
next_router_root: FileSystemPathVc, next_router_root: Vc<FileSystemPath>,
) -> Result<Vec<PageEntryVc>> { ) -> Result<Vec<Vc<PageEntry>>> {
let PagesStructure { let PagesStructure {
app, app,
document, document,
@ -199,7 +190,7 @@ async fn get_page_entries_for_root_directory(
entries.push(get_page_entry_for_file( entries.push(get_page_entry_for_file(
ssr_module_context, ssr_module_context,
client_module_context, client_module_context,
FileSourceVc::new(app.project_path).into(), Vc::upcast(FileSource::new(app.project_path)),
next_router_root, next_router_root,
app.next_router_path, app.next_router_path,
)); ));
@ -209,7 +200,7 @@ async fn get_page_entries_for_root_directory(
entries.push(get_page_entry_for_file( entries.push(get_page_entry_for_file(
ssr_module_context, ssr_module_context,
client_module_context, client_module_context,
FileSourceVc::new(document.project_path).into(), Vc::upcast(FileSource::new(document.project_path)),
next_router_root, next_router_root,
document.next_router_path, document.next_router_path,
)); ));
@ -220,7 +211,7 @@ async fn get_page_entries_for_root_directory(
entries.push(get_page_entry_for_file( entries.push(get_page_entry_for_file(
ssr_module_context, ssr_module_context,
client_module_context, client_module_context,
FileSourceVc::new(error.project_path).into(), Vc::upcast(FileSource::new(error.project_path)),
next_router_root, next_router_root,
error.next_router_path, error.next_router_path,
)); ));
@ -252,11 +243,11 @@ async fn get_page_entries_for_root_directory(
#[async_recursion::async_recursion] #[async_recursion::async_recursion]
async fn get_page_entries_for_directory( async fn get_page_entries_for_directory(
ssr_module_context: AssetContextVc, ssr_module_context: Vc<Box<dyn AssetContext>>,
client_module_context: AssetContextVc, client_module_context: Vc<Box<dyn AssetContext>>,
pages_structure: PagesDirectoryStructureVc, pages_structure: Vc<PagesDirectoryStructure>,
next_router_root: FileSystemPathVc, next_router_root: Vc<FileSystemPath>,
entries: &mut Vec<PageEntryVc>, entries: &mut Vec<Vc<PageEntry>>,
) -> Result<()> { ) -> Result<()> {
let PagesDirectoryStructure { let PagesDirectoryStructure {
ref items, ref items,
@ -273,7 +264,7 @@ async fn get_page_entries_for_directory(
entries.push(get_page_entry_for_file( entries.push(get_page_entry_for_file(
ssr_module_context, ssr_module_context,
client_module_context, client_module_context,
FileSourceVc::new(project_path).into(), Vc::upcast(FileSource::new(project_path)),
next_router_root, next_router_root,
next_router_path, next_router_path,
)); ));
@ -297,21 +288,21 @@ async fn get_page_entries_for_directory(
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct PageEntry { pub struct PageEntry {
/// The pathname of the page. /// The pathname of the page.
pub pathname: StringVc, pub pathname: Vc<String>,
/// The Node.js SSR entry module asset. /// The Node.js SSR entry module asset.
pub ssr_module: EcmascriptChunkPlaceableVc, pub ssr_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
/// The client entry module asset. /// The client entry module asset.
pub client_module: EcmascriptModuleAssetVc, pub client_module: Vc<EcmascriptModuleAsset>,
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get_page_entry_for_file( async fn get_page_entry_for_file(
ssr_module_context: AssetContextVc, ssr_module_context: Vc<Box<dyn AssetContext>>,
client_module_context: AssetContextVc, client_module_context: Vc<Box<dyn AssetContext>>,
source: SourceVc, source: Vc<Box<dyn Source>>,
next_router_root: FileSystemPathVc, next_router_root: Vc<FileSystemPath>,
next_router_path: FileSystemPathVc, next_router_path: Vc<FileSystemPath>,
) -> Result<PageEntryVc> { ) -> Result<Vc<PageEntry>> {
let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page)); let reference_type = Value::new(ReferenceType::Entry(EntryReferenceSubType::Page));
let pathname = pathname_for_path(next_router_root, next_router_path, PathType::Page); let pathname = pathname_for_path(next_router_root, next_router_path, PathType::Page);
@ -320,11 +311,15 @@ async fn get_page_entry_for_file(
let client_module = create_page_loader_entry_module(client_module_context, source, pathname); let client_module = create_page_loader_entry_module(client_module_context, source, pathname);
let Some(client_module) = EcmascriptModuleAssetVc::resolve_from(client_module).await? else { let Some(client_module) =
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(client_module).await?
else {
bail!("expected an ECMAScript module asset"); bail!("expected an ECMAScript module asset");
}; };
let Some(ssr_module) = EcmascriptChunkPlaceableVc::resolve_from(ssr_module).await? else { let Some(ssr_module) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(ssr_module).await?
else {
bail!("expected an ECMAScript chunk placeable asset"); bail!("expected an ECMAScript chunk placeable asset");
}; };
@ -338,23 +333,23 @@ async fn get_page_entry_for_file(
/// Computes the pathname for a given path. /// Computes the pathname for a given path.
#[turbo_tasks::function] #[turbo_tasks::function]
async fn pathname_from_path(next_router_path: FileSystemPathVc) -> Result<StringVc> { async fn pathname_from_path(next_router_path: Vc<FileSystemPath>) -> Result<Vc<String>> {
let pathname = next_router_path.await?; let pathname = next_router_path.await?;
Ok(StringVc::cell(pathname.path.clone())) Ok(Vc::cell(pathname.path.clone()))
} }
/// Computes the chunks of page entries, adds their paths to the corresponding /// Computes the chunks of page entries, adds their paths to the corresponding
/// manifests, and pushes the assets to the `all_chunks` vec. /// manifests, and pushes the assets to the `all_chunks` vec.
pub async fn compute_page_entries_chunks( pub async fn compute_page_entries_chunks(
page_entries: &PageEntries, page_entries: &PageEntries,
client_chunking_context: EcmascriptChunkingContextVc, client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
ssr_chunking_context: BuildChunkingContextVc, ssr_chunking_context: Vc<BuildChunkingContext>,
node_root: FileSystemPathVc, node_root: Vc<FileSystemPath>,
pages_manifest_dir_path: &FileSystemPath, pages_manifest_dir_path: &FileSystemPath,
client_relative_path: &FileSystemPath, client_relative_path: &FileSystemPath,
pages_manifest: &mut PagesManifest, pages_manifest: &mut PagesManifest,
build_manifest: &mut BuildManifest, build_manifest: &mut BuildManifest,
all_chunks: &mut Vec<OutputAssetVc>, all_chunks: &mut Vec<Vc<Box<dyn OutputAsset>>>,
) -> Result<()> { ) -> Result<()> {
for page_entry in page_entries.entries.iter() { for page_entry in page_entries.entries.iter() {
let page_entry = page_entry.await?; let page_entry = page_entry.await?;
@ -362,7 +357,7 @@ pub async fn compute_page_entries_chunks(
let asset_path: String = get_asset_path_from_pathname(&pathname, ".js"); let asset_path: String = get_asset_path_from_pathname(&pathname, ".js");
let ssr_entry_chunk = ssr_chunking_context.entry_chunk( let ssr_entry_chunk = ssr_chunking_context.entry_chunk(
node_root.join(&format!("server/pages/{asset_path}")), node_root.join(format!("server/pages/{asset_path}")),
page_entry.ssr_module, page_entry.ssr_module,
page_entries.ssr_runtime_entries, page_entries.ssr_runtime_entries,
); );
@ -377,13 +372,13 @@ pub async fn compute_page_entries_chunks(
let client_entry_chunk = page_entry let client_entry_chunk = page_entry
.client_module .client_module
.as_root_chunk(client_chunking_context.into()); .as_root_chunk(Vc::upcast(client_chunking_context));
let client_chunks = client_chunking_context.evaluated_chunk_group( let client_chunks = client_chunking_context.evaluated_chunk_group(
client_entry_chunk, client_entry_chunk,
page_entries page_entries
.client_runtime_entries .client_runtime_entries
.with_entry(page_entry.client_module.into()), .with_entry(Vc::upcast(page_entry.client_module)),
); );
let build_manifest_pages_entry = build_manifest let build_manifest_pages_entry = build_manifest

View file

@ -10,8 +10,8 @@
"check": "tsc --noEmit" "check": "tsc --noEmit"
}, },
"dependencies": { "dependencies": {
"@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230713.3", "@vercel/turbopack-ecmascript-runtime": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-ecmascript-runtime/js?turbopack-230716.2",
"@vercel/turbopack-node": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230713.3", "@vercel/turbopack-node": "https://gitpkg-fork.vercel.sh/vercel/turbo/crates/turbopack-node/js?turbopack-230716.2",
"anser": "^2.1.1", "anser": "^2.1.1",
"css.escape": "^1.5.1", "css.escape": "^1.5.1",
"next": "*", "next": "*",

View file

@ -1,14 +1,15 @@
use std::collections::HashMap; use std::collections::HashMap;
use turbopack_binding::turbo::tasks_fs::FileSystemPathVc; use turbo_tasks::Vc;
use turbopack_binding::turbo::tasks_fs::FileSystemPath;
pub mod next_server_component_transition; pub mod next_server_component_transition;
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct LayoutSegment { pub struct LayoutSegment {
pub files: HashMap<String, FileSystemPathVc>, pub files: HashMap<String, Vc<FileSystemPath>>,
pub target: FileSystemPathVc, pub target: Vc<FileSystemPath>,
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct LayoutSegments(Vec<LayoutSegmentVc>); pub struct LayoutSegments(Vec<Vc<LayoutSegment>>);

View file

@ -1,14 +1,13 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{compile_time_info::CompileTimeInfoVc, module::ModuleVc}, core::{compile_time_info::CompileTimeInfo, module::Module},
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{ turbopack::{
module_options::ModuleOptionsContextVc, module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext,
resolve_options_context::ResolveOptionsContextVc, transition::Transition, ModuleAssetContext,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}, },
}; };
@ -20,10 +19,10 @@ use crate::next_client_component::{
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextServerComponentTransition { pub struct NextServerComponentTransition {
pub rsc_compile_time_info: CompileTimeInfoVc, pub rsc_compile_time_info: Vc<CompileTimeInfo>,
pub rsc_module_options_context: ModuleOptionsContextVc, pub rsc_module_options_context: Vc<ModuleOptionsContext>,
pub rsc_resolve_options_context: ResolveOptionsContextVc, pub rsc_resolve_options_context: Vc<ResolveOptionsContext>,
pub server_root: FileSystemPathVc, pub server_root: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
@ -31,48 +30,52 @@ impl Transition for NextServerComponentTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_compile_time_info( fn process_compile_time_info(
&self, &self,
_compile_time_info: CompileTimeInfoVc, _compile_time_info: Vc<CompileTimeInfo>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
self.rsc_compile_time_info self.rsc_compile_time_info
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_module_options_context( fn process_module_options_context(
&self, &self,
_context: ModuleOptionsContextVc, _context: Vc<ModuleOptionsContext>,
) -> ModuleOptionsContextVc { ) -> Vc<ModuleOptionsContext> {
self.rsc_module_options_context self.rsc_module_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_resolve_options_context( fn process_resolve_options_context(
&self, &self,
_context: ResolveOptionsContextVc, _context: Vc<ResolveOptionsContext>,
) -> ResolveOptionsContextVc { ) -> Vc<ResolveOptionsContext> {
self.rsc_resolve_options_context self.rsc_resolve_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
&self, &self,
module: ModuleVc, module: Vc<Box<dyn Module>>,
_context: ModuleAssetContextVc, _context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let Some(asset) = EcmascriptChunkPlaceableVc::resolve_from(module).await? else { let Some(asset) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(module).await?
else {
bail!("Not an ecmascript module"); bail!("Not an ecmascript module");
}; };
Ok(WithChunkingContextScopeAsset { Ok(Vc::upcast(
asset: WithClientChunksAsset { WithChunkingContextScopeAsset {
asset, asset: Vc::upcast(
// next.js code already adds _next prefix WithClientChunksAsset {
server_root: self.server_root.join("_next"), asset,
// next.js code already adds _next prefix
server_root: self.server_root.join("_next".to_string()),
}
.cell(),
),
layer: "rsc".to_string(),
} }
.cell() .cell(),
.into(), ))
layer: "rsc".to_string(),
}
.cell()
.into())
} }
} }

View file

@ -7,28 +7,26 @@ use swc_core::{
common::{source_map::Pos, Span, Spanned}, common::{source_map::Pos, Span, Spanned},
ecma::ast::{Expr, Ident, Program}, ecma::ast::{Expr, Ident, Program},
}; };
use turbo_tasks::{primitives::StringVc, trace::TraceRawVcs, TryJoinIterExt}; use turbo_tasks::{trace::TraceRawVcs, TryJoinIterExt, ValueDefault, Vc};
use turbo_tasks_fs::FileSystemPathVc; use turbo_tasks_fs::FileSystemPath;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetVc}, asset::Asset,
context::{AssetContext, AssetContextVc}, context::AssetContext,
file_source::FileSourceVc, file_source::FileSource,
ident::AssetIdentVc, ident::AssetIdent,
issue::{ issue::{Issue, IssueExt, IssueSeverity, IssueSource, OptionIssueSource},
Issue, IssueSeverity, IssueSeverityVc, IssueSourceVc, IssueVc, OptionIssueSourceVc, module::Module,
},
module::ModuleVc,
reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType}, reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType},
}, },
ecmascript::{ ecmascript::{
analyzer::{graph::EvalContext, ConstantNumber, ConstantValue, JsValue}, analyzer::{graph::EvalContext, ConstantNumber, ConstantValue, JsValue},
parse::ParseResult, parse::ParseResult,
EcmascriptModuleAssetVc, EcmascriptModuleAsset,
}, },
}; };
use crate::{app_structure::LoaderTreeVc, util::NextRuntime}; use crate::{app_structure::LoaderTree, util::NextRuntime};
#[derive(Default, PartialEq, Eq, Clone, Copy, Debug, TraceRawVcs, Serialize, Deserialize)] #[derive(Default, PartialEq, Eq, Clone, Copy, Debug, TraceRawVcs, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
@ -75,9 +73,9 @@ pub struct NextSegmentConfig {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextSegmentConfigVc { impl ValueDefault for NextSegmentConfig {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn default() -> Self { pub fn value_default() -> Vc<Self> {
NextSegmentConfig::default().cell() NextSegmentConfig::default().cell()
} }
} }
@ -155,36 +153,36 @@ impl NextSegmentConfig {
/// An issue that occurred while parsing the app segment config. /// An issue that occurred while parsing the app segment config.
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextSegmentConfigParsingIssue { pub struct NextSegmentConfigParsingIssue {
ident: AssetIdentVc, ident: Vc<AssetIdent>,
detail: StringVc, detail: Vc<String>,
source: IssueSourceVc, source: Vc<IssueSource>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Issue for NextSegmentConfigParsingIssue { impl Issue for NextSegmentConfigParsingIssue {
#[turbo_tasks::function] #[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc { fn severity(&self) -> Vc<IssueSeverity> {
IssueSeverity::Warning.into() IssueSeverity::Warning.into()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn title(&self) -> StringVc { fn title(&self) -> Vc<String> {
StringVc::cell("Unable to parse config export in source file".to_string()) Vc::cell("Unable to parse config export in source file".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn category(&self) -> StringVc { fn category(&self) -> Vc<String> {
StringVc::cell("parsing".to_string()) Vc::cell("parsing".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc { fn context(&self) -> Vc<FileSystemPath> {
self.ident.path() self.ident.path()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn description(&self) -> StringVc { fn description(&self) -> Vc<String> {
StringVc::cell( Vc::cell(
"The exported configuration object in a source file need to have a very specific \ "The exported configuration object in a source file need to have a very specific \
format from which some properties can be statically parsed at compiled-time." format from which some properties can be statically parsed at compiled-time."
.to_string(), .to_string(),
@ -192,30 +190,32 @@ impl Issue for NextSegmentConfigParsingIssue {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn detail(&self) -> StringVc { fn detail(&self) -> Vc<String> {
self.detail self.detail
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn documentation_link(&self) -> StringVc { fn documentation_link(&self) -> Vc<String> {
StringVc::cell( Vc::cell(
"https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config" "https://nextjs.org/docs/app/api-reference/file-conventions/route-segment-config"
.to_string(), .to_string(),
) )
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn source(&self) -> OptionIssueSourceVc { fn source(&self) -> Vc<OptionIssueSource> {
OptionIssueSourceVc::some(self.source) OptionIssueSource::some(self.source)
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn parse_segment_config_from_source( pub async fn parse_segment_config_from_source(
module_asset: ModuleVc, module_asset: Vc<Box<dyn Module>>,
) -> Result<NextSegmentConfigVc> { ) -> Result<Vc<NextSegmentConfig>> {
let Some(ecmascript_asset) = EcmascriptModuleAssetVc::resolve_from(module_asset).await? else { let Some(ecmascript_asset) =
return Ok(NextSegmentConfigVc::default()); Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(module_asset).await?
else {
return Ok(Default::default());
}; };
let ParseResult::Ok { let ParseResult::Ok {
@ -224,7 +224,7 @@ pub async fn parse_segment_config_from_source(
.. ..
} = &*ecmascript_asset.parse().await? } = &*ecmascript_asset.parse().await?
else { else {
return Ok(NextSegmentConfigVc::default()); return Ok(Default::default());
}; };
let mut config = NextSegmentConfig::default(); let mut config = NextSegmentConfig::default();
@ -252,12 +252,12 @@ pub async fn parse_segment_config_from_source(
Ok(config.cell()) Ok(config.cell())
} }
fn issue_source(source: AssetVc, span: Span) -> IssueSourceVc { fn issue_source(source: Vc<Box<dyn Asset>>, span: Span) -> Vc<IssueSource> {
IssueSourceVc::from_byte_offset(source, span.lo.to_usize(), span.hi.to_usize()) IssueSource::from_byte_offset(source, span.lo.to_usize(), span.hi.to_usize())
} }
fn parse_config_value( fn parse_config_value(
module: ModuleVc, module: Vc<Box<dyn Module>>,
config: &mut NextSegmentConfig, config: &mut NextSegmentConfig,
ident: &Ident, ident: &Ident,
init: &Expr, init: &Expr,
@ -268,11 +268,10 @@ fn parse_config_value(
let (explainer, hints) = value.explain(2, 0); let (explainer, hints) = value.explain(2, 0);
NextSegmentConfigParsingIssue { NextSegmentConfigParsingIssue {
ident: module.ident(), ident: module.ident(),
detail: StringVc::cell(format!("{detail} Got {explainer}.{hints}")), detail: Vc::cell(format!("{detail} Got {explainer}.{hints}")),
source: issue_source(module.into(), span), source: issue_source(Vc::upcast(module), span),
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
}; };
@ -370,9 +369,9 @@ fn parse_config_value(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn parse_segment_config_from_loader_tree( pub async fn parse_segment_config_from_loader_tree(
loader_tree: LoaderTreeVc, loader_tree: Vc<LoaderTree>,
context: AssetContextVc, context: Vc<Box<dyn AssetContext>>,
) -> Result<NextSegmentConfigVc> { ) -> Result<Vc<NextSegmentConfig>> {
let loader_tree = loader_tree.await?; let loader_tree = loader_tree.await?;
let components = loader_tree.components.await?; let components = loader_tree.components.await?;
let mut config = NextSegmentConfig::default(); let mut config = NextSegmentConfig::default();
@ -392,7 +391,7 @@ pub async fn parse_segment_config_from_loader_tree(
{ {
config.apply_parent_config( config.apply_parent_config(
&*parse_segment_config_from_source(context.process( &*parse_segment_config_from_source(context.process(
FileSourceVc::new(component).into(), Vc::upcast(FileSource::new(component)),
turbo_tasks::Value::new(ReferenceType::EcmaScriptModules( turbo_tasks::Value::new(ReferenceType::EcmaScriptModules(
EcmaScriptModulesReferenceSubType::Undefined, EcmaScriptModulesReferenceSubType::Undefined,
)), )),

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,4 @@
use std::{ use std::collections::{BTreeMap, HashMap};
borrow::Cow,
collections::{BTreeMap, HashMap},
};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indexmap::{indexmap, map::Entry, IndexMap}; use indexmap::{indexmap, map::Entry, IndexMap};
@ -9,38 +6,36 @@ use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbo_tasks::{ use turbo_tasks::{
debug::ValueDebugFormat, debug::ValueDebugFormat, trace::TraceRawVcs, Completion, Completions, TaskInput, ValueToString,
primitives::{StringVc, StringsVc}, Vc,
trace::TraceRawVcs,
CompletionVc, CompletionsVc, TaskInput, ValueToString,
}; };
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPathVc}, turbo::tasks_fs::{DirectoryContent, DirectoryEntry, FileSystemEntryType, FileSystemPath},
turbopack::core::issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, turbopack::core::issue::{Issue, IssueExt, IssueSeverity},
}; };
use crate::next_config::NextConfigVc; use crate::next_config::NextConfig;
/// A final route in the app directory. /// A final route in the app directory.
#[turbo_tasks::value] #[turbo_tasks::value]
#[derive(Default, Debug, Clone)] #[derive(Default, Debug, Clone)]
pub struct Components { pub struct Components {
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub page: Option<FileSystemPathVc>, pub page: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub layout: Option<FileSystemPathVc>, pub layout: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<FileSystemPathVc>, pub error: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub loading: Option<FileSystemPathVc>, pub loading: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub template: Option<FileSystemPathVc>, pub template: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub not_found: Option<FileSystemPathVc>, pub not_found: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub default: Option<FileSystemPathVc>, pub default: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
pub route: Option<FileSystemPathVc>, pub route: Option<Vc<FileSystemPath>>,
#[serde(skip_serializing_if = "Metadata::is_empty")] #[serde(skip_serializing_if = "Metadata::is_empty")]
pub metadata: Metadata, pub metadata: Metadata,
} }
@ -76,13 +71,13 @@ impl Components {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ComponentsVc { impl Components {
/// Returns a completion that changes when any route in the components /// Returns a completion that changes when any route in the components
/// changes. /// changes.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn routes_changed(self) -> Result<CompletionVc> { pub async fn routes_changed(self: Vc<Self>) -> Result<Vc<Completion>> {
self.await?; self.await?;
Ok(CompletionVc::new()) Ok(Completion::new())
} }
} }
@ -90,19 +85,19 @@ impl ComponentsVc {
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)]
pub enum MetadataWithAltItem { pub enum MetadataWithAltItem {
Static { Static {
path: FileSystemPathVc, path: Vc<FileSystemPath>,
alt_path: Option<FileSystemPathVc>, alt_path: Option<Vc<FileSystemPath>>,
}, },
Dynamic { Dynamic {
path: FileSystemPathVc, path: Vc<FileSystemPath>,
}, },
} }
/// A single metadata file. /// A single metadata file.
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)] #[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, TraceRawVcs)]
pub enum MetadataItem { pub enum MetadataItem {
Static { path: FileSystemPathVc }, Static { path: Vc<FileSystemPath> },
Dynamic { path: FileSystemPathVc }, Dynamic { path: Vc<FileSystemPath> },
} }
/// Metadata file that can be placed in any segment of the app directory. /// Metadata file that can be placed in any segment of the app directory.
@ -184,16 +179,16 @@ impl GlobalMetadata {
#[derive(Debug)] #[derive(Debug)]
pub struct DirectoryTree { pub struct DirectoryTree {
/// key is e.g. "dashboard", "(dashboard)", "@slot" /// key is e.g. "dashboard", "(dashboard)", "@slot"
pub subdirectories: BTreeMap<String, DirectoryTreeVc>, pub subdirectories: BTreeMap<String, Vc<DirectoryTree>>,
pub components: ComponentsVc, pub components: Vc<Components>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl DirectoryTreeVc { impl DirectoryTree {
/// Returns a completion that changes when any route in the whole tree /// Returns a completion that changes when any route in the whole tree
/// changes. /// changes.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn routes_changed(self) -> Result<CompletionVc> { pub async fn routes_changed(self: Vc<Self>) -> Result<Vc<Completion>> {
let DirectoryTree { let DirectoryTree {
subdirectories, subdirectories,
components, components,
@ -203,54 +198,57 @@ impl DirectoryTreeVc {
for child in subdirectories.values() { for child in subdirectories.values() {
children.push(child.routes_changed()); children.push(child.routes_changed());
} }
Ok(CompletionsVc::cell(children).completed()) Ok(Vc::<Completions>::cell(children).completed())
} }
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct OptionAppDir(Option<FileSystemPathVc>); pub struct OptionAppDir(Option<Vc<FileSystemPath>>);
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl OptionAppDirVc { impl OptionAppDir {
/// Returns a completion that changes when any route in the whole tree /// Returns a completion that changes when any route in the whole tree
/// changes. /// changes.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn routes_changed(self, next_config: NextConfigVc) -> Result<CompletionVc> { pub async fn routes_changed(
self: Vc<Self>,
next_config: Vc<NextConfig>,
) -> Result<Vc<Completion>> {
if let Some(app_dir) = *self.await? { if let Some(app_dir) = *self.await? {
let directory_tree = get_directory_tree(app_dir, next_config.page_extensions()); let directory_tree = get_directory_tree(app_dir, next_config.page_extensions());
directory_tree.routes_changed().await?; directory_tree.routes_changed().await?;
} }
Ok(CompletionVc::new()) Ok(Completion::new())
} }
} }
/// Finds and returns the [DirectoryTree] of the app directory if existing. /// Finds and returns the [DirectoryTree] of the app directory if existing.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn find_app_dir(project_path: FileSystemPathVc) -> Result<OptionAppDirVc> { pub async fn find_app_dir(project_path: Vc<FileSystemPath>) -> Result<Vc<OptionAppDir>> {
let app = project_path.join("app"); let app = project_path.join("app".to_string());
let src_app = project_path.join("src/app"); let src_app = project_path.join("src/app".to_string());
let app_dir = if *app.get_type().await? == FileSystemEntryType::Directory { let app_dir = if *app.get_type().await? == FileSystemEntryType::Directory {
app app
} else if *src_app.get_type().await? == FileSystemEntryType::Directory { } else if *src_app.get_type().await? == FileSystemEntryType::Directory {
src_app src_app
} else { } else {
return Ok(OptionAppDirVc::cell(None)); return Ok(Vc::cell(None));
} }
.resolve() .resolve()
.await?; .await?;
Ok(OptionAppDirVc::cell(Some(app_dir))) Ok(Vc::cell(Some(app_dir)))
} }
/// Finds and returns the [DirectoryTree] of the app directory if enabled and /// Finds and returns the [DirectoryTree] of the app directory if enabled and
/// existing. /// existing.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn find_app_dir_if_enabled( pub async fn find_app_dir_if_enabled(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<OptionAppDirVc> { ) -> Result<Vc<OptionAppDir>> {
if !*next_config.app_dir().await? { if !*next_config.app_dir().await? {
return Ok(OptionAppDirVc::cell(None)); return Ok(Vc::cell(None));
} }
Ok(find_app_dir(project_path)) Ok(find_app_dir(project_path))
} }
@ -297,9 +295,9 @@ fn match_metadata_file<'a>(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get_directory_tree( async fn get_directory_tree(
dir: FileSystemPathVc, dir: Vc<FileSystemPath>,
page_extensions: StringsVc, page_extensions: Vc<Vec<String>>,
) -> Result<DirectoryTreeVc> { ) -> Result<Vc<DirectoryTree>> {
let DirectoryContent::Entries(entries) = &*dir.read_dir().await? else { let DirectoryContent::Entries(entries) = &*dir.read_dir().await? else {
bail!("{} must be a directory", dir.to_string().await?); bail!("{} must be a directory", dir.to_string().await?);
}; };
@ -367,7 +365,7 @@ async fn get_directory_tree(
let basename = file_name let basename = file_name
.rsplit_once('.') .rsplit_once('.')
.map_or(file_name, |(basename, _)| basename); .map_or(file_name, |(basename, _)| basename);
let alt_path = file.parent().join(&format!("{}.alt.txt", basename)); let alt_path = file.parent().join(format!("{}.alt.txt", basename));
let alt_path = let alt_path =
matches!(&*alt_path.get_type().await?, FileSystemEntryType::File) matches!(&*alt_path.get_type().await?, FileSystemEntryType::File)
.then_some(alt_path); .then_some(alt_path);
@ -416,16 +414,16 @@ async fn get_directory_tree(
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct LoaderTree { pub struct LoaderTree {
pub segment: String, pub segment: String,
pub parallel_routes: IndexMap<String, LoaderTreeVc>, pub parallel_routes: IndexMap<String, Vc<LoaderTree>>,
pub components: ComponentsVc, pub components: Vc<Components>,
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn merge_loader_trees( async fn merge_loader_trees(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
tree1: LoaderTreeVc, tree1: Vc<LoaderTree>,
tree2: LoaderTreeVc, tree2: Vc<LoaderTree>,
) -> Result<LoaderTreeVc> { ) -> Result<Vc<LoaderTree>> {
let tree1 = tree1.await?; let tree1 = tree1.await?;
let tree2 = tree2.await?; let tree2 = tree2.await?;
@ -463,8 +461,8 @@ async fn merge_loader_trees(
TaskInput, TaskInput,
)] )]
pub enum Entrypoint { pub enum Entrypoint {
AppPage { loader_tree: LoaderTreeVc }, AppPage { loader_tree: Vc<LoaderTree> },
AppRoute { path: FileSystemPathVc }, AppRoute { path: Vc<FileSystemPath> },
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
@ -479,10 +477,10 @@ fn match_parallel_route(name: &str) -> Option<&str> {
} }
async fn add_parallel_route( async fn add_parallel_route(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
result: &mut IndexMap<String, LoaderTreeVc>, result: &mut IndexMap<String, Vc<LoaderTree>>,
key: String, key: String,
loader_tree: LoaderTreeVc, loader_tree: Vc<LoaderTree>,
) -> Result<()> { ) -> Result<()> {
match result.entry(key) { match result.entry(key) {
Entry::Occupied(mut e) => { Entry::Occupied(mut e) => {
@ -499,10 +497,10 @@ async fn add_parallel_route(
} }
async fn add_app_page( async fn add_app_page(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
result: &mut IndexMap<String, Entrypoint>, result: &mut IndexMap<String, Entrypoint>,
key: String, key: String,
loader_tree: LoaderTreeVc, loader_tree: Vc<LoaderTree>,
) -> Result<()> { ) -> Result<()> {
match result.entry(key) { match result.entry(key) {
Entry::Occupied(mut e) => { Entry::Occupied(mut e) => {
@ -510,11 +508,10 @@ async fn add_app_page(
let Entrypoint::AppPage { loader_tree: value } = value else { let Entrypoint::AppPage { loader_tree: value } = value else {
DirectoryTreeIssue { DirectoryTreeIssue {
app_dir, app_dir,
message: StringVc::cell(format!("Conflicting route at {}", e.key())), message: Vc::cell(format!("Conflicting route at {}", e.key())),
severity: IssueSeverity::Error.cell(), severity: IssueSeverity::Error.cell(),
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
return Ok(()); return Ok(());
}; };
@ -530,20 +527,19 @@ async fn add_app_page(
} }
async fn add_app_route( async fn add_app_route(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
result: &mut IndexMap<String, Entrypoint>, result: &mut IndexMap<String, Entrypoint>,
key: String, key: String,
path: FileSystemPathVc, path: Vc<FileSystemPath>,
) -> Result<()> { ) -> Result<()> {
match result.entry(key) { match result.entry(key) {
Entry::Occupied(mut e) => { Entry::Occupied(mut e) => {
DirectoryTreeIssue { DirectoryTreeIssue {
app_dir, app_dir,
message: StringVc::cell(format!("Conflicting route at {}", e.key())), message: Vc::cell(format!("Conflicting route at {}", e.key())),
severity: IssueSeverity::Error.cell(), severity: IssueSeverity::Error.cell(),
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
*e.get_mut() = Entrypoint::AppRoute { path }; *e.get_mut() = Entrypoint::AppRoute { path };
} }
@ -555,25 +551,28 @@ async fn add_app_route(
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_entrypoints(app_dir: FileSystemPathVc, page_extensions: StringsVc) -> EntrypointsVc { pub fn get_entrypoints(
app_dir: Vc<FileSystemPath>,
page_extensions: Vc<Vec<String>>,
) -> Vc<Entrypoints> {
directory_tree_to_entrypoints(app_dir, get_directory_tree(app_dir, page_extensions)) directory_tree_to_entrypoints(app_dir, get_directory_tree(app_dir, page_extensions))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn directory_tree_to_entrypoints( fn directory_tree_to_entrypoints(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
directory_tree: DirectoryTreeVc, directory_tree: Vc<DirectoryTree>,
) -> EntrypointsVc { ) -> Vc<Entrypoints> {
directory_tree_to_entrypoints_internal(app_dir, "", directory_tree, "/") directory_tree_to_entrypoints_internal(app_dir, "".to_string(), directory_tree, "/".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn directory_tree_to_entrypoints_internal( async fn directory_tree_to_entrypoints_internal(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
directory_name: &str, directory_name: String,
directory_tree: DirectoryTreeVc, directory_tree: Vc<DirectoryTree>,
path_prefix: &str, path_prefix: String,
) -> Result<EntrypointsVc> { ) -> Result<Vc<Entrypoints>> {
let mut result = IndexMap::new(); let mut result = IndexMap::new();
let directory_tree = &*directory_tree.await?; let directory_tree = &*directory_tree.await?;
@ -581,7 +580,7 @@ async fn directory_tree_to_entrypoints_internal(
let subdirectories = &directory_tree.subdirectories; let subdirectories = &directory_tree.subdirectories;
let components = directory_tree.components.await?; let components = directory_tree.components.await?;
let current_level_is_parallel_route = is_parallel_route(directory_name); let current_level_is_parallel_route = is_parallel_route(&directory_name);
if let Some(page) = components.page { if let Some(page) = components.page {
add_app_page( add_app_page(
@ -692,18 +691,17 @@ async fn directory_tree_to_entrypoints_internal(
let parallel_route_key = match_parallel_route(subdir_name); let parallel_route_key = match_parallel_route(subdir_name);
let map = directory_tree_to_entrypoints_internal( let map = directory_tree_to_entrypoints_internal(
app_dir, app_dir,
subdir_name, subdir_name.to_string(),
subdirectory, subdirectory,
// TODO(alexkirsz) We don't check optional segment here because Next.js seems to expect // TODO(alexkirsz) We don't check optional segment here because Next.js seems to expect
// it, although this might just need to be computed as "original name". // it, although this might just need to be computed as "original name".
if parallel_route_key.is_some() { if parallel_route_key.is_some() {
Cow::Borrowed(path_prefix) path_prefix.clone()
} else if path_prefix == "/" { } else if path_prefix == "/" {
format!("/{subdir_name}").into() format!("/{subdir_name}")
} else { } else {
format!("{path_prefix}/{subdir_name}").into() format!("{path_prefix}/{subdir_name}")
} },
.as_ref(),
) )
.await?; .await?;
for (full_path, &entrypoint) in map.iter() { for (full_path, &entrypoint) in map.iter() {
@ -731,7 +729,7 @@ async fn directory_tree_to_entrypoints_internal(
} }
} }
} }
Ok(EntrypointsVc::cell(result)) Ok(Vc::cell(result))
} }
/// ref: https://github.com/vercel/next.js/blob/c390c1662bc79e12cf7c037dcb382ef5ead6e492/packages/next/src/build/entries.ts#L119 /// ref: https://github.com/vercel/next.js/blob/c390c1662bc79e12cf7c037dcb382ef5ead6e492/packages/next/src/build/entries.ts#L119
@ -743,9 +741,9 @@ fn get_underscore_normalized_path(path: &str) -> String {
/// Returns the global metadata for an app directory. /// Returns the global metadata for an app directory.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_global_metadata( pub async fn get_global_metadata(
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
page_extensions: StringsVc, page_extensions: Vc<Vec<String>>,
) -> Result<GlobalMetadataVc> { ) -> Result<Vc<GlobalMetadata>> {
let DirectoryContent::Entries(entries) = &*app_dir.read_dir().await? else { let DirectoryContent::Entries(entries) = &*app_dir.read_dir().await? else {
bail!("app_dir must be a directory") bail!("app_dir must be a directory")
}; };
@ -778,37 +776,37 @@ pub async fn get_global_metadata(
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
struct DirectoryTreeIssue { struct DirectoryTreeIssue {
pub severity: IssueSeverityVc, pub severity: Vc<IssueSeverity>,
pub app_dir: FileSystemPathVc, pub app_dir: Vc<FileSystemPath>,
pub message: StringVc, pub message: Vc<String>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Issue for DirectoryTreeIssue { impl Issue for DirectoryTreeIssue {
#[turbo_tasks::function] #[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc { fn severity(&self) -> Vc<IssueSeverity> {
self.severity self.severity
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn title(&self) -> Result<StringVc> { async fn title(&self) -> Result<Vc<String>> {
Ok(StringVc::cell( Ok(Vc::cell(
"An issue occurred while preparing your Next.js app".to_string(), "An issue occurred while preparing your Next.js app".to_string(),
)) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn category(&self) -> StringVc { fn category(&self) -> Vc<String> {
StringVc::cell("next app".to_string()) Vc::cell("next app".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc { fn context(&self) -> Vc<FileSystemPath> {
self.app_dir self.app_dir
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn description(&self) -> StringVc { fn description(&self) -> Vc<String> {
self.message self.message
} }
} }

View file

@ -1,18 +1,15 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{ use turbo_tasks::{Value, Vc};
primitives::{BoolVc, StringVc},
Value,
};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{FileSystemEntryType, FileSystemPathVc}, turbo::tasks_fs::{FileSystemEntryType, FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, issue::{Issue, IssueExt, IssueSeverity},
resolve::{parse::RequestVc, pattern::Pattern, resolve}, resolve::{parse::Request, pattern::Pattern, resolve},
}, },
node::transforms::webpack::{WebpackLoaderItem, WebpackLoaderItemsVc}, node::transforms::webpack::WebpackLoaderItem,
turbopack::{ turbopack::{
module_options::{LoaderRuleItem, OptionWebpackRulesVc, WebpackRulesVc}, module_options::{LoaderRuleItem, OptionWebpackRules, WebpackRules},
resolve_options, resolve_options,
resolve_options_context::ResolveOptionsContext, resolve_options_context::ResolveOptionsContext,
}, },
@ -36,13 +33,13 @@ const BABEL_CONFIG_FILES: &[&str] = &[
/// webpack loader for each eligible file type if it doesn't already exist. /// webpack loader for each eligible file type if it doesn't already exist.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn maybe_add_babel_loader( pub async fn maybe_add_babel_loader(
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
webpack_rules: Option<WebpackRulesVc>, webpack_rules: Option<Vc<WebpackRules>>,
) -> Result<OptionWebpackRulesVc> { ) -> Result<Vc<OptionWebpackRules>> {
let has_babel_config = { let has_babel_config = {
let mut has_babel_config = false; let mut has_babel_config = false;
for filename in BABEL_CONFIG_FILES { for filename in BABEL_CONFIG_FILES {
let filetype = *project_root.join(filename).get_type().await?; let filetype = *project_root.join(filename.to_string()).get_type().await?;
if matches!(filetype, FileSystemEntryType::File) { if matches!(filetype, FileSystemEntryType::File) {
has_babel_config = true; has_babel_config = true;
break; break;
@ -76,18 +73,17 @@ pub async fn maybe_add_babel_loader(
{ {
BabelIssue { BabelIssue {
path: project_root, path: project_root,
title: StringVc::cell( title: Vc::cell(
"Unable to resolve babel-loader, but a babel config is present" "Unable to resolve babel-loader, but a babel config is present"
.to_owned(), .to_owned(),
), ),
description: StringVc::cell( description: Vc::cell(
"Make sure babel-loader is installed via your package manager." "Make sure babel-loader is installed via your package manager."
.to_owned(), .to_owned(),
), ),
severity: IssueSeverity::Fatal.cell(), severity: IssueSeverity::Fatal.cell(),
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
has_emitted_babel_resolve_issue = true; has_emitted_babel_resolve_issue = true;
@ -100,12 +96,12 @@ pub async fn maybe_add_babel_loader(
if let Some(rule) = rule { if let Some(rule) = rule {
let mut loaders = rule.loaders.await?.clone_value(); let mut loaders = rule.loaders.await?.clone_value();
loaders.push(loader); loaders.push(loader);
rule.loaders = WebpackLoaderItemsVc::cell(loaders); rule.loaders = Vc::cell(loaders);
} else { } else {
rules.insert( rules.insert(
pattern.to_string(), pattern.to_string(),
LoaderRuleItem { LoaderRuleItem {
loaders: WebpackLoaderItemsVc::cell(vec![loader]), loaders: Vc::cell(vec![loader]),
rename_as: Some("*".to_string()), rename_as: Some("*".to_string()),
}, },
); );
@ -115,19 +111,17 @@ pub async fn maybe_add_babel_loader(
} }
if has_changed { if has_changed {
return Ok(OptionWebpackRulesVc::cell(Some(WebpackRulesVc::cell( return Ok(Vc::cell(Some(Vc::cell(rules))));
rules,
))));
} }
} }
Ok(OptionWebpackRulesVc::cell(webpack_rules)) Ok(Vc::cell(webpack_rules))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn is_babel_loader_available(project_path: FileSystemPathVc) -> Result<BoolVc> { pub async fn is_babel_loader_available(project_path: Vc<FileSystemPath>) -> Result<Vc<bool>> {
let result = resolve( let result = resolve(
project_path, project_path,
RequestVc::parse(Value::new(Pattern::Constant( Request::parse(Value::new(Pattern::Constant(
"babel-loader/package.json".to_string(), "babel-loader/package.json".to_string(),
))), ))),
resolve_options( resolve_options(
@ -142,41 +136,41 @@ pub async fn is_babel_loader_available(project_path: FileSystemPathVc) -> Result
), ),
); );
let assets = result.primary_assets().await?; let assets = result.primary_assets().await?;
Ok(BoolVc::cell(!assets.is_empty())) Ok(Vc::cell(!assets.is_empty()))
} }
#[turbo_tasks::value] #[turbo_tasks::value]
struct BabelIssue { struct BabelIssue {
path: FileSystemPathVc, path: Vc<FileSystemPath>,
title: StringVc, title: Vc<String>,
description: StringVc, description: Vc<String>,
severity: IssueSeverityVc, severity: Vc<IssueSeverity>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Issue for BabelIssue { impl Issue for BabelIssue {
#[turbo_tasks::function] #[turbo_tasks::function]
fn category(&self) -> StringVc { fn category(&self) -> Vc<String> {
StringVc::cell("other".to_string()) Vc::cell("other".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc { fn severity(&self) -> Vc<IssueSeverity> {
self.severity self.severity
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc { fn context(&self) -> Vc<FileSystemPath> {
self.path self.path
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn title(&self) -> StringVc { fn title(&self) -> Vc<String> {
self.title self.title
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn description(&self) -> StringVc { fn description(&self) -> Vc<String> {
self.description self.description
} }
} }

View file

@ -1,46 +1,47 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indexmap::{indexmap, IndexMap}; use indexmap::{indexmap, IndexMap};
use turbo_tasks::{Value, ValueToString}; use turbo_tasks::{Value, ValueToString, Vc};
use turbo_tasks_fs::{File, FileSystemPathVc}; use turbo_tasks_fs::{File, FileSystemPath};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetVc}, asset::{Asset, AssetContent},
chunk::EvaluatableAssetVc, chunk::EvaluatableAsset,
context::{AssetContext, AssetContextVc}, context::AssetContext,
issue::{IssueSeverity, OptionIssueSourceVc}, issue::{IssueSeverity, OptionIssueSource},
reference_type::{EcmaScriptModulesReferenceSubType, InnerAssetsVc, ReferenceType}, reference_type::{EcmaScriptModulesReferenceSubType, InnerAssets, ReferenceType},
resolve::parse::RequestVc, resolve::parse::Request,
source::SourceVc, source::Source,
virtual_source::VirtualSourceVc, virtual_source::VirtualSource,
}, },
ecmascript::{resolve::esm_resolve, utils::StringifyJs, EcmascriptModuleAssetVc}, ecmascript::{resolve::esm_resolve, utils::StringifyJs, EcmascriptModuleAsset},
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn route_bootstrap( pub async fn route_bootstrap(
asset: AssetVc, asset: Vc<Box<dyn Asset>>,
context: AssetContextVc, context: Vc<Box<dyn AssetContext>>,
base_path: FileSystemPathVc, base_path: Vc<FileSystemPath>,
bootstrap_asset: SourceVc, bootstrap_asset: Vc<Box<dyn Source>>,
config: BootstrapConfigVc, config: Vc<BootstrapConfig>,
) -> Result<EvaluatableAssetVc> { ) -> Result<Vc<Box<dyn EvaluatableAsset>>> {
let resolve_origin = if let Some(m) = EcmascriptModuleAssetVc::resolve_from(asset).await? { let resolve_origin =
m.as_resolve_origin() if let Some(m) = Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(asset).await? {
} else { Vc::upcast(m)
bail!("asset does not represent an ecmascript module"); } else {
}; bail!("asset does not represent an ecmascript module");
};
// TODO: this is where you'd switch the route kind to the one you need // TODO: this is where you'd switch the route kind to the one you need
let route_module_kind = "app-route"; let route_module_kind = "app-route";
let resolved_route_module_asset = esm_resolve( let resolved_route_module_asset = esm_resolve(
resolve_origin, resolve_origin,
RequestVc::parse_string(format!( Request::parse_string(format!(
"next/dist/server/future/route-modules/{}/module", "next/dist/server/future/route-modules/{}/module",
route_module_kind route_module_kind
)), )),
Value::new(EcmaScriptModulesReferenceSubType::Undefined), Value::new(EcmaScriptModulesReferenceSubType::Undefined),
OptionIssueSourceVc::none(), OptionIssueSource::none(),
IssueSeverity::Error.cell(), IssueSeverity::Error.cell(),
); );
let route_module_asset = match &*resolved_route_module_asset.first_asset().await? { let route_module_asset = match &*resolved_route_module_asset.first_asset().await? {
@ -53,7 +54,7 @@ pub async fn route_bootstrap(
context, context,
base_path, base_path,
bootstrap_asset, bootstrap_asset,
InnerAssetsVc::cell(indexmap! { Vc::cell(indexmap! {
"ROUTE_MODULE".to_string() => route_module_asset, "ROUTE_MODULE".to_string() => route_module_asset,
}), }),
config, config,
@ -64,22 +65,22 @@ pub async fn route_bootstrap(
pub struct BootstrapConfig(IndexMap<String, String>); pub struct BootstrapConfig(IndexMap<String, String>);
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl BootstrapConfigVc { impl BootstrapConfig {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn empty() -> Self { pub fn empty() -> Vc<Self> {
BootstrapConfigVc::cell(IndexMap::new()) Vc::cell(IndexMap::new())
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn bootstrap( pub async fn bootstrap(
asset: AssetVc, asset: Vc<Box<dyn Asset>>,
context: AssetContextVc, context: Vc<Box<dyn AssetContext>>,
base_path: FileSystemPathVc, base_path: Vc<FileSystemPath>,
bootstrap_asset: SourceVc, bootstrap_asset: Vc<Box<dyn Source>>,
inner_assets: InnerAssetsVc, inner_assets: Vc<InnerAssets>,
config: BootstrapConfigVc, config: Vc<BootstrapConfig>,
) -> Result<EvaluatableAssetVc> { ) -> Result<Vc<Box<dyn EvaluatableAsset>>> {
let path = asset.ident().path().await?; let path = asset.ident().path().await?;
let Some(path) = base_path.await?.get_path_to(&path) else { let Some(path) = base_path.await?.get_path_to(&path) else {
bail!( bail!(
@ -106,31 +107,32 @@ pub async fn bootstrap(
config.insert("KIND".to_string(), "APP_ROUTE".to_string()); config.insert("KIND".to_string(), "APP_ROUTE".to_string());
let config_asset = context.process( let config_asset = context.process(
VirtualSourceVc::new( Vc::upcast(VirtualSource::new(
asset.ident().path().join("bootstrap-config.ts"), asset.ident().path().join("bootstrap-config.ts".to_string()),
File::from( AssetContent::file(
config File::from(
.iter() config
.map(|(k, v)| format!("export const {} = {};\n", k, StringifyJs(v))) .iter()
.collect::<Vec<_>>() .map(|(k, v)| format!("export const {} = {};\n", k, StringifyJs(v)))
.join(""), .collect::<Vec<_>>()
) .join(""),
.into(), )
) .into(),
.into(), ),
Value::new(ReferenceType::Internal(InnerAssetsVc::empty())), )),
Value::new(ReferenceType::Internal(InnerAssets::empty())),
); );
let mut inner_assets = inner_assets.await?.clone_value(); let mut inner_assets = inner_assets.await?.clone_value();
inner_assets.insert("ENTRY".to_string(), asset); inner_assets.insert("ENTRY".to_string(), asset);
inner_assets.insert("BOOTSTRAP_CONFIG".to_string(), config_asset.into()); inner_assets.insert("BOOTSTRAP_CONFIG".to_string(), Vc::upcast(config_asset));
let asset = context.process( let asset = context.process(
bootstrap_asset, bootstrap_asset,
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(inner_assets))), Value::new(ReferenceType::Internal(Vc::cell(inner_assets))),
); );
let Some(asset) = EvaluatableAssetVc::resolve_from(asset).await? else { let Some(asset) = Vc::try_resolve_sidecast::<Box<dyn EvaluatableAsset>>(asset).await? else {
bail!("internal module must be evaluatable"); bail!("internal module must be evaluatable");
}; };

View file

@ -1,27 +1,28 @@
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{FileContentVc, FileSystem, FileSystemPathVc, FileSystemVc}, turbo::tasks_fs::{FileContent, FileSystem, FileSystemPath},
turbopack::core::{file_source::FileSourceVc, source::SourceVc}, turbopack::core::{file_source::FileSource, source::Source},
}; };
pub const VIRTUAL_PACKAGE_NAME: &str = "@vercel/turbopack-next"; pub const VIRTUAL_PACKAGE_NAME: &str = "@vercel/turbopack-next";
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) fn next_js_fs() -> FileSystemVc { pub(crate) fn next_js_fs() -> Vc<Box<dyn FileSystem>> {
// [TODO]: macro need to be refactored to be used via turbopack-binding // [TODO]: macro need to be refactored to be used via turbopack-binding
turbo_tasks_fs::embed_directory!("next", "$CARGO_MANIFEST_DIR/js/src") turbo_tasks_fs::embed_directory!("next", "$CARGO_MANIFEST_DIR/js/src")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) fn next_js_file(path: &str) -> FileContentVc { pub(crate) fn next_js_file(path: String) -> Vc<FileContent> {
next_js_fs().root().join(path).read() next_js_fs().root().join(path).read()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) fn next_js_file_path(path: &str) -> FileSystemPathVc { pub(crate) fn next_js_file_path(path: String) -> Vc<FileSystemPath> {
next_js_fs().root().join(path) next_js_fs().root().join(path)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) fn next_asset(path: &str) -> SourceVc { pub(crate) fn next_asset(path: String) -> Vc<Box<dyn Source>> {
FileSourceVc::new(next_js_file_path(path)).into() Vc::upcast(FileSource::new(next_js_file_path(path)))
} }

View file

@ -1,12 +1,12 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{ use turbo_tasks::{
graph::{AdjacencyMap, GraphTraversal}, graph::{AdjacencyMap, GraphTraversal},
CompletionVc, CompletionsVc, TryJoinIterExt, Completion, Completions, TryJoinIterExt, Vc,
}; };
use turbo_tasks_fs::{rebase, FileSystemPathVc}; use turbo_tasks_fs::{rebase, FileSystemPath};
use turbopack_binding::turbopack::core::{ use turbopack_binding::turbopack::core::{
asset::Asset, asset::Asset,
output::{OutputAssetVc, OutputAssetsVc}, output::{OutputAsset, OutputAssets},
reference::AssetReference, reference::AssetReference,
}; };
@ -14,31 +14,36 @@ use turbopack_binding::turbopack::core::{
/// inside the node root or the client root. /// inside the node root or the client root.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn emit_all_assets( pub async fn emit_all_assets(
assets: OutputAssetsVc, assets: Vc<OutputAssets>,
node_root: FileSystemPathVc, node_root: Vc<FileSystemPath>,
client_relative_path: FileSystemPathVc, client_relative_path: Vc<FileSystemPath>,
client_output_path: FileSystemPathVc, client_output_path: Vc<FileSystemPath>,
) -> Result<CompletionVc> { ) -> Result<Vc<Completion>> {
let all_assets = all_assets_from_entries(assets).await?; let all_assets = all_assets_from_entries(assets).await?;
Ok(CompletionsVc::all( Ok(Completions::all(
all_assets all_assets
.iter() .iter()
.copied() .copied()
.map(|asset| async move { .map(|asset| async move {
if asset.ident().path().await?.is_inside(&*node_root.await?) { if asset
.ident()
.path()
.await?
.is_inside_ref(&*node_root.await?)
{
return Ok(emit(asset)); return Ok(emit(asset));
} else if asset } else if asset
.ident() .ident()
.path() .path()
.await? .await?
.is_inside(&*client_relative_path.await?) .is_inside_ref(&*client_relative_path.await?)
{ {
// Client assets are emitted to the client output path, which is prefixed with // Client assets are emitted to the client output path, which is prefixed with
// _next. We need to rebase them to remove that prefix. // _next. We need to rebase them to remove that prefix.
return Ok(emit_rebase(asset, client_relative_path, client_output_path)); return Ok(emit_rebase(asset, client_relative_path, client_output_path));
} }
Ok(CompletionVc::immutable()) Ok(Completion::immutable())
}) })
.try_join() .try_join()
.await?, .await?,
@ -46,12 +51,16 @@ pub async fn emit_all_assets(
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn emit(asset: OutputAssetVc) -> CompletionVc { fn emit(asset: Vc<Box<dyn OutputAsset>>) -> Vc<Completion> {
asset.content().write(asset.ident().path()) asset.content().write(asset.ident().path())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn emit_rebase(asset: OutputAssetVc, from: FileSystemPathVc, to: FileSystemPathVc) -> CompletionVc { fn emit_rebase(
asset: Vc<Box<dyn OutputAsset>>,
from: Vc<FileSystemPath>,
to: Vc<FileSystemPath>,
) -> Vc<Completion> {
asset asset
.content() .content()
.write(rebase(asset.ident().path(), from, to)) .write(rebase(asset.ident().path(), from, to))
@ -60,8 +69,8 @@ fn emit_rebase(asset: OutputAssetVc, from: FileSystemPathVc, to: FileSystemPathV
/// Walks the asset graph from multiple assets and collect all referenced /// Walks the asset graph from multiple assets and collect all referenced
/// assets. /// assets.
#[turbo_tasks::function] #[turbo_tasks::function]
async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<OutputAssetsVc> { async fn all_assets_from_entries(entries: Vc<OutputAssets>) -> Result<Vc<OutputAssets>> {
Ok(OutputAssetsVc::cell( Ok(Vc::cell(
AdjacencyMap::new() AdjacencyMap::new()
.skip_duplicates() .skip_duplicates()
.visit(entries.await?.iter().copied(), get_referenced_assets) .visit(entries.await?.iter().copied(), get_referenced_assets)
@ -75,23 +84,27 @@ async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<OutputAssets
/// Computes the list of all chunk children of a given chunk. /// Computes the list of all chunk children of a given chunk.
async fn get_referenced_assets( async fn get_referenced_assets(
asset: OutputAssetVc, asset: Vc<Box<dyn OutputAsset>>,
) -> Result<impl Iterator<Item = OutputAssetVc> + Send> { ) -> Result<impl Iterator<Item = Vc<Box<dyn OutputAsset>>> + Send> {
Ok(asset Ok(
.references() asset
.await? .references()
.iter() .await?
.map(|reference| async move { .iter()
let primary_assets = reference.resolve_reference().primary_assets().await?; .map(|reference| async move {
Ok(primary_assets.clone_value()) let primary_assets = reference.resolve_reference().primary_assets().await?;
}) Ok(primary_assets.clone_value())
.try_join() })
.await? .try_join()
.into_iter() .await?
.flatten() .into_iter()
.map(|asset| async move { Ok(OutputAssetVc::resolve_from(asset).await?) }) .flatten()
.try_join() .map(|asset| async move {
.await? Ok(Vc::try_resolve_sidecast::<Box<dyn OutputAsset>>(asset).await?)
.into_iter() })
.flatten()) .try_join()
.await?
.into_iter()
.flatten(),
)
} }

View file

@ -1,47 +1,47 @@
use anyhow::Result; use anyhow::Result;
use indexmap::indexmap; use indexmap::indexmap;
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_env::{ turbo::tasks_env::{CustomProcessEnv, EnvMap, FilterProcessEnv, ProcessEnv},
CustomProcessEnvVc, EnvMapVc, FilterProcessEnvVc, ProcessEnv, ProcessEnvVc, turbopack::env::EmbeddableProcessEnv,
},
turbopack::env::EmbeddableProcessEnvVc,
}; };
use crate::next_config::NextConfigVc; use crate::next_config::NextConfig;
/// Creates a ProcessEnvVc safe to use in JS, by stringifying and encoding as /// Creates a Vc<Box<dyn ProcessEnv>> safe to use in JS, by stringifying and
/// regular JS strings. Setting `client` to true will additionally filter the /// encoding as regular JS strings. Setting `client` to true will additionally
/// env to just the keys that are acceptable for the client to access. /// filter the env to just the keys that are acceptable for the client to
/// access.
/// ///
/// For now, it also injects overridden values as if they were real JS code, eg /// For now, it also injects overridden values as if they were real JS code, eg
/// an Object and not a String. /// an Object and not a String.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn env_for_js( pub async fn env_for_js(
env: ProcessEnvVc, env: Vc<Box<dyn ProcessEnv>>,
client: bool, client: bool,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<ProcessEnvVc> { ) -> Result<Vc<Box<dyn ProcessEnv>>> {
let test_mode = env.read("__NEXT_TEST_MODE").await?; let test_mode = env.read("__NEXT_TEST_MODE".to_string()).await?;
let test_mode = test_mode.as_deref().unwrap_or(""); let test_mode = test_mode.as_deref().unwrap_or("");
let env = if client { let env = if client {
FilterProcessEnvVc::new( Vc::upcast(FilterProcessEnv::new(
env, env,
vec![ vec![
"NEXT_PUBLIC_".to_string(), "NEXT_PUBLIC_".to_string(),
"NODE_ENV".to_string(), "NODE_ENV".to_string(),
"PORT".to_string(), "PORT".to_string(),
], ],
) ))
.into()
} else { } else {
// Server doesn't need to have env vars injected since it will have them in the // Server doesn't need to have env vars injected since it will have them in the
// real process.env. // real process.env.
EnvMapVc::cell(Default::default()).into() Vc::upcast(EnvMap::empty())
}; };
let env = let env = Vc::upcast(EmbeddableProcessEnv::new(Vc::upcast(
EmbeddableProcessEnvVc::new(CustomProcessEnvVc::new(env, next_config.env()).into()).into(); CustomProcessEnv::new(env, next_config.env()),
)));
let image_config = next_config.image_config().await?; let image_config = next_config.image_config().await?;
let mut map = indexmap! { let mut map = indexmap! {
@ -65,5 +65,5 @@ pub async fn env_for_js(
map.insert("__NEXT_TEST_MODE".to_string(), "true".to_string()); map.insert("__NEXT_TEST_MODE".to_string(), "true".to_string());
} }
Ok(CustomProcessEnvVc::new(env, EnvMapVc::cell(map)).into()) Ok(Vc::upcast(CustomProcessEnv::new(env, Vc::cell(map))))
} }

View file

@ -1,21 +1,18 @@
use std::collections::HashMap; use std::collections::HashMap;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::{tasks_env::ProcessEnvVc, tasks_fs::FileSystemPathVc}, turbo::{tasks_env::ProcessEnv, tasks_fs::FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
compile_time_info::CompileTimeInfoVc, compile_time_info::CompileTimeInfo,
context::AssetContextVc, context::AssetContext,
resolve::{options::ImportMap, origin::PlainResolveOriginVc}, resolve::{options::ImportMap, origin::PlainResolveOrigin},
},
dev_server::html::DevHtmlAssetVc,
node::execution_context::ExecutionContextVc,
turbopack::{
ecmascript::EcmascriptModuleAssetVc, transition::TransitionsByNameVc,
ModuleAssetContextVc,
}, },
dev_server::html::DevHtmlAsset,
node::execution_context::ExecutionContext,
turbopack::{ecmascript::EcmascriptModuleAsset, ModuleAssetContext},
}, },
}; };
@ -25,20 +22,20 @@ use crate::{
get_client_chunking_context, get_client_module_options_context, get_client_chunking_context, get_client_module_options_context,
get_client_resolve_options_context, get_client_runtime_entries, ClientContextType, get_client_resolve_options_context, get_client_runtime_entries, ClientContextType,
}, },
next_config::NextConfigVc, next_config::NextConfig,
next_import_map::insert_next_shared_aliases, next_import_map::insert_next_shared_aliases,
runtime::resolve_runtime_request, runtime::resolve_runtime_request,
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_fallback_page( pub async fn get_fallback_page(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
dev_server_root: FileSystemPathVc, dev_server_root: Vc<FileSystemPath>,
env: ProcessEnvVc, env: Vc<Box<dyn ProcessEnv>>,
client_compile_time_info: CompileTimeInfoVc, client_compile_time_info: Vc<CompileTimeInfo>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<DevHtmlAssetVc> { ) -> Result<Vc<DevHtmlAsset>> {
let ty = Value::new(ClientContextType::Fallback); let ty = Value::new(ClientContextType::Fallback);
let mode = NextMode::Development; let mode = NextMode::Development;
let resolve_options_context = let resolve_options_context =
@ -69,35 +66,34 @@ pub async fn get_fallback_page(
) )
.await?; .await?;
let context: AssetContextVc = ModuleAssetContextVc::new( let context: Vc<Box<dyn AssetContext>> = Vc::upcast(ModuleAssetContext::new(
TransitionsByNameVc::cell(HashMap::new()), Vc::cell(HashMap::new()),
client_compile_time_info, client_compile_time_info,
module_options_context, module_options_context,
resolve_options_context.with_extended_import_map(import_map.cell()), resolve_options_context.with_extended_import_map(import_map.cell()),
) ));
.into();
let runtime_entries = entries.resolve_entries(context); let runtime_entries = entries.resolve_entries(context);
let fallback_chunk = resolve_runtime_request( let fallback_chunk = resolve_runtime_request(
PlainResolveOriginVc::new(context, project_path).into(), Vc::upcast(PlainResolveOrigin::new(context, project_path)),
"entry/fallback", "entry/fallback".to_string(),
); );
let module = if let Some(module) = let module = if let Some(module) =
EcmascriptModuleAssetVc::resolve_from(fallback_chunk.as_asset()).await? Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(fallback_chunk).await?
{ {
module module
} else { } else {
bail!("fallback runtime entry is not an ecmascript module"); bail!("fallback runtime entry is not an ecmascript module");
}; };
Ok(DevHtmlAssetVc::new( Ok(DevHtmlAsset::new(
dev_server_root.join("fallback.html"), dev_server_root.join("fallback.html".to_string()),
vec![( vec![(
module.into(), Vc::upcast(module),
chunking_context.into(), Vc::upcast(chunking_context),
Some(runtime_entries.with_entry(module.into())), Some(runtime_entries.with_entry(Vc::upcast(module))),
)], )],
)) ))
} }

View file

@ -3,6 +3,8 @@
#![feature(async_closure)] #![feature(async_closure)]
#![feature(str_split_remainder)] #![feature(str_split_remainder)]
#![feature(impl_trait_in_assoc_type)] #![feature(impl_trait_in_assoc_type)]
#![feature(arbitrary_self_types)]
#![feature(async_fn_in_trait)]
mod app_render; mod app_render;
mod app_segment_config; mod app_segment_config;
@ -47,9 +49,7 @@ mod web_entry_source;
pub use app_source::create_app_source; pub use app_source::create_app_source;
pub use emit::emit_all_assets; pub use emit::emit_all_assets;
pub use next_app::unsupported_dynamic_metadata_issue::{ pub use next_app::unsupported_dynamic_metadata_issue::UnsupportedDynamicMetadataIssue;
UnsupportedDynamicMetadataIssue, UnsupportedDynamicMetadataIssueVc,
};
pub use page_loader::create_page_loader_entry_module; pub use page_loader::create_page_loader_entry_module;
pub use page_source::create_page_source; pub use page_source::create_page_source;
pub use turbopack_binding::{turbopack::node::source_map, *}; pub use turbopack_binding::{turbopack::node::source_map, *};

View file

@ -2,46 +2,41 @@ use anyhow::Result;
use async_recursion::async_recursion; use async_recursion::async_recursion;
use indexmap::IndexMap; use indexmap::IndexMap;
use indoc::formatdoc; use indoc::formatdoc;
use turbo_tasks::{Value, ValueToString}; use turbo_tasks::{Value, ValueToString, Vc};
use turbo_tasks_fs::FileSystemPathVc; use turbo_tasks_fs::FileSystemPath;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::AssetVc, asset::Asset,
context::AssetContext, context::AssetContext,
file_source::FileSourceVc, file_source::FileSource,
reference_type::{EcmaScriptModulesReferenceSubType, InnerAssetsVc, ReferenceType}, reference_type::{EcmaScriptModulesReferenceSubType, InnerAssets, ReferenceType},
},
ecmascript::{magic_identifier, text::TextContentFileSourceVc, utils::StringifyJs},
r#static::StaticModuleAssetVc,
turbopack::{
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
ecmascript::{magic_identifier, text::TextContentFileSource, utils::StringifyJs},
r#static::StaticModuleAsset,
turbopack::{transition::Transition, ModuleAssetContext},
}; };
use crate::{ use crate::{
app_structure::{ app_structure::{Components, LoaderTree, Metadata, MetadataItem, MetadataWithAltItem},
Components, LoaderTree, LoaderTreeVc, Metadata, MetadataItem, MetadataWithAltItem,
},
mode::NextMode, mode::NextMode,
next_image::module::{BlurPlaceholderMode, StructuredImageModuleType}, next_image::module::{BlurPlaceholderMode, StructuredImageModuleType},
}; };
pub struct LoaderTreeBuilder { pub struct LoaderTreeBuilder {
inner_assets: IndexMap<String, AssetVc>, inner_assets: IndexMap<String, Vc<Box<dyn Asset>>>,
counter: usize, counter: usize,
imports: Vec<String>, imports: Vec<String>,
loader_tree_code: String, loader_tree_code: String,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
unsupported_metadata: Vec<FileSystemPathVc>, unsupported_metadata: Vec<Vc<FileSystemPath>>,
mode: NextMode, mode: NextMode,
server_component_transition: ServerComponentTransition, server_component_transition: ServerComponentTransition,
pages: Vec<FileSystemPathVc>, pages: Vec<Vc<FileSystemPath>>,
} }
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum ServerComponentTransition { pub enum ServerComponentTransition {
Transition(TransitionVc), Transition(Vc<Box<dyn Transition>>),
TransitionName(String), TransitionName(String),
} }
@ -72,7 +67,7 @@ impl ComponentType {
impl LoaderTreeBuilder { impl LoaderTreeBuilder {
fn new( fn new(
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
server_component_transition: ServerComponentTransition, server_component_transition: ServerComponentTransition,
mode: NextMode, mode: NextMode,
) -> Self { ) -> Self {
@ -98,7 +93,7 @@ impl LoaderTreeBuilder {
async fn write_component( async fn write_component(
&mut self, &mut self,
ty: ComponentType, ty: ComponentType,
component: Option<FileSystemPathVc>, component: Option<Vc<FileSystemPath>>,
) -> Result<()> { ) -> Result<()> {
use std::fmt::Write; use std::fmt::Write;
@ -149,7 +144,7 @@ impl LoaderTreeBuilder {
} }
} }
let source = FileSourceVc::new(component).into(); let source = Vc::upcast(FileSource::new(component));
let reference_ty = Value::new(ReferenceType::EcmaScriptModules( let reference_ty = Value::new(ReferenceType::EcmaScriptModules(
EcmaScriptModulesReferenceSubType::Undefined, EcmaScriptModulesReferenceSubType::Undefined,
)); ));
@ -160,12 +155,12 @@ impl LoaderTreeBuilder {
} }
ServerComponentTransition::TransitionName(transition_name) => self ServerComponentTransition::TransitionName(transition_name) => self
.context .context
.with_transition(transition_name.as_str()) .with_transition(transition_name.clone())
.process(source, reference_ty), .process(source, reference_ty),
}; };
self.inner_assets self.inner_assets
.insert(format!("COMPONENT_{i}"), module.into()); .insert(format!("COMPONENT_{i}"), Vc::upcast(module));
} }
Ok(()) Ok(())
} }
@ -206,8 +201,10 @@ impl LoaderTreeBuilder {
.push(format!("import {identifier} from \"{inner_module_id}\";")); .push(format!("import {identifier} from \"{inner_module_id}\";"));
self.inner_assets.insert( self.inner_assets.insert(
inner_module_id, inner_module_id,
StaticModuleAssetVc::new(FileSourceVc::new(path).into(), self.context.into()) Vc::upcast(StaticModuleAsset::new(
.into(), Vc::upcast(FileSource::new(path)),
Vc::upcast(self.context),
)),
); );
writeln!(self.loader_tree_code, " manifest: {identifier},")?; writeln!(self.loader_tree_code, " manifest: {identifier},")?;
} }
@ -249,12 +246,11 @@ impl LoaderTreeBuilder {
MetadataWithAltItem::Static { path, alt_path } => { MetadataWithAltItem::Static { path, alt_path } => {
self.inner_assets.insert( self.inner_assets.insert(
inner_module_id, inner_module_id,
StructuredImageModuleType::create_module( Vc::upcast(StructuredImageModuleType::create_module(
FileSourceVc::new(*path).into(), Vc::upcast(FileSource::new(*path)),
BlurPlaceholderMode::None, BlurPlaceholderMode::None,
self.context, self.context,
) )),
.into(),
); );
writeln!(self.loader_tree_code, "{s}(async (props) => [{{")?; writeln!(self.loader_tree_code, "{s}(async (props) => [{{")?;
writeln!(self.loader_tree_code, "{s} url: {identifier}.src,")?; writeln!(self.loader_tree_code, "{s} url: {identifier}.src,")?;
@ -275,13 +271,12 @@ impl LoaderTreeBuilder {
.push(format!("import {identifier} from \"{inner_module_id}\";")); .push(format!("import {identifier} from \"{inner_module_id}\";"));
self.inner_assets.insert( self.inner_assets.insert(
inner_module_id, inner_module_id,
self.context Vc::upcast(self.context.process(
.process( Vc::upcast(TextContentFileSource::new(Vc::upcast(FileSource::new(
TextContentFileSourceVc::new(FileSourceVc::new(*alt_path).into()) *alt_path,
.into(), )))),
Value::new(ReferenceType::Internal(InnerAssetsVc::empty())), Value::new(ReferenceType::Internal(InnerAssets::empty())),
) )),
.into(),
); );
writeln!(self.loader_tree_code, "{s} alt: {identifier},")?; writeln!(self.loader_tree_code, "{s} alt: {identifier},")?;
} }
@ -295,7 +290,7 @@ impl LoaderTreeBuilder {
} }
#[async_recursion] #[async_recursion]
async fn walk_tree(&mut self, loader_tree: LoaderTreeVc) -> Result<()> { async fn walk_tree(&mut self, loader_tree: Vc<LoaderTree>) -> Result<()> {
use std::fmt::Write; use std::fmt::Write;
let LoaderTree { let LoaderTree {
@ -344,7 +339,7 @@ impl LoaderTreeBuilder {
Ok(()) Ok(())
} }
async fn build(mut self, loader_tree: LoaderTreeVc) -> Result<LoaderTreeModule> { async fn build(mut self, loader_tree: Vc<LoaderTree>) -> Result<LoaderTreeModule> {
self.walk_tree(loader_tree).await?; self.walk_tree(loader_tree).await?;
Ok(LoaderTreeModule { Ok(LoaderTreeModule {
imports: self.imports, imports: self.imports,
@ -359,15 +354,15 @@ impl LoaderTreeBuilder {
pub struct LoaderTreeModule { pub struct LoaderTreeModule {
pub imports: Vec<String>, pub imports: Vec<String>,
pub loader_tree_code: String, pub loader_tree_code: String,
pub inner_assets: IndexMap<String, AssetVc>, pub inner_assets: IndexMap<String, Vc<Box<dyn Asset>>>,
pub unsupported_metadata: Vec<FileSystemPathVc>, pub unsupported_metadata: Vec<Vc<FileSystemPath>>,
pub pages: Vec<FileSystemPathVc>, pub pages: Vec<Vc<FileSystemPath>>,
} }
impl LoaderTreeModule { impl LoaderTreeModule {
pub async fn build( pub async fn build(
loader_tree: LoaderTreeVc, loader_tree: Vc<LoaderTree>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
server_component_transition: ServerComponentTransition, server_component_transition: ServerComponentTransition,
mode: NextMode, mode: NextMode,
) -> Result<Self> { ) -> Result<Self> {

View file

@ -4,57 +4,51 @@ use mime::{APPLICATION_JAVASCRIPT_UTF_8, APPLICATION_JSON};
use serde::Serialize; use serde::Serialize;
use turbo_tasks::{ use turbo_tasks::{
graph::{GraphTraversal, NonDeterministic}, graph::{GraphTraversal, NonDeterministic},
primitives::{StringReadRef, StringVc, StringsVc}, ReadRef, Vc,
}; };
use turbopack_binding::{ use turbopack_binding::{
turbo::{tasks::TryJoinIterExt, tasks_fs::File}, turbo::{tasks::TryJoinIterExt, tasks_fs::File},
turbopack::{ turbopack::{
core::{ core::{asset::AssetContent, introspect::Introspectable, version::VersionedContentExt},
asset::AssetContentVc,
introspect::{Introspectable, IntrospectableVc},
},
dev_server::source::{ dev_server::source::{
route_tree::{BaseSegment, RouteTreeVc, RouteTreesVc, RouteType}, route_tree::{BaseSegment, RouteTree, RouteTrees, RouteType},
ContentSource, ContentSourceContentVc, ContentSourceData, ContentSourceVc, ContentSource, ContentSourceContent, ContentSourceData, GetContentSourceContent,
GetContentSourceContent, GetContentSourceContentVc,
}, },
node::render::{ node::render::{
node_api_source::NodeApiContentSourceVc, rendered_source::NodeRenderContentSourceVc, node_api_source::NodeApiContentSource, rendered_source::NodeRenderContentSource,
}, },
}, },
}; };
use crate::{ use crate::{embed_js::next_js_file, next_config::Rewrites, util::get_asset_path_from_pathname};
embed_js::next_js_file,
next_config::{RewritesReadRef, RewritesVc},
util::get_asset_path_from_pathname,
};
/// A content source which creates the next.js `_devPagesManifest.json` and /// A content source which creates the next.js `_devPagesManifest.json` and
/// `_devMiddlewareManifest.json` which are used for client side navigation. /// `_devMiddlewareManifest.json` which are used for client side navigation.
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct DevManifestContentSource { pub struct DevManifestContentSource {
pub page_roots: Vec<ContentSourceVc>, pub page_roots: Vec<Vc<Box<dyn ContentSource>>>,
pub rewrites: RewritesVc, pub rewrites: Vc<Rewrites>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl DevManifestContentSourceVc { impl DevManifestContentSource {
/// Recursively find all routes in the `page_roots` content sources. /// Recursively find all routes in the `page_roots` content sources.
#[turbo_tasks::function] #[turbo_tasks::function]
async fn find_routes(self) -> Result<StringsVc> { async fn find_routes(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
let this = &*self.await?; let this = &*self.await?;
async fn content_source_to_pathname( async fn content_source_to_pathname(
content_source: ContentSourceVc, content_source: Vc<Box<dyn ContentSource>>,
) -> Result<Option<StringReadRef>> { ) -> Result<Option<ReadRef<String>>> {
// TODO This shouldn't use casts but an public api instead // TODO This shouldn't use casts but an public api instead
if let Some(api_source) = NodeApiContentSourceVc::resolve_from(content_source).await? { if let Some(api_source) =
Vc::try_resolve_downcast_type::<NodeApiContentSource>(content_source).await?
{
return Ok(Some(api_source.get_pathname().await?)); return Ok(Some(api_source.get_pathname().await?));
} }
if let Some(page_source) = if let Some(page_source) =
NodeRenderContentSourceVc::resolve_from(content_source).await? Vc::try_resolve_downcast_type::<NodeRenderContentSource>(content_source).await?
{ {
return Ok(Some(page_source.get_pathname().await?)); return Ok(Some(page_source.get_pathname().await?));
} }
@ -63,8 +57,8 @@ impl DevManifestContentSourceVc {
} }
async fn get_content_source_children( async fn get_content_source_children(
content_source: ContentSourceVc, content_source: Vc<Box<dyn ContentSource>>,
) -> Result<Vec<ContentSourceVc>> { ) -> Result<Vec<Vc<Box<dyn ContentSource>>>> {
Ok(content_source.get_children().await?.clone_value()) Ok(content_source.get_children().await?.clone_value())
} }
@ -85,13 +79,13 @@ impl DevManifestContentSourceVc {
routes.sort_by_cached_key(|s| s.split('/').map(PageSortKey::from).collect::<Vec<_>>()); routes.sort_by_cached_key(|s| s.split('/').map(PageSortKey::from).collect::<Vec<_>>());
routes.dedup(); routes.dedup();
Ok(StringsVc::cell(routes)) Ok(Vc::cell(routes))
} }
/// Recursively find all pages in the `page_roots` content sources /// Recursively find all pages in the `page_roots` content sources
/// (excluding api routes). /// (excluding api routes).
#[turbo_tasks::function] #[turbo_tasks::function]
async fn find_pages(self) -> Result<StringsVc> { async fn find_pages(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
let routes = &*self.find_routes().await?; let routes = &*self.find_routes().await?;
// we don't need to sort as it's already sorted by `find_routes` // we don't need to sort as it's already sorted by `find_routes`
@ -101,12 +95,12 @@ impl DevManifestContentSourceVc {
.cloned() .cloned()
.collect(); .collect();
Ok(StringsVc::cell(pages)) Ok(Vc::cell(pages))
} }
/// Create a build manifest with all pages. /// Create a build manifest with all pages.
#[turbo_tasks::function] #[turbo_tasks::function]
async fn create_build_manifest(self) -> Result<StringVc> { async fn create_build_manifest(self: Vc<Self>) -> Result<Vc<String>> {
let this = &*self.await?; let this = &*self.await?;
let sorted_pages = &*self.find_pages().await?; let sorted_pages = &*self.find_pages().await?;
@ -129,7 +123,7 @@ impl DevManifestContentSourceVc {
routes, routes,
}; };
let manifest = next_js_file("entry/manifest/buildManifest.js") let manifest = next_js_file("entry/manifest/buildManifest.js".to_string())
.await? .await?
.as_content() .as_content()
.context("embedded buildManifest file missing")? .context("embedded buildManifest file missing")?
@ -137,7 +131,7 @@ impl DevManifestContentSourceVc {
.to_str()? .to_str()?
.replace("$$MANIFEST$$", &serde_json::to_string(&manifest)?); .replace("$$MANIFEST$$", &serde_json::to_string(&manifest)?);
Ok(StringVc::cell(manifest)) Ok(Vc::cell(manifest))
} }
} }
@ -145,7 +139,7 @@ impl DevManifestContentSourceVc {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct BuildManifest<'a> { struct BuildManifest<'a> {
#[serde(rename = "__rewrites")] #[serde(rename = "__rewrites")]
rewrites: RewritesReadRef, rewrites: ReadRef<Rewrites>,
sorted_pages: &'a Vec<String>, sorted_pages: &'a Vec<String>,
#[serde(flatten)] #[serde(flatten)]
@ -160,22 +154,22 @@ const DEV_MIDDLEWARE_MANIFEST_PATHNAME: &str =
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ContentSource for DevManifestContentSource { impl ContentSource for DevManifestContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_routes(self_vc: DevManifestContentSourceVc) -> RouteTreeVc { fn get_routes(self: Vc<Self>) -> Vc<RouteTree> {
RouteTreesVc::cell(vec![ Vc::<RouteTrees>::cell(vec![
RouteTreeVc::new_route( RouteTree::new_route(
BaseSegment::from_static_pathname(DEV_MANIFEST_PATHNAME).collect(), BaseSegment::from_static_pathname(DEV_MANIFEST_PATHNAME).collect(),
RouteType::Exact, RouteType::Exact,
self_vc.into(), Vc::upcast(self),
), ),
RouteTreeVc::new_route( RouteTree::new_route(
BaseSegment::from_static_pathname(BUILD_MANIFEST_PATHNAME).collect(), BaseSegment::from_static_pathname(BUILD_MANIFEST_PATHNAME).collect(),
RouteType::Exact, RouteType::Exact,
self_vc.into(), Vc::upcast(self),
), ),
RouteTreeVc::new_route( RouteTree::new_route(
BaseSegment::from_static_pathname(DEV_MIDDLEWARE_MANIFEST_PATHNAME).collect(), BaseSegment::from_static_pathname(DEV_MIDDLEWARE_MANIFEST_PATHNAME).collect(),
RouteType::Exact, RouteType::Exact,
self_vc.into(), Vc::upcast(self),
), ),
]) ])
.merge() .merge()
@ -186,13 +180,13 @@ impl ContentSource for DevManifestContentSource {
impl GetContentSourceContent for DevManifestContentSource { impl GetContentSourceContent for DevManifestContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get( async fn get(
self_vc: DevManifestContentSourceVc, self: Vc<Self>,
path: &str, path: String,
_data: turbo_tasks::Value<ContentSourceData>, _data: turbo_tasks::Value<ContentSourceData>,
) -> Result<ContentSourceContentVc> { ) -> Result<Vc<ContentSourceContent>> {
let manifest_file = match path { let manifest_file = match path.as_str() {
DEV_MANIFEST_PATHNAME => { DEV_MANIFEST_PATHNAME => {
let pages = &*self_vc.find_routes().await?; let pages = &*self.find_routes().await?;
File::from(serde_json::to_string(&serde_json::json!({ File::from(serde_json::to_string(&serde_json::json!({
"pages": pages, "pages": pages,
@ -200,7 +194,7 @@ impl GetContentSourceContent for DevManifestContentSource {
.with_content_type(APPLICATION_JSON) .with_content_type(APPLICATION_JSON)
} }
BUILD_MANIFEST_PATHNAME => { BUILD_MANIFEST_PATHNAME => {
let build_manifest = &*self_vc.create_build_manifest().await?; let build_manifest = &*self.create_build_manifest().await?;
File::from(build_manifest.as_str()).with_content_type(APPLICATION_JAVASCRIPT_UTF_8) File::from(build_manifest.as_str()).with_content_type(APPLICATION_JAVASCRIPT_UTF_8)
} }
@ -215,8 +209,8 @@ impl GetContentSourceContent for DevManifestContentSource {
_ => bail!("unknown path: {}", path), _ => bail!("unknown path: {}", path),
}; };
Ok(ContentSourceContentVc::static_content( Ok(ContentSourceContent::static_content(
AssetContentVc::from(manifest_file).into(), AssetContent::file(manifest_file.into()).versioned(),
)) ))
} }
} }
@ -224,13 +218,13 @@ impl GetContentSourceContent for DevManifestContentSource {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Introspectable for DevManifestContentSource { impl Introspectable for DevManifestContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ty(&self) -> StringVc { fn ty(&self) -> Vc<String> {
StringVc::cell("dev manifest source".to_string()) Vc::cell("dev manifest source".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn details(&self) -> StringVc { fn details(&self) -> Vc<String> {
StringVc::cell( Vc::cell(
"provides _devPagesManifest.json, _buildManifest.js and _devMiddlewareManifest.json." "provides _devPagesManifest.json, _buildManifest.js and _devMiddlewareManifest.json."
.to_string(), .to_string(),
) )

View file

@ -1,43 +1,43 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{primitives::StringVc, TryJoinIterExt, ValueToString}; use turbo_tasks::{TryJoinIterExt, ValueToString, Vc};
use turbo_tasks_fs::FileSystemPathVc; use turbo_tasks_fs::FileSystemPath;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::issue::{Issue, IssueSeverity, IssueSeverityVc, IssueVc}, core::issue::{Issue, IssueSeverity},
ecmascript::utils::FormatIter, ecmascript::utils::FormatIter,
}; };
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct UnsupportedDynamicMetadataIssue { pub struct UnsupportedDynamicMetadataIssue {
pub app_dir: FileSystemPathVc, pub app_dir: Vc<FileSystemPath>,
pub files: Vec<FileSystemPathVc>, pub files: Vec<Vc<FileSystemPath>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Issue for UnsupportedDynamicMetadataIssue { impl Issue for UnsupportedDynamicMetadataIssue {
#[turbo_tasks::function] #[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc { fn severity(&self) -> Vc<IssueSeverity> {
IssueSeverity::Warning.into() IssueSeverity::Warning.into()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn category(&self) -> StringVc { fn category(&self) -> Vc<String> {
StringVc::cell("unsupported".to_string()) Vc::cell("unsupported".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc { fn context(&self) -> Vc<FileSystemPath> {
self.app_dir self.app_dir
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn title(&self) -> StringVc { fn title(&self) -> Vc<String> {
StringVc::cell( Vc::cell(
"Dynamic metadata from filesystem is currently not supported in Turbopack".to_string(), "Dynamic metadata from filesystem is currently not supported in Turbopack".to_string(),
) )
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn description(&self) -> Result<StringVc> { async fn description(&self) -> Result<Vc<String>> {
let mut files = self let mut files = self
.files .files
.iter() .iter()
@ -45,7 +45,7 @@ impl Issue for UnsupportedDynamicMetadataIssue {
.try_join() .try_join()
.await?; .await?;
files.sort(); files.sort();
Ok(StringVc::cell(format!( Ok(Vc::cell(format!(
"The following files were found in the app directory, but are not supported by \ "The following files were found in the app directory, but are not supported by \
Turbopack. They are ignored:\n{}", Turbopack. They are ignored:\n{}",
FormatIter(|| files.iter().flat_map(|file| vec!["\n- ", file])) FormatIter(|| files.iter().flat_map(|file| vec!["\n- ", file]))

View file

@ -1,16 +1,15 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::primitives::StringVc; use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath, turbopack::core::resolve::options::ImportMapping,
turbopack::core::resolve::options::{ImportMapping, ImportMappingVc},
}; };
use crate::next_import_map::get_next_package; use crate::next_import_map::get_next_package;
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_postcss_package_mapping( pub async fn get_postcss_package_mapping(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
) -> Result<ImportMappingVc> { ) -> Result<Vc<ImportMapping>> {
Ok(ImportMapping::Alternatives(vec![ Ok(ImportMapping::Alternatives(vec![
// Prefer the local installed version over the next.js version // Prefer the local installed version over the next.js version
ImportMapping::PrimaryAlternative("postcss".to_string(), Some(project_path)).cell(), ImportMapping::PrimaryAlternative("postcss".to_string(), Some(project_path)).cell(),
@ -25,8 +24,8 @@ pub async fn get_postcss_package_mapping(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_external_next_compiled_package_mapping( pub async fn get_external_next_compiled_package_mapping(
package_name: StringVc, package_name: Vc<String>,
) -> Result<ImportMappingVc> { ) -> Result<Vc<ImportMapping>> {
Ok( Ok(
ImportMapping::Alternatives(vec![ImportMapping::External(Some(format!( ImportMapping::Alternatives(vec![ImportMapping::External(Some(format!(
"next/dist/compiled/{}", "next/dist/compiled/{}",

View file

@ -1,38 +1,33 @@
use core::{default::Default, result::Result::Ok}; use core::{default::Default, result::Result::Ok};
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{ use turbo_tasks::{Value, Vc};
primitives::{OptionStringVc, StringVc},
Value,
};
use turbo_tasks_fs::FileSystem; use turbo_tasks_fs::FileSystem;
use turbopack_binding::{ use turbopack_binding::{
turbo::{tasks_env::ProcessEnvVc, tasks_fs::FileSystemPathVc}, turbo::{tasks_env::ProcessEnv, tasks_fs::FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
compile_time_defines, compile_time_defines,
compile_time_info::{ compile_time_info::{
CompileTimeDefines, CompileTimeDefinesVc, CompileTimeInfo, CompileTimeInfoVc, CompileTimeDefines, CompileTimeInfo, FreeVarReference, FreeVarReferences,
FreeVarReference, FreeVarReferencesVc,
}, },
environment::{BrowserEnvironment, EnvironmentVc, ExecutionEnvironment}, environment::{BrowserEnvironment, Environment, ExecutionEnvironment},
free_var_references, free_var_references,
resolve::{parse::RequestVc, pattern::Pattern}, resolve::{parse::Request, pattern::Pattern},
}, },
dev::{react_refresh::assert_can_resolve_react_refresh, DevChunkingContextVc}, dev::{react_refresh::assert_can_resolve_react_refresh, DevChunkingContext},
ecmascript::{chunk::EcmascriptChunkingContextVc, TransformPluginVc}, ecmascript::chunk::EcmascriptChunkingContext,
ecmascript_plugin::transform::directives::server::ServerDirectiveTransformer, ecmascript_plugin::transform::directives::server::ServerDirectiveTransformer,
env::ProcessEnvAssetVc, env::ProcessEnvAsset,
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::{ turbopack::{
condition::ContextCondition, condition::ContextCondition,
module_options::{ module_options::{
module_options_context::{ModuleOptionsContext, ModuleOptionsContextVc}, module_options_context::ModuleOptionsContext, CustomEcmascriptTransformPlugins,
CustomEcmascriptTransformPlugins, CustomEcmascriptTransformPluginsVc,
JsxTransformOptions, MdxTransformModuleOptions, PostCssTransformOptions, JsxTransformOptions, MdxTransformModuleOptions, PostCssTransformOptions,
TypescriptTransformOptions, WebpackLoadersOptions, TypescriptTransformOptions, WebpackLoadersOptions,
}, },
resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, resolve_options_context::ResolveOptionsContext,
}, },
}, },
}; };
@ -44,14 +39,14 @@ use crate::{
env::env_for_js, env::env_for_js,
mode::NextMode, mode::NextMode,
next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping}, next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping},
next_client::runtime_entry::{RuntimeEntriesVc, RuntimeEntry}, next_client::runtime_entry::{RuntimeEntries, RuntimeEntry},
next_config::NextConfigVc, next_config::NextConfig,
next_import_map::{ next_import_map::{
get_next_client_fallback_import_map, get_next_client_import_map, get_next_client_fallback_import_map, get_next_client_import_map,
get_next_client_resolved_map, mdx_import_source_file, get_next_client_resolved_map, mdx_import_source_file,
}, },
next_shared::{ next_shared::{
resolve::UnsupportedModulesResolvePluginVc, resolve::UnsupportedModulesResolvePlugin,
transforms::{ transforms::{
emotion::get_emotion_transform_plugin, get_relay_transform_plugin, emotion::get_emotion_transform_plugin, get_relay_transform_plugin,
styled_components::get_styled_components_transform_plugin, styled_components::get_styled_components_transform_plugin,
@ -80,12 +75,12 @@ fn defines(mode: NextMode) -> CompileTimeDefines {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn next_client_defines(mode: NextMode) -> CompileTimeDefinesVc { fn next_client_defines(mode: NextMode) -> Vc<CompileTimeDefines> {
defines(mode).cell() defines(mode).cell()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn next_client_free_vars(mode: NextMode) -> Result<FreeVarReferencesVc> { async fn next_client_free_vars(mode: NextMode) -> Result<Vc<FreeVarReferences>> {
Ok(free_var_references!( Ok(free_var_references!(
..defines(mode).into_iter(), ..defines(mode).into_iter(),
Buffer = FreeVarReference::EcmaScriptModule { Buffer = FreeVarReference::EcmaScriptModule {
@ -103,18 +98,19 @@ async fn next_client_free_vars(mode: NextMode) -> Result<FreeVarReferencesVc> {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_client_compile_time_info(mode: NextMode, browserslist_query: &str) -> CompileTimeInfoVc { pub fn get_client_compile_time_info(
CompileTimeInfo::builder(EnvironmentVc::new(Value::new( mode: NextMode,
ExecutionEnvironment::Browser( browserslist_query: String,
BrowserEnvironment { ) -> Vc<CompileTimeInfo> {
dom: true, CompileTimeInfo::builder(Environment::new(Value::new(ExecutionEnvironment::Browser(
web_worker: false, BrowserEnvironment {
service_worker: false, dom: true,
browserslist_query: browserslist_query.to_owned(), web_worker: false,
} service_worker: false,
.into(), browserslist_query: browserslist_query.to_owned(),
), }
))) .into(),
))))
.defines(next_client_defines(mode)) .defines(next_client_defines(mode))
.free_var_references(next_client_free_vars(mode)) .free_var_references(next_client_free_vars(mode))
.cell() .cell()
@ -123,20 +119,20 @@ pub fn get_client_compile_time_info(mode: NextMode, browserslist_query: &str) ->
#[turbo_tasks::value(serialization = "auto_for_input")] #[turbo_tasks::value(serialization = "auto_for_input")]
#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)]
pub enum ClientContextType { pub enum ClientContextType {
Pages { pages_dir: FileSystemPathVc }, Pages { pages_dir: Vc<FileSystemPath> },
App { app_dir: FileSystemPathVc }, App { app_dir: Vc<FileSystemPath> },
Fallback, Fallback,
Other, Other,
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_client_resolve_options_context( pub async fn get_client_resolve_options_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
ty: Value<ClientContextType>, ty: Value<ClientContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<ResolveOptionsContextVc> { ) -> Result<Vc<ResolveOptionsContext>> {
let next_client_import_map = let next_client_import_map =
get_next_client_import_map(project_path, ty, next_config, execution_context); get_next_client_import_map(project_path, ty, next_config, execution_context);
let next_client_fallback_import_map = get_next_client_fallback_import_map(ty); let next_client_fallback_import_map = get_next_client_fallback_import_map(ty);
@ -149,7 +145,9 @@ pub async fn get_client_resolve_options_context(
resolved_map: Some(next_client_resolved_map), resolved_map: Some(next_client_resolved_map),
browser: true, browser: true,
module: true, module: true,
plugins: vec![UnsupportedModulesResolvePluginVc::new(project_path).into()], plugins: vec![Vc::upcast(UnsupportedModulesResolvePlugin::new(
project_path,
))],
..Default::default() ..Default::default()
}; };
Ok(ResolveOptionsContext { Ok(ResolveOptionsContext {
@ -166,13 +164,13 @@ pub async fn get_client_resolve_options_context(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_client_module_options_context( pub async fn get_client_module_options_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
env: EnvironmentVc, env: Vc<Environment>,
ty: Value<ClientContextType>, ty: Value<ClientContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<ModuleOptionsContextVc> { ) -> Result<Vc<ModuleOptionsContext>> {
let custom_rules = get_next_client_transforms_rules(next_config, ty.into_value(), mode).await?; let custom_rules = get_next_client_transforms_rules(next_config, ty.into_value(), mode).await?;
let resolve_options_context = let resolve_options_context =
get_client_resolve_options_context(project_path, ty, mode, next_config, execution_context); get_client_resolve_options_context(project_path, ty, mode, next_config, execution_context);
@ -197,9 +195,9 @@ pub async fn get_client_module_options_context(
let enable_webpack_loaders = webpack_rules.map(|rules| { let enable_webpack_loaders = webpack_rules.map(|rules| {
WebpackLoadersOptions { WebpackLoadersOptions {
rules, rules,
loader_runner_package: Some(get_external_next_compiled_package_mapping( loader_runner_package: Some(get_external_next_compiled_package_mapping(Vc::cell(
StringVc::cell("loader-runner".to_owned()), "loader-runner".to_owned(),
)), ))),
} }
.cell() .cell()
}); });
@ -210,19 +208,17 @@ pub async fn get_client_module_options_context(
*get_emotion_transform_plugin(next_config).await?, *get_emotion_transform_plugin(next_config).await?,
*get_styled_components_transform_plugin(next_config).await?, *get_styled_components_transform_plugin(next_config).await?,
*get_styled_jsx_transform_plugin().await?, *get_styled_jsx_transform_plugin().await?,
Some(TransformPluginVc::cell(Box::new( Some(Vc::cell(Box::new(ServerDirectiveTransformer::new(
ServerDirectiveTransformer::new( // ServerDirective is not implemented yet and always reports an issue.
// ServerDirective is not implemented yet and always reports an issue. // We don't have to pass a valid transition name yet, but the API is prepared.
// We don't have to pass a valid transition name yet, but the API is prepared. &Vc::cell("TODO".to_string()),
&StringVc::cell("TODO".to_string()), )) as _)),
),
))),
] ]
.into_iter() .into_iter()
.flatten() .flatten()
.collect(); .collect();
let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms, source_transforms,
output_transforms: vec![], output_transforms: vec![],
@ -280,43 +276,41 @@ pub async fn get_client_module_options_context(
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_client_chunking_context( pub fn get_client_chunking_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
client_root: FileSystemPathVc, client_root: Vc<FileSystemPath>,
environment: EnvironmentVc, environment: Vc<Environment>,
mode: NextMode, mode: NextMode,
) -> EcmascriptChunkingContextVc { ) -> Vc<Box<dyn EcmascriptChunkingContext>> {
let builder = DevChunkingContextVc::builder( let builder = DevChunkingContext::builder(
project_path, project_path,
client_root, client_root,
client_root.join("_next/static/chunks"), client_root.join("_next/static/chunks".to_string()),
get_client_assets_path(client_root), get_client_assets_path(client_root),
environment, environment,
); );
let builder = match mode { let builder = match mode {
NextMode::Development => builder.hot_module_replacement(), NextMode::Development => builder.hot_module_replacement(),
NextMode::Build => { NextMode::Build => builder.chunk_base_path(Vc::cell(Some("_next/".to_string()))),
builder.chunk_base_path(OptionStringVc::cell(Some("_next/".to_string())))
}
}; };
builder.build().into() Vc::upcast(builder.build())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_client_assets_path(client_root: FileSystemPathVc) -> FileSystemPathVc { pub fn get_client_assets_path(client_root: Vc<FileSystemPath>) -> Vc<FileSystemPath> {
client_root.join("_next/static/media") client_root.join("_next/static/media".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_client_runtime_entries( pub async fn get_client_runtime_entries(
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
env: ProcessEnvVc, env: Vc<Box<dyn ProcessEnv>>,
ty: Value<ClientContextType>, ty: Value<ClientContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<RuntimeEntriesVc> { ) -> Result<Vc<RuntimeEntries>> {
let mut runtime_entries = vec![]; let mut runtime_entries = vec![];
if matches!( if matches!(
@ -324,9 +318,10 @@ pub async fn get_client_runtime_entries(
ClientContextType::App { .. } | ClientContextType::Pages { .. }, ClientContextType::App { .. } | ClientContextType::Pages { .. },
) { ) {
runtime_entries.push( runtime_entries.push(
RuntimeEntry::Source( RuntimeEntry::Source(Vc::upcast(ProcessEnvAsset::new(
ProcessEnvAssetVc::new(project_root, env_for_js(env, true, next_config)).into(), project_root,
) env_for_js(env, true, next_config),
)))
.cell(), .cell(),
); );
} }
@ -349,17 +344,18 @@ pub async fn get_client_runtime_entries(
// because the bootstrap contains JSX which requires Refresh's global // because the bootstrap contains JSX which requires Refresh's global
// functions to be available. // functions to be available.
if let Some(request) = enable_react_refresh { if let Some(request) = enable_react_refresh {
runtime_entries.push(RuntimeEntry::Request(request, project_root.join("_")).cell()) runtime_entries
.push(RuntimeEntry::Request(request, project_root.join("_".to_string())).cell())
}; };
} }
NextMode::Build => match *ty { NextMode::Build => match *ty {
ClientContextType::App { .. } => { ClientContextType::App { .. } => {
runtime_entries.push( runtime_entries.push(
RuntimeEntry::Request( RuntimeEntry::Request(
RequestVc::parse(Value::new(Pattern::Constant( Request::parse(Value::new(Pattern::Constant(
"./build/client/app-bootstrap.ts".to_string(), "./build/client/app-bootstrap.ts".to_string(),
))), ))),
next_js_fs().root().join("_"), next_js_fs().root().join("_".to_string()),
) )
.cell(), .cell(),
); );
@ -367,10 +363,10 @@ pub async fn get_client_runtime_entries(
ClientContextType::Pages { .. } => { ClientContextType::Pages { .. } => {
runtime_entries.push( runtime_entries.push(
RuntimeEntry::Request( RuntimeEntry::Request(
RequestVc::parse(Value::new(Pattern::Constant( Request::parse(Value::new(Pattern::Constant(
"./build/client/bootstrap.ts".to_string(), "./build/client/bootstrap.ts".to_string(),
))), ))),
next_js_fs().root().join("_"), next_js_fs().root().join("_".to_string()),
) )
.cell(), .cell(),
); );
@ -379,5 +375,5 @@ pub async fn get_client_runtime_entries(
}, },
} }
Ok(RuntimeEntriesVc::cell(runtime_entries)) Ok(Vc::cell(runtime_entries))
} }

View file

@ -7,5 +7,5 @@ pub use context::{
get_client_chunking_context, get_client_compile_time_info, get_client_module_options_context, get_client_chunking_context, get_client_compile_time_info, get_client_module_options_context,
get_client_resolve_options_context, get_client_runtime_entries, ClientContextType, get_client_resolve_options_context, get_client_runtime_entries, ClientContextType,
}; };
pub use runtime_entry::{RuntimeEntries, RuntimeEntriesVc, RuntimeEntry, RuntimeEntryVc}; pub use runtime_entry::{RuntimeEntries, RuntimeEntry};
pub use transition::NextClientTransition; pub use transition::NextClientTransition;

View file

@ -1,14 +1,15 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::{tasks::ValueToString, tasks_fs::FileSystemPathVc}, turbo::{tasks::ValueToString, tasks_fs::FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
asset::Asset, asset::Asset,
chunk::{EvaluatableAssetVc, EvaluatableAssetsVc}, chunk::{EvaluatableAsset, EvaluatableAssetExt, EvaluatableAssets},
context::AssetContextVc, context::AssetContext,
issue::{IssueSeverity, OptionIssueSourceVc}, issue::{IssueSeverity, OptionIssueSource},
resolve::{origin::PlainResolveOriginVc, parse::RequestVc}, resolve::{origin::PlainResolveOrigin, parse::Request},
source::SourceVc, source::Source,
}, },
ecmascript::resolve::cjs_resolve, ecmascript::resolve::cjs_resolve,
}, },
@ -16,29 +17,30 @@ use turbopack_binding::{
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub enum RuntimeEntry { pub enum RuntimeEntry {
Request(RequestVc, FileSystemPathVc), Request(Vc<Request>, Vc<FileSystemPath>),
Evaluatable(EvaluatableAssetVc), Evaluatable(Vc<Box<dyn EvaluatableAsset>>),
Source(SourceVc), Source(Vc<Box<dyn Source>>),
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl RuntimeEntryVc { impl RuntimeEntry {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn resolve_entry(self, context: AssetContextVc) -> Result<EvaluatableAssetsVc> { pub async fn resolve_entry(
self: Vc<Self>,
context: Vc<Box<dyn AssetContext>>,
) -> Result<Vc<EvaluatableAssets>> {
let (request, path) = match *self.await? { let (request, path) = match *self.await? {
RuntimeEntry::Evaluatable(e) => return Ok(EvaluatableAssetsVc::one(e)), RuntimeEntry::Evaluatable(e) => return Ok(EvaluatableAssets::one(e)),
RuntimeEntry::Source(source) => { RuntimeEntry::Source(source) => {
return Ok(EvaluatableAssetsVc::one(EvaluatableAssetVc::from_source( return Ok(EvaluatableAssets::one(source.to_evaluatable(context)));
source, context,
)));
} }
RuntimeEntry::Request(r, path) => (r, path), RuntimeEntry::Request(r, path) => (r, path),
}; };
let assets = cjs_resolve( let assets = cjs_resolve(
PlainResolveOriginVc::new(context, path).into(), Vc::upcast(PlainResolveOrigin::new(context, path)),
request, request,
OptionIssueSourceVc::none(), OptionIssueSource::none(),
IssueSeverity::Error.cell(), IssueSeverity::Error.cell(),
) )
.primary_assets() .primary_assets()
@ -46,7 +48,9 @@ impl RuntimeEntryVc {
let mut runtime_entries = Vec::with_capacity(assets.len()); let mut runtime_entries = Vec::with_capacity(assets.len());
for asset in &assets { for asset in &assets {
if let Some(entry) = EvaluatableAssetVc::resolve_from(asset).await? { if let Some(entry) =
Vc::try_resolve_sidecast::<Box<dyn EvaluatableAsset>>(*asset).await?
{
runtime_entries.push(entry); runtime_entries.push(entry);
} else { } else {
bail!( bail!(
@ -56,17 +60,20 @@ impl RuntimeEntryVc {
} }
} }
Ok(EvaluatableAssetsVc::cell(runtime_entries)) Ok(Vc::cell(runtime_entries))
} }
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct RuntimeEntries(Vec<RuntimeEntryVc>); pub struct RuntimeEntries(Vec<Vc<RuntimeEntry>>);
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl RuntimeEntriesVc { impl RuntimeEntries {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn resolve_entries(self, context: AssetContextVc) -> Result<EvaluatableAssetsVc> { pub async fn resolve_entries(
self: Vc<Self>,
context: Vc<Box<dyn AssetContext>>,
) -> Result<Vc<EvaluatableAssets>> {
let mut runtime_entries = Vec::new(); let mut runtime_entries = Vec::new();
for reference in &self.await? { for reference in &self.await? {
@ -74,6 +81,6 @@ impl RuntimeEntriesVc {
runtime_entries.extend(&resolved_entries); runtime_entries.extend(&resolved_entries);
} }
Ok(EvaluatableAssetsVc::cell(runtime_entries)) Ok(Vc::cell(runtime_entries))
} }
} }

View file

@ -1,11 +1,12 @@
use anyhow::Result; use anyhow::Result;
use next_transform_strip_page_exports::ExportFilter; use next_transform_strip_page_exports::ExportFilter;
use turbo_tasks::Vc;
use turbopack_binding::turbopack::turbopack::module_options::ModuleRule; use turbopack_binding::turbopack::turbopack::module_options::ModuleRule;
use crate::{ use crate::{
mode::NextMode, mode::NextMode,
next_client::context::ClientContextType, next_client::context::ClientContextType,
next_config::NextConfigVc, next_config::NextConfig,
next_shared::transforms::{ next_shared::transforms::{
get_next_dynamic_transform_rule, get_next_font_transform_rule, get_next_image_rule, get_next_dynamic_transform_rule, get_next_font_transform_rule, get_next_image_rule,
get_next_modularize_imports_rule, get_next_pages_transforms_rule, get_next_modularize_imports_rule, get_next_pages_transforms_rule,
@ -15,7 +16,7 @@ use crate::{
/// Returns a list of module rules which apply client-side, Next.js-specific /// Returns a list of module rules which apply client-side, Next.js-specific
/// transforms. /// transforms.
pub async fn get_next_client_transforms_rules( pub async fn get_next_client_transforms_rules(
next_config: NextConfigVc, next_config: Vc<NextConfig>,
context_ty: ClientContextType, context_ty: ClientContextType,
mode: NextMode, mode: NextMode,
) -> Result<Vec<ModuleRule>> { ) -> Result<Vec<ModuleRule>> {

View file

@ -1,25 +1,20 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indexmap::indexmap; use indexmap::indexmap;
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
chunk::{ChunkingContext, ChunkingContextVc}, chunk::ChunkingContext, compile_time_info::CompileTimeInfo, context::AssetContext,
compile_time_info::CompileTimeInfoVc, module::Module, reference_type::ReferenceType,
context::AssetContext,
module::ModuleVc,
reference_type::{InnerAssetsVc, ReferenceType},
}, },
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{ turbopack::{
ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset,
module_options::ModuleOptionsContextVc, module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext,
resolve_options_context::ResolveOptionsContextVc, transition::Transition, ModuleAssetContext,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}; };
use super::runtime_entry::RuntimeEntriesVc; use super::runtime_entry::RuntimeEntries;
use crate::embed_js::next_asset; use crate::embed_js::next_asset;
/// Makes a transition into a next.js client context. /// Makes a transition into a next.js client context.
@ -30,11 +25,11 @@ use crate::embed_js::next_asset;
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextClientTransition { pub struct NextClientTransition {
pub is_app: bool, pub is_app: bool,
pub client_compile_time_info: CompileTimeInfoVc, pub client_compile_time_info: Vc<CompileTimeInfo>,
pub client_module_options_context: ModuleOptionsContextVc, pub client_module_options_context: Vc<ModuleOptionsContext>,
pub client_resolve_options_context: ResolveOptionsContextVc, pub client_resolve_options_context: Vc<ResolveOptionsContext>,
pub client_chunking_context: ChunkingContextVc, pub client_chunking_context: Vc<Box<dyn ChunkingContext>>,
pub runtime_entries: RuntimeEntriesVc, pub runtime_entries: Vc<RuntimeEntries>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
@ -42,60 +37,65 @@ impl Transition for NextClientTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_compile_time_info( fn process_compile_time_info(
&self, &self,
_compile_time_info: CompileTimeInfoVc, _compile_time_info: Vc<CompileTimeInfo>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
self.client_compile_time_info self.client_compile_time_info
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_module_options_context( fn process_module_options_context(
&self, &self,
_context: ModuleOptionsContextVc, _context: Vc<ModuleOptionsContext>,
) -> ModuleOptionsContextVc { ) -> Vc<ModuleOptionsContext> {
self.client_module_options_context self.client_module_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_resolve_options_context( fn process_resolve_options_context(
&self, &self,
_context: ResolveOptionsContextVc, _context: Vc<ResolveOptionsContext>,
) -> ResolveOptionsContextVc { ) -> Vc<ResolveOptionsContext> {
self.client_resolve_options_context self.client_resolve_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
&self, &self,
asset: ModuleVc, asset: Vc<Box<dyn Module>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let asset = if !self.is_app { let asset = if !self.is_app {
let internal_asset = next_asset("entry/next-hydrate.tsx"); let internal_asset = next_asset("entry/next-hydrate.tsx".to_string());
context.process( context.process(
internal_asset, internal_asset,
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(indexmap! { Value::new(ReferenceType::Internal(Vc::cell(indexmap! {
"PAGE".to_string() => asset.into() "PAGE".to_string() => Vc::upcast(asset)
}))), }))),
) )
} else { } else {
asset asset
}; };
let Some(asset) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? else { let Some(asset) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(asset).await?
else {
bail!("not an ecmascript placeable module"); bail!("not an ecmascript placeable module");
}; };
let runtime_entries = self.runtime_entries.resolve_entries(context.into()); let runtime_entries = self.runtime_entries.resolve_entries(Vc::upcast(context));
let asset = ChunkGroupFilesAsset { let asset = ChunkGroupFilesAsset {
module: asset.into(), module: Vc::upcast(asset),
// This ensures that the chunk group files asset will strip out the _next prefix from // This ensures that the chunk group files asset will strip out the _next prefix from
// all chunk paths, which is what the Next.js renderer code expects. // all chunk paths, which is what the Next.js renderer code expects.
client_root: self.client_chunking_context.output_root().join("_next"), client_root: self
.client_chunking_context
.output_root()
.join("_next".to_string()),
chunking_context: self.client_chunking_context, chunking_context: self.client_chunking_context,
runtime_entries: Some(runtime_entries), runtime_entries: Some(runtime_entries),
}; };
Ok(asset.cell().into()) Ok(Vc::upcast(asset.cell()))
} }
} }

View file

@ -1,50 +1,48 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{compile_time_info::CompileTimeInfoVc, module::ModuleVc}, core::{compile_time_info::CompileTimeInfo, module::Module},
ecmascript::chunk::EcmascriptChunkingContextVc, ecmascript::chunk::EcmascriptChunkingContext,
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::{ turbopack::{
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable, module_options::ModuleOptionsContext,
module_options::ModuleOptionsContextVc, resolve_options_context::ResolveOptionsContext, transition::Transition,
resolve_options_context::ResolveOptionsContextVc, ModuleAssetContext,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}, },
}; };
use super::with_chunks::WithChunksAssetVc; use super::with_chunks::WithChunksAsset;
use crate::{ use crate::{
mode::NextMode, mode::NextMode,
next_client::context::{ next_client::context::{
get_client_module_options_context, get_client_resolve_options_context, ClientContextType, get_client_module_options_context, get_client_resolve_options_context, ClientContextType,
}, },
next_config::NextConfigVc, next_config::NextConfig,
}; };
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextClientChunksTransition { pub struct NextClientChunksTransition {
pub client_compile_time_info: CompileTimeInfoVc, pub client_compile_time_info: Vc<CompileTimeInfo>,
pub client_module_options_context: ModuleOptionsContextVc, pub client_module_options_context: Vc<ModuleOptionsContext>,
pub client_resolve_options_context: ResolveOptionsContextVc, pub client_resolve_options_context: Vc<ResolveOptionsContext>,
pub client_chunking_context: EcmascriptChunkingContextVc, pub client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextClientChunksTransitionVc { impl NextClientChunksTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new( pub fn new(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
ty: Value<ClientContextType>, ty: Value<ClientContextType>,
mode: NextMode, mode: NextMode,
client_chunking_context: EcmascriptChunkingContextVc, client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
client_compile_time_info: CompileTimeInfoVc, client_compile_time_info: Vc<CompileTimeInfo>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> NextClientChunksTransitionVc { ) -> Vc<NextClientChunksTransition> {
let client_module_options_context = get_client_module_options_context( let client_module_options_context = get_client_module_options_context(
project_path, project_path,
execution_context, execution_context,
@ -74,36 +72,41 @@ impl Transition for NextClientChunksTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_compile_time_info( fn process_compile_time_info(
&self, &self,
_compile_time_info: CompileTimeInfoVc, _compile_time_info: Vc<CompileTimeInfo>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
self.client_compile_time_info self.client_compile_time_info
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_module_options_context( fn process_module_options_context(
&self, &self,
_context: ModuleOptionsContextVc, _context: Vc<ModuleOptionsContext>,
) -> ModuleOptionsContextVc { ) -> Vc<ModuleOptionsContext> {
self.client_module_options_context self.client_module_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_resolve_options_context( fn process_resolve_options_context(
&self, &self,
_context: ResolveOptionsContextVc, _context: Vc<ResolveOptionsContext>,
) -> ResolveOptionsContextVc { ) -> Vc<ResolveOptionsContext> {
self.client_resolve_options_context self.client_resolve_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
&self, &self,
asset: ModuleVc, asset: Vc<Box<dyn Module>>,
_context: ModuleAssetContextVc, _context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
Ok( Ok(
if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { if let Some(placeable) =
WithChunksAssetVc::new(placeable, self.client_chunking_context).into() Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(asset).await?
{
Vc::upcast(WithChunksAsset::new(
placeable,
self.client_chunking_context,
))
} else { } else {
asset asset
}, },

View file

@ -1,48 +1,44 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{availability_info::AvailabilityInfo, Chunk, ChunkableModule, ChunkingContext},
availability_info::AvailabilityInfo, ChunkVc, ChunkableModule, ChunkableModuleVc, ident::AssetIdent,
ChunkingContextVc, module::Module,
}, reference::AssetReferences,
ident::AssetIdentVc,
module::{Module, ModuleVc},
reference::AssetReferencesVc,
}, },
ecmascript::chunk::EcmascriptChunkingContextVc, ecmascript::chunk::EcmascriptChunkingContext,
turbopack::ecmascript::chunk::{ turbopack::ecmascript::chunk::{
EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkPlaceable, EcmascriptExports,
EcmascriptChunkVc, EcmascriptExportsVc,
}, },
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
fn modifier() -> StringVc { fn modifier() -> Vc<String> {
StringVc::cell("in chunking context".to_string()) Vc::cell("in chunking context".to_string())
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct InChunkingContextAsset { pub struct InChunkingContextAsset {
pub asset: EcmascriptChunkPlaceableVc, pub asset: Vc<Box<dyn EcmascriptChunkPlaceable>>,
pub chunking_context: ChunkingContextVc, pub chunking_context: Vc<Box<dyn ChunkingContext>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for InChunkingContextAsset { impl Asset for InChunkingContextAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.asset.ident().with_modifier(modifier()) self.asset.ident().with_modifier(modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> AssetContentVc { fn content(&self) -> Vc<AssetContent> {
self.asset.content() self.asset.content()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc { fn references(&self) -> Vc<AssetReferences> {
self.asset.references() self.asset.references()
} }
} }
@ -55,10 +51,14 @@ impl ChunkableModule for InChunkingContextAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk( fn as_chunk(
&self, &self,
_context: ChunkingContextVc, _context: Vc<Box<dyn ChunkingContext>>,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> ChunkVc { ) -> Vc<Box<dyn Chunk>> {
EcmascriptChunkVc::new(self.chunking_context, self.asset, availability_info).into() Vc::upcast(EcmascriptChunk::new(
self.chunking_context,
self.asset,
availability_info,
))
} }
} }
@ -67,10 +67,11 @@ impl EcmascriptChunkPlaceable for InChunkingContextAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn as_chunk_item( async fn as_chunk_item(
&self, &self,
_context: EcmascriptChunkingContextVc, _context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<EcmascriptChunkItemVc> { ) -> Result<Vc<Box<dyn EcmascriptChunkItem>>> {
let Some(chunking_context) = let Some(chunking_context) =
EcmascriptChunkingContextVc::resolve_from(&self.chunking_context).await? Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkingContext>>(self.chunking_context)
.await?
else { else {
bail!("chunking context is not an EcmascriptChunkingContext") bail!("chunking context is not an EcmascriptChunkingContext")
}; };
@ -78,7 +79,7 @@ impl EcmascriptChunkPlaceable for InChunkingContextAsset {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_exports(&self) -> EcmascriptExportsVc { fn get_exports(&self) -> Vc<EcmascriptExports> {
self.asset.get_exports() self.asset.get_exports()
} }
} }

View file

@ -2,4 +2,4 @@ pub(crate) mod client_chunks_transition;
pub(crate) mod in_chunking_context_asset; pub(crate) mod in_chunking_context_asset;
pub(crate) mod with_chunks; pub(crate) mod with_chunks;
pub use client_chunks_transition::NextClientChunksTransitionVc; pub use client_chunks_transition::NextClientChunksTransition;

View file

@ -2,30 +2,29 @@ use std::io::Write;
use anyhow::Result; use anyhow::Result;
use indoc::writedoc; use indoc::writedoc;
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{
tasks::{primitives::StringVc, TryJoinIterExt, Value}, tasks::{TryJoinIterExt, Value},
tasks_fs::rope::RopeBuilder, tasks_fs::rope::RopeBuilder,
}, },
turbopack::{ turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{
availability_info::AvailabilityInfo, ChunkDataVc, ChunkGroupReferenceVc, ChunkItem, availability_info::AvailabilityInfo, Chunk, ChunkData, ChunkGroupReference,
ChunkItemVc, ChunkVc, ChunkableModule, ChunkableModuleVc, ChunkingContext, ChunkItem, ChunkableModule, ChunkingContext, ChunksData,
ChunkingContextVc, ChunksDataVc,
}, },
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
output::OutputAssetsVc, output::OutputAssets,
reference::AssetReferencesVc, reference::AssetReferences,
}, },
ecmascript::{ ecmascript::{
chunk::{ chunk::{
EcmascriptChunkData, EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunk, EcmascriptChunkData, EcmascriptChunkItem,
EcmascriptChunkItemContentVc, EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkItemContent, EcmascriptChunkItemExt, EcmascriptChunkPlaceable,
EcmascriptChunkPlaceableVc, EcmascriptChunkVc, EcmascriptChunkingContextVc, EcmascriptChunkingContext, EcmascriptExports,
EcmascriptExports, EcmascriptExportsVc,
}, },
utils::StringifyJs, utils::StringifyJs,
}, },
@ -33,18 +32,18 @@ use turbopack_binding::{
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
fn modifier() -> StringVc { fn modifier() -> Vc<String> {
StringVc::cell("chunks".to_string()) Vc::cell("chunks".to_string())
} }
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct WithChunksAsset { pub struct WithChunksAsset {
asset: EcmascriptChunkPlaceableVc, asset: Vc<Box<dyn EcmascriptChunkPlaceable>>,
chunking_context: EcmascriptChunkingContextVc, chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl WithChunksAssetVc { impl WithChunksAsset {
/// Create a new [`WithChunksAsset`]. /// Create a new [`WithChunksAsset`].
/// ///
/// # Arguments /// # Arguments
@ -53,23 +52,23 @@ impl WithChunksAssetVc {
/// * `chunking_context` - The chunking context of the asset. /// * `chunking_context` - The chunking context of the asset.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new( pub fn new(
asset: EcmascriptChunkPlaceableVc, asset: Vc<Box<dyn EcmascriptChunkPlaceable>>,
chunking_context: EcmascriptChunkingContextVc, chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> WithChunksAssetVc { ) -> Vc<WithChunksAsset> {
WithChunksAssetVc::cell(WithChunksAsset { WithChunksAsset::cell(WithChunksAsset {
asset, asset,
chunking_context, chunking_context,
}) })
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn entry_chunk(self) -> Result<ChunkVc> { async fn entry_chunk(self: Vc<Self>) -> Result<Vc<Box<dyn Chunk>>> {
let this = self.await?; let this = self.await?;
Ok(this.asset.as_root_chunk(this.chunking_context.into())) Ok(this.asset.as_root_chunk(Vc::upcast(this.chunking_context)))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn chunks(self) -> Result<OutputAssetsVc> { async fn chunks(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
let this = self.await?; let this = self.await?;
Ok(this.chunking_context.chunk_group(self.entry_chunk())) Ok(this.chunking_context.chunk_group(self.entry_chunk()))
} }
@ -78,25 +77,24 @@ impl WithChunksAssetVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for WithChunksAsset { impl Asset for WithChunksAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.asset.ident().with_modifier(modifier()) self.asset.ident().with_modifier(modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> AssetContentVc { fn content(&self) -> Vc<AssetContent> {
unimplemented!() unimplemented!()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn references(self_vc: WithChunksAssetVc) -> Result<AssetReferencesVc> { async fn references(self: Vc<Self>) -> Result<Vc<AssetReferences>> {
let this = self_vc.await?; let this = self.await?;
let entry_chunk = self_vc.entry_chunk(); let entry_chunk = self.entry_chunk();
Ok(AssetReferencesVc::cell(vec![ChunkGroupReferenceVc::new( Ok(Vc::cell(vec![Vc::upcast(ChunkGroupReference::new(
this.chunking_context.into(), Vc::upcast(this.chunking_context),
entry_chunk, entry_chunk,
) ))]))
.into()]))
} }
} }
@ -107,16 +105,15 @@ impl Module for WithChunksAsset {}
impl ChunkableModule for WithChunksAsset { impl ChunkableModule for WithChunksAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk( fn as_chunk(
self_vc: WithChunksAssetVc, self: Vc<Self>,
context: ChunkingContextVc, context: Vc<Box<dyn ChunkingContext>>,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> ChunkVc { ) -> Vc<Box<dyn Chunk>> {
EcmascriptChunkVc::new( Vc::upcast(EcmascriptChunk::new(
context, context,
self_vc.as_ecmascript_chunk_placeable(), Vc::upcast(self),
availability_info, availability_info,
) ))
.into()
} }
} }
@ -124,19 +121,20 @@ impl ChunkableModule for WithChunksAsset {
impl EcmascriptChunkPlaceable for WithChunksAsset { impl EcmascriptChunkPlaceable for WithChunksAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn as_chunk_item( async fn as_chunk_item(
self_vc: WithChunksAssetVc, self: Vc<Self>,
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<EcmascriptChunkItemVc> { ) -> Result<Vc<Box<dyn EcmascriptChunkItem>>> {
Ok(WithChunksChunkItem { Ok(Vc::upcast(
context, WithChunksChunkItem {
inner: self_vc, context,
} inner: self,
.cell() }
.into()) .cell(),
))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_exports(&self) -> EcmascriptExportsVc { fn get_exports(&self) -> Vc<EcmascriptExports> {
// TODO This should be EsmExports // TODO This should be EsmExports
EcmascriptExports::Value.cell() EcmascriptExports::Value.cell()
} }
@ -144,17 +142,17 @@ impl EcmascriptChunkPlaceable for WithChunksAsset {
#[turbo_tasks::value] #[turbo_tasks::value]
struct WithChunksChunkItem { struct WithChunksChunkItem {
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
inner: WithChunksAssetVc, inner: Vc<WithChunksAsset>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl WithChunksChunkItemVc { impl WithChunksChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn chunks_data(self) -> Result<ChunksDataVc> { async fn chunks_data(self: Vc<Self>) -> Result<Vc<ChunksData>> {
let this = self.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
Ok(ChunkDataVc::from_assets( Ok(ChunkData::from_assets(
inner.chunking_context.output_root(), inner.chunking_context.output_root(),
this.inner.chunks(), this.inner.chunks(),
)) ))
@ -164,16 +162,16 @@ impl WithChunksChunkItemVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl EcmascriptChunkItem for WithChunksChunkItem { impl EcmascriptChunkItem for WithChunksChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn chunking_context(&self) -> EcmascriptChunkingContextVc { fn chunking_context(&self) -> Vc<Box<dyn EcmascriptChunkingContext>> {
self.context self.context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn content(self_vc: WithChunksChunkItemVc) -> Result<EcmascriptChunkItemContentVc> { async fn content(self: Vc<Self>) -> Result<Vc<EcmascriptChunkItemContent>> {
let this = self_vc.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
let chunks_data = self_vc.chunks_data().await?; let chunks_data = self.chunks_data().await?;
let chunks_data = chunks_data.iter().try_join().await?; let chunks_data = chunks_data.iter().try_join().await?;
let chunks_data: Vec<_> = chunks_data let chunks_data: Vec<_> = chunks_data
.iter() .iter()
@ -212,18 +210,18 @@ impl EcmascriptChunkItem for WithChunksChunkItem {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ChunkItem for WithChunksChunkItem { impl ChunkItem for WithChunksChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn asset_ident(&self) -> AssetIdentVc { fn asset_ident(&self) -> Vc<AssetIdent> {
self.inner.ident() self.inner.ident()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn references(self_vc: WithChunksChunkItemVc) -> Result<AssetReferencesVc> { async fn references(self: Vc<Self>) -> Result<Vc<AssetReferences>> {
let mut references = self_vc.await?.inner.references().await?.clone_value(); let mut references = self.await?.inner.references().await?.clone_value();
for chunk_data in &*self_vc.chunks_data().await? { for chunk_data in &*self.chunks_data().await? {
references.extend(chunk_data.references().await?.iter().copied()); references.extend(chunk_data.references().await?.iter().copied());
} }
Ok(AssetReferencesVc::cell(references)) Ok(Vc::cell(references))
} }
} }

View file

@ -1,17 +1,14 @@
use anyhow::Result; use anyhow::Result;
use indexmap::indexmap; use indexmap::indexmap;
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
context::AssetContext, context::AssetContext,
module::ModuleVc, module::Module,
reference_type::{EntryReferenceSubType, InnerAssetsVc, ReferenceType}, reference_type::{EntryReferenceSubType, ReferenceType},
source::SourceVc, source::Source,
},
turbopack::{
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
turbopack::{transition::Transition, ModuleAssetContext},
}; };
use crate::embed_js::next_asset; use crate::embed_js::next_asset;
@ -25,43 +22,47 @@ pub struct NextServerToClientTransition {
impl Transition for NextServerToClientTransition { impl Transition for NextServerToClientTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process( async fn process(
self_vc: NextServerToClientTransitionVc, self: Vc<Self>,
source: SourceVc, source: Vc<Box<dyn Source>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
_reference_type: Value<ReferenceType>, _reference_type: Value<ReferenceType>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let this = self_vc.await?; let this = self.await?;
let context = self_vc.process_context(context); let context = self.process_context(context);
let client_chunks = context.with_transition("next-client-chunks").process( let client_chunks = context
source, .with_transition("next-client-chunks".to_string())
Value::new(ReferenceType::Entry( .process(
EntryReferenceSubType::AppClientComponent, source,
)), Value::new(ReferenceType::Entry(
); EntryReferenceSubType::AppClientComponent,
)),
);
Ok(match this.ssr { Ok(match this.ssr {
true => { true => {
let internal_source = next_asset("entry/app/server-to-client-ssr.tsx"); let internal_source = next_asset("entry/app/server-to-client-ssr.tsx".to_string());
let client_module = context.with_transition("next-ssr-client-module").process( let client_module = context
source, .with_transition("next-ssr-client-module".to_string())
Value::new(ReferenceType::Entry( .process(
EntryReferenceSubType::AppClientComponent, source,
)), Value::new(ReferenceType::Entry(
); EntryReferenceSubType::AppClientComponent,
)),
);
context.process( context.process(
internal_source, internal_source,
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(indexmap! { Value::new(ReferenceType::Internal(Vc::cell(indexmap! {
"CLIENT_MODULE".to_string() => client_module.into(), "CLIENT_MODULE".to_string() => Vc::upcast(client_module),
"CLIENT_CHUNKS".to_string() => client_chunks.into(), "CLIENT_CHUNKS".to_string() => Vc::upcast(client_chunks),
}))), }))),
) )
} }
false => { false => {
let internal_source = next_asset("entry/app/server-to-client.tsx"); let internal_source = next_asset("entry/app/server-to-client.tsx".to_string());
context.process( context.process(
internal_source, internal_source,
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(indexmap! { Value::new(ReferenceType::Internal(Vc::cell(indexmap! {
"CLIENT_CHUNKS".to_string() => client_chunks.into(), "CLIENT_CHUNKS".to_string() => Vc::upcast(client_chunks),
}))), }))),
) )
} }

View file

@ -1,12 +1,10 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::Vc;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{compile_time_info::CompileTimeInfoVc, module::ModuleVc}, core::{compile_time_info::CompileTimeInfo, module::Module},
turbopack::{ turbopack::{
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable, module_options::ModuleOptionsContext,
module_options::ModuleOptionsContextVc, resolve_options_context::ResolveOptionsContext, transition::Transition, ModuleAssetContext,
resolve_options_context::ResolveOptionsContextVc,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}; };
@ -14,9 +12,9 @@ use super::with_chunking_context_scope_asset::WithChunkingContextScopeAsset;
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextSSRClientModuleTransition { pub struct NextSSRClientModuleTransition {
pub ssr_environment: CompileTimeInfoVc, pub ssr_environment: Vc<CompileTimeInfo>,
pub ssr_module_options_context: ModuleOptionsContextVc, pub ssr_module_options_context: Vc<ModuleOptionsContext>,
pub ssr_resolve_options_context: ResolveOptionsContextVc, pub ssr_resolve_options_context: Vc<ResolveOptionsContext>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
@ -24,41 +22,44 @@ impl Transition for NextSSRClientModuleTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_compile_time_info( fn process_compile_time_info(
&self, &self,
_compile_time_info: CompileTimeInfoVc, _compile_time_info: Vc<CompileTimeInfo>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
self.ssr_environment self.ssr_environment
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_module_options_context( fn process_module_options_context(
&self, &self,
_context: ModuleOptionsContextVc, _context: Vc<ModuleOptionsContext>,
) -> ModuleOptionsContextVc { ) -> Vc<ModuleOptionsContext> {
self.ssr_module_options_context self.ssr_module_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_resolve_options_context( fn process_resolve_options_context(
&self, &self,
_context: ResolveOptionsContextVc, _context: Vc<ResolveOptionsContext>,
) -> ResolveOptionsContextVc { ) -> Vc<ResolveOptionsContext> {
self.ssr_resolve_options_context self.ssr_resolve_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
&self, &self,
asset: ModuleVc, asset: Vc<Box<dyn Module>>,
_context: ModuleAssetContextVc, _context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
Ok( Ok(
if let Some(placeable) = EcmascriptChunkPlaceableVc::resolve_from(asset).await? { if let Some(placeable) =
WithChunkingContextScopeAsset { Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(asset).await?
asset: placeable, {
layer: "ssr".to_string(), Vc::upcast(
} WithChunkingContextScopeAsset {
.cell() asset: placeable,
.into() layer: "ssr".to_string(),
}
.cell(),
)
} else { } else {
asset asset
}, },

View file

@ -1,48 +1,44 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{availability_info::AvailabilityInfo, Chunk, ChunkableModule, ChunkingContext},
availability_info::AvailabilityInfo, ChunkVc, ChunkableModule, ChunkableModuleVc, ident::AssetIdent,
ChunkingContext, ChunkingContextVc, module::Module,
}, reference::AssetReferences,
ident::AssetIdentVc,
module::{Module, ModuleVc},
reference::AssetReferencesVc,
}, },
ecmascript::chunk::EcmascriptChunkingContextVc, ecmascript::chunk::EcmascriptChunkingContext,
turbopack::ecmascript::chunk::{ turbopack::ecmascript::chunk::{
EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkPlaceable, EcmascriptExports,
EcmascriptChunkVc, EcmascriptExportsVc,
}, },
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
fn modifier() -> StringVc { fn modifier() -> Vc<String> {
StringVc::cell("with chunking context scope".to_string()) Vc::cell("with chunking context scope".to_string())
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct WithChunkingContextScopeAsset { pub struct WithChunkingContextScopeAsset {
pub asset: EcmascriptChunkPlaceableVc, pub asset: Vc<Box<dyn EcmascriptChunkPlaceable>>,
pub layer: String, pub layer: String,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for WithChunkingContextScopeAsset { impl Asset for WithChunkingContextScopeAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.asset.ident().with_modifier(modifier()) self.asset.ident().with_modifier(modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> AssetContentVc { fn content(&self) -> Vc<AssetContent> {
self.asset.content() self.asset.content()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc { fn references(&self) -> Vc<AssetReferences> {
self.asset.references() self.asset.references()
} }
} }
@ -55,15 +51,14 @@ impl ChunkableModule for WithChunkingContextScopeAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk( fn as_chunk(
&self, &self,
context: ChunkingContextVc, context: Vc<Box<dyn ChunkingContext>>,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> ChunkVc { ) -> Vc<Box<dyn Chunk>> {
EcmascriptChunkVc::new( Vc::upcast(EcmascriptChunk::new(
context.with_layer(&self.layer), context.with_layer(self.layer.clone()),
self.asset, self.asset,
availability_info, availability_info,
) ))
.into()
} }
} }
@ -72,20 +67,22 @@ impl EcmascriptChunkPlaceable for WithChunkingContextScopeAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn as_chunk_item( async fn as_chunk_item(
&self, &self,
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<EcmascriptChunkItemVc> { ) -> Result<Vc<Box<dyn EcmascriptChunkItem>>> {
Ok(self.asset.as_chunk_item( Ok(self.asset.as_chunk_item(
EcmascriptChunkingContextVc::resolve_from(context.with_layer(&self.layer)) Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkingContext>>(
.await? context.with_layer(self.layer.clone()),
.context( )
"ChunkingContextVc::with_layer should not return a different kind of chunking \ .await?
context", .context(
)?, "ChunkingContext::with_layer should not return a different kind of chunking \
context",
)?,
)) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_exports(&self) -> EcmascriptExportsVc { fn get_exports(&self) -> Vc<EcmascriptExports> {
self.asset.get_exports() self.asset.get_exports()
} }
} }

View file

@ -1,33 +1,28 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use indoc::formatdoc; use indoc::formatdoc;
use turbo_tasks::{primitives::StringVc, TryJoinIterExt, Value, ValueToString, ValueToStringVc}; use turbo_tasks::{TryJoinIterExt, Value, ValueToString, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{
availability_info::AvailabilityInfo, ChunkDataVc, ChunkItem, ChunkItemVc, ChunkVc, availability_info::AvailabilityInfo, Chunk, ChunkData, ChunkItem, ChunkableModule,
ChunkableModule, ChunkableModuleReference, ChunkableModuleReferenceVc, ChunkableModuleReference, ChunkingContext, ChunkingType, ChunkingTypeOption,
ChunkableModuleVc, ChunkingContext, ChunkingContextVc, ChunkingType, ChunksData,
ChunkingTypeOptionVc, ChunksDataVc,
}, },
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
output::OutputAssetsVc, output::OutputAssets,
proxied_asset::ProxiedAssetVc, proxied_asset::ProxiedAsset,
reference::{ reference::{AssetReference, AssetReferences, SingleAssetReference},
AssetReference, AssetReferenceVc, AssetReferencesVc, SingleAssetReferenceVc, resolve::ResolveResult,
},
resolve::{ResolveResult, ResolveResultVc},
}, },
ecmascript::chunk::EcmascriptChunkData, ecmascript::chunk::{EcmascriptChunkData, EcmascriptChunkItemExt},
turbopack::ecmascript::{ turbopack::ecmascript::{
chunk::{ chunk::{
EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkItemContent,
EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkPlaceable, EcmascriptChunkingContext, EcmascriptExports,
EcmascriptChunkVc, EcmascriptChunkingContextVc, EcmascriptExports,
EcmascriptExportsVc,
}, },
utils::StringifyJs, utils::StringifyJs,
}, },
@ -35,35 +30,36 @@ use turbopack_binding::{
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
fn modifier() -> StringVc { fn modifier() -> Vc<String> {
StringVc::cell("client chunks".to_string()) Vc::cell("client chunks".to_string())
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct WithClientChunksAsset { pub struct WithClientChunksAsset {
pub asset: EcmascriptChunkPlaceableVc, pub asset: Vc<Box<dyn EcmascriptChunkPlaceable>>,
pub server_root: FileSystemPathVc, pub server_root: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for WithClientChunksAsset { impl Asset for WithClientChunksAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.asset.ident().with_modifier(modifier()) self.asset.ident().with_modifier(modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> AssetContentVc { fn content(&self) -> Vc<AssetContent> {
unimplemented!() unimplemented!()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc { fn references(&self) -> Vc<AssetReferences> {
AssetReferencesVc::cell(vec![WithClientChunksAssetReference { Vc::cell(vec![Vc::upcast(
asset: self.asset.into(), WithClientChunksAssetReference {
} asset: Vc::upcast(self.asset),
.cell() }
.into()]) .cell(),
)])
} }
} }
@ -74,16 +70,15 @@ impl Module for WithClientChunksAsset {}
impl ChunkableModule for WithClientChunksAsset { impl ChunkableModule for WithClientChunksAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk( fn as_chunk(
self_vc: WithClientChunksAssetVc, self: Vc<Self>,
context: ChunkingContextVc, context: Vc<Box<dyn ChunkingContext>>,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> ChunkVc { ) -> Vc<Box<dyn Chunk>> {
EcmascriptChunkVc::new( Vc::upcast(EcmascriptChunk::new(
context.with_layer("rsc"), context.with_layer("rsc".to_string()),
self_vc.as_ecmascript_chunk_placeable(), Vc::upcast(self),
availability_info, availability_info,
) ))
.into()
} }
} }
@ -91,24 +86,27 @@ impl ChunkableModule for WithClientChunksAsset {
impl EcmascriptChunkPlaceable for WithClientChunksAsset { impl EcmascriptChunkPlaceable for WithClientChunksAsset {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn as_chunk_item( async fn as_chunk_item(
self_vc: WithClientChunksAssetVc, self: Vc<Self>,
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<EcmascriptChunkItemVc> { ) -> Result<Vc<Box<dyn EcmascriptChunkItem>>> {
Ok(WithClientChunksChunkItem { Ok(Vc::upcast(
context: EcmascriptChunkingContextVc::resolve_from(context.with_layer("rsc")) WithClientChunksChunkItem {
context: Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkingContext>>(
context.with_layer("rsc".to_string()),
)
.await? .await?
.context( .context(
"ChunkingContextVc::with_layer should not return a different kind of chunking \ "ChunkingContext::with_layer should not return a different kind of chunking \
context", context",
)?, )?,
inner: self_vc, inner: self,
} }
.cell() .cell(),
.into()) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_exports(&self) -> EcmascriptExportsVc { fn get_exports(&self) -> Vc<EcmascriptExports> {
// TODO This should be EsmExports // TODO This should be EsmExports
EcmascriptExports::Value.cell() EcmascriptExports::Value.cell()
} }
@ -116,23 +114,23 @@ impl EcmascriptChunkPlaceable for WithClientChunksAsset {
#[turbo_tasks::value] #[turbo_tasks::value]
struct WithClientChunksChunkItem { struct WithClientChunksChunkItem {
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
inner: WithClientChunksAssetVc, inner: Vc<WithClientChunksAsset>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl WithClientChunksChunkItemVc { impl WithClientChunksChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn chunks(self) -> Result<OutputAssetsVc> { async fn chunks(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
let this = self.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
Ok(this Ok(this
.context .context
.chunk_group(inner.asset.as_root_chunk(this.context.into()))) .chunk_group(inner.asset.as_root_chunk(Vc::upcast(this.context))))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn client_chunks(self) -> Result<OutputAssetsVc> { async fn client_chunks(self: Vc<Self>) -> Result<Vc<OutputAssets>> {
let this = self.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
let chunks = self.chunks(); let chunks = self.chunks();
@ -144,21 +142,22 @@ impl WithClientChunksChunkItemVc {
// Only expose CSS chunks as client chunks. // Only expose CSS chunks as client chunks.
if &*extension == "css" { if &*extension == "css" {
if let Some(path) = output_root.get_path_to(&*chunk.ident().path().await?) { if let Some(path) = output_root.get_path_to(&*chunk.ident().path().await?) {
client_chunks.push( client_chunks.push(Vc::upcast(ProxiedAsset::new(
ProxiedAssetVc::new(chunk.into(), inner.server_root.join(path)).into(), Vc::upcast(chunk),
); inner.server_root.join(path.to_string()),
)));
} }
} }
} }
Ok(OutputAssetsVc::cell(client_chunks)) Ok(Vc::cell(client_chunks))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn chunks_data(self) -> Result<ChunksDataVc> { async fn chunks_data(self: Vc<Self>) -> Result<Vc<ChunksData>> {
let this = self.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
Ok(ChunkDataVc::from_assets( Ok(ChunkData::from_assets(
inner.server_root, inner.server_root,
self.client_chunks(), self.client_chunks(),
)) ))
@ -168,16 +167,16 @@ impl WithClientChunksChunkItemVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl EcmascriptChunkItem for WithClientChunksChunkItem { impl EcmascriptChunkItem for WithClientChunksChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn chunking_context(&self) -> EcmascriptChunkingContextVc { fn chunking_context(&self) -> Vc<Box<dyn EcmascriptChunkingContext>> {
self.context self.context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn content(self_vc: WithClientChunksChunkItemVc) -> Result<EcmascriptChunkItemContentVc> { async fn content(self: Vc<Self>) -> Result<Vc<EcmascriptChunkItemContent>> {
let this = self_vc.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
let chunks_data = self_vc.chunks_data().await?; let chunks_data = self.chunks_data().await?;
let chunks_data = chunks_data.iter().try_join().await?; let chunks_data = chunks_data.iter().try_join().await?;
let chunks_data: Vec<_> = chunks_data let chunks_data: Vec<_> = chunks_data
.iter() .iter()
@ -209,45 +208,47 @@ impl EcmascriptChunkItem for WithClientChunksChunkItem {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ChunkItem for WithClientChunksChunkItem { impl ChunkItem for WithClientChunksChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn asset_ident(&self) -> AssetIdentVc { fn asset_ident(&self) -> Vc<AssetIdent> {
self.inner.ident() self.inner.ident()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn references(self_vc: WithClientChunksChunkItemVc) -> Result<AssetReferencesVc> { async fn references(self: Vc<Self>) -> Result<Vc<AssetReferences>> {
let this = self_vc.await?; let this = self.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
let mut references = Vec::new(); let mut references = Vec::new();
references.push( references.push(Vc::upcast(
WithClientChunksAssetReference { WithClientChunksAssetReference {
asset: inner.asset.into(), asset: Vc::upcast(inner.asset),
} }
.cell() .cell(),
.into(), ));
); let client_chunks = self.client_chunks();
let client_chunks = self_vc.client_chunks();
let client_chunks = client_chunks.await?; let client_chunks = client_chunks.await?;
let client_chunk = StringVc::cell("client chunk".to_string()); let client_chunk = Vc::cell("client chunk".to_string());
for &chunk in client_chunks.iter() { for &chunk in client_chunks.iter() {
references.push(SingleAssetReferenceVc::new(chunk.into(), client_chunk).into()); references.push(Vc::upcast(SingleAssetReference::new(
Vc::upcast(chunk),
client_chunk,
)));
} }
for chunk_data in &*self_vc.chunks_data().await? { for chunk_data in &*self.chunks_data().await? {
references.extend(chunk_data.references().await?.iter().copied()); references.extend(chunk_data.references().await?.iter().copied());
} }
Ok(AssetReferencesVc::cell(references)) Ok(Vc::cell(references))
} }
} }
#[turbo_tasks::value] #[turbo_tasks::value]
struct WithClientChunksAssetReference { struct WithClientChunksAssetReference {
asset: AssetVc, asset: Vc<Box<dyn Asset>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ValueToString for WithClientChunksAssetReference { impl ValueToString for WithClientChunksAssetReference {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn to_string(&self) -> Result<StringVc> { async fn to_string(&self) -> Result<Vc<String>> {
Ok(StringVc::cell(format!( Ok(Vc::cell(format!(
"local asset {}", "local asset {}",
self.asset.ident().to_string().await? self.asset.ident().to_string().await?
))) )))
@ -257,7 +258,7 @@ impl ValueToString for WithClientChunksAssetReference {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl AssetReference for WithClientChunksAssetReference { impl AssetReference for WithClientChunksAssetReference {
#[turbo_tasks::function] #[turbo_tasks::function]
fn resolve_reference(&self) -> ResolveResultVc { fn resolve_reference(&self) -> Vc<ResolveResult> {
ResolveResult::asset(self.asset).cell() ResolveResult::asset(self.asset).cell()
} }
} }
@ -265,7 +266,7 @@ impl AssetReference for WithClientChunksAssetReference {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ChunkableModuleReference for WithClientChunksAssetReference { impl ChunkableModuleReference for WithClientChunksAssetReference {
#[turbo_tasks::function] #[turbo_tasks::function]
fn chunking_type(&self) -> ChunkingTypeOptionVc { fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
ChunkingTypeOptionVc::cell(Some(ChunkingType::IsolatedParallel)) Vc::cell(Some(ChunkingType::IsolatedParallel))
} }
} }

View file

@ -1,63 +1,65 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::primitives::StringVc; use turbo_tasks::Vc;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
reference::AssetReferencesVc, reference::AssetReferences,
}, },
turbopack::css::{chunk::CssChunkPlaceableVc, ParseCss, ParseCssResultVc, ParseCssVc}, turbopack::css::{chunk::CssChunkPlaceable, ParseCss, ParseCssResult},
}; };
/// A [`CssClientReferenceModule`] is a marker module used to indicate which /// A [`CssClientReferenceModule`] is a marker module used to indicate which
/// client reference should appear in the client reference manifest. /// client reference should appear in the client reference manifest.
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct CssClientReferenceModule { pub struct CssClientReferenceModule {
pub client_module: CssChunkPlaceableVc, pub client_module: Vc<Box<dyn CssChunkPlaceable>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl CssClientReferenceModuleVc { impl CssClientReferenceModule {
/// Create a new [`CssClientReferenceModule`] from the given source CSS /// Create a new [`CssClientReferenceModule`] from the given source CSS
/// module. /// module.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(client_module: CssChunkPlaceableVc) -> CssClientReferenceModuleVc { pub fn new(client_module: Vc<Box<dyn CssChunkPlaceable>>) -> Vc<CssClientReferenceModule> {
CssClientReferenceModule { client_module }.cell() CssClientReferenceModule { client_module }.cell()
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn css_client_reference_modifier() -> StringVc { fn css_client_reference_modifier() -> Vc<String> {
StringVc::cell("css client reference".to_string()) Vc::cell("css client reference".to_string())
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for CssClientReferenceModule { impl Asset for CssClientReferenceModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.client_module self.client_module
.ident() .ident()
.with_modifier(css_client_reference_modifier()) .with_modifier(css_client_reference_modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> Result<AssetContentVc> { fn content(&self) -> Result<Vc<AssetContent>> {
// The client reference asset only serves as a marker asset. // The client reference asset only serves as a marker asset.
bail!("CssClientReferenceModule has no content") bail!("CssClientReferenceModule has no content")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(_self_vc: CssClientReferenceModuleVc) -> AssetReferencesVc { fn references(self: Vc<Self>) -> Vc<AssetReferences> {
AssetReferencesVc::empty() AssetReferences::empty()
} }
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ParseCss for CssClientReferenceModule { impl ParseCss for CssClientReferenceModule {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn parse_css(&self) -> Result<ParseCssResultVc> { async fn parse_css(&self) -> Result<Vc<ParseCssResult>> {
let Some(parse_css) = ParseCssVc::resolve_from(self.client_module).await? else { let Some(parse_css) =
Vc::try_resolve_sidecast::<Box<dyn ParseCss>>(self.client_module).await?
else {
bail!("CSS client reference client module must be CSS parseable"); bail!("CSS client reference client module must be CSS parseable");
}; };

View file

@ -1,33 +1,31 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
module::ModuleVc, module::Module,
reference_type::{CssReferenceSubType, ReferenceType}, reference_type::{CssReferenceSubType, ReferenceType},
resolve::ModulePartVc, resolve::ModulePart,
source::SourceVc, source::Source,
}, },
turbopack::{ turbopack::{
css::chunk::CssChunkPlaceableVc, css::chunk::CssChunkPlaceable, module_options::CustomModuleType, transition::Transition,
module_options::{CustomModuleType, CustomModuleTypeVc}, ModuleAssetContext,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}; };
use super::css_client_reference_module::CssClientReferenceModuleVc; use super::css_client_reference_module::CssClientReferenceModule;
/// Module type for CSS client references. This will be used to hook into CSS /// Module type for CSS client references. This will be used to hook into CSS
/// asset processing and inject a client reference on the server side. /// asset processing and inject a client reference on the server side.
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct CssClientReferenceModuleType { pub struct CssClientReferenceModuleType {
client_transition: TransitionVc, client_transition: Vc<Box<dyn Transition>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl CssClientReferenceModuleTypeVc { impl CssClientReferenceModuleType {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(client_transition: TransitionVc) -> Self { pub fn new(client_transition: Vc<Box<dyn Transition>>) -> Vc<Self> {
CssClientReferenceModuleType { client_transition }.cell() CssClientReferenceModuleType { client_transition }.cell()
} }
} }
@ -37,20 +35,22 @@ impl CustomModuleType for CssClientReferenceModuleType {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn create_module( async fn create_module(
&self, &self,
source: SourceVc, source: Vc<Box<dyn Source>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
_part: Option<ModulePartVc>, _part: Option<Vc<ModulePart>>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let client_module = self.client_transition.process( let client_module = self.client_transition.process(
source, source,
context, context,
Value::new(ReferenceType::Css(CssReferenceSubType::Internal)), Value::new(ReferenceType::Css(CssReferenceSubType::Internal)),
); );
let Some(client_module) = CssChunkPlaceableVc::resolve_from(&client_module).await? else { let Some(client_module) =
Vc::try_resolve_sidecast::<Box<dyn CssChunkPlaceable>>(client_module).await?
else {
bail!("client asset is not CSS chunk placeable"); bail!("client asset is not CSS chunk placeable");
}; };
Ok(CssClientReferenceModuleVc::new(client_module).into()) Ok(Vc::upcast(CssClientReferenceModule::new(client_module)))
} }
} }

View file

@ -1,17 +1,18 @@
use turbo_tasks::Vc;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::reference_type::{CssReferenceSubType, ReferenceType}, core::reference_type::{CssReferenceSubType, ReferenceType},
turbopack::{ turbopack::{
module_options::{ModuleRule, ModuleRuleCondition, ModuleRuleEffect, ModuleType}, module_options::{ModuleRule, ModuleRuleCondition, ModuleRuleEffect, ModuleType},
transition::TransitionVc, transition::Transition,
}, },
}; };
use super::css_client_reference_module_type::CssClientReferenceModuleTypeVc; use super::css_client_reference_module_type::CssClientReferenceModuleType;
pub(crate) fn get_next_css_client_reference_transforms_rule( pub(crate) fn get_next_css_client_reference_transforms_rule(
client_transition: TransitionVc, client_transition: Vc<Box<dyn Transition>>,
) -> ModuleRule { ) -> ModuleRule {
let module_type = CssClientReferenceModuleTypeVc::new(client_transition); let module_type = CssClientReferenceModuleType::new(client_transition);
ModuleRule::new_internal( ModuleRule::new_internal(
// Override the default module type for CSS assets. Instead, they will go through the // Override the default module type for CSS assets. Instead, they will go through the
@ -22,7 +23,7 @@ pub(crate) fn get_next_css_client_reference_transforms_rule(
ReferenceType::Css(CssReferenceSubType::Internal), ReferenceType::Css(CssReferenceSubType::Internal),
)]), )]),
vec![ModuleRuleEffect::ModuleType(ModuleType::Custom( vec![ModuleRuleEffect::ModuleType(ModuleType::Custom(
module_type.into(), Vc::upcast(module_type),
))], ))],
) )
} }

View file

@ -1,13 +1,13 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::primitives::StringVc; use turbo_tasks::Vc;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
reference::AssetReferencesVc, reference::AssetReferences,
}, },
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable,
}; };
/// An [`EcmascriptClientReferenceModule`] is a marker module, used by the /// An [`EcmascriptClientReferenceModule`] is a marker module, used by the
@ -15,13 +15,13 @@ use turbopack_binding::turbopack::{
/// should appear in the client reference manifest. /// should appear in the client reference manifest.
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct EcmascriptClientReferenceModule { pub struct EcmascriptClientReferenceModule {
pub server_ident: AssetIdentVc, pub server_ident: Vc<AssetIdent>,
pub client_module: EcmascriptChunkPlaceableVc, pub client_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
pub ssr_module: EcmascriptChunkPlaceableVc, pub ssr_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl EcmascriptClientReferenceModuleVc { impl EcmascriptClientReferenceModule {
/// Create a new [`EcmascriptClientReferenceModule`]. /// Create a new [`EcmascriptClientReferenceModule`].
/// ///
/// # Arguments /// # Arguments
@ -32,10 +32,10 @@ impl EcmascriptClientReferenceModuleVc {
/// * `ssr_module` - The SSR module. /// * `ssr_module` - The SSR module.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new( pub fn new(
server_ident: AssetIdentVc, server_ident: Vc<AssetIdent>,
client_module: EcmascriptChunkPlaceableVc, client_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
ssr_module: EcmascriptChunkPlaceableVc, ssr_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
) -> EcmascriptClientReferenceModuleVc { ) -> Vc<EcmascriptClientReferenceModule> {
EcmascriptClientReferenceModule { EcmascriptClientReferenceModule {
server_ident, server_ident,
client_module, client_module,
@ -46,27 +46,27 @@ impl EcmascriptClientReferenceModuleVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn ecmascript_client_reference_modifier() -> StringVc { fn ecmascript_client_reference_modifier() -> Vc<String> {
StringVc::cell("ecmascript client reference".to_string()) Vc::cell("ecmascript client reference".to_string())
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for EcmascriptClientReferenceModule { impl Asset for EcmascriptClientReferenceModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.server_ident self.server_ident
.with_modifier(ecmascript_client_reference_modifier()) .with_modifier(ecmascript_client_reference_modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> Result<AssetContentVc> { fn content(&self) -> Result<Vc<AssetContent>> {
// The ES client reference asset only serves as a marker asset. // The ES client reference asset only serves as a marker asset.
bail!("EcmascriptClientReferenceModule has no content") bail!("EcmascriptClientReferenceModule has no content")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(_self_vc: EcmascriptClientReferenceModuleVc) -> AssetReferencesVc { fn references(self: Vc<Self>) -> Vc<AssetReferences> {
AssetReferencesVc::empty() AssetReferences::empty()
} }
} }

View file

@ -2,48 +2,46 @@ use std::{io::Write, iter::once};
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indoc::writedoc; use indoc::writedoc;
use turbo_tasks::{primitives::StringVc, Value, ValueToString}; use turbo_tasks::{Value, ValueToString, Vc};
use turbo_tasks_fs::File; use turbo_tasks_fs::File;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{
availability_info::AvailabilityInfo, ChunkItem, ChunkItemVc, ChunkVc, ChunkableModule, availability_info::AvailabilityInfo, Chunk, ChunkItem, ChunkableModule, ChunkingContext,
ChunkableModuleVc, ChunkingContextVc,
}, },
code_builder::CodeBuilder, code_builder::CodeBuilder,
context::{AssetContext, AssetContextVc}, context::AssetContext,
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
reference::{AssetReferencesVc, SingleAssetReferenceVc}, reference::{AssetReferences, SingleAssetReference},
reference_type::ReferenceType, reference_type::ReferenceType,
virtual_source::VirtualSourceVc, virtual_source::VirtualSource,
}, },
ecmascript::{ ecmascript::{
chunk::{ chunk::{
EcmascriptChunkItem, EcmascriptChunkItemContentVc, EcmascriptChunkItemVc, EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkItemContent,
EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkVc, EcmascriptChunkPlaceable, EcmascriptChunkingContext, EcmascriptExports,
EcmascriptChunkingContextVc, EcmascriptExportsVc,
}, },
utils::StringifyJs, utils::StringifyJs,
EcmascriptModuleAssetVc, EcmascriptModuleAsset,
}, },
}; };
use super::ecmascript_client_reference_module::EcmascriptClientReferenceModuleVc; use super::ecmascript_client_reference_module::EcmascriptClientReferenceModule;
/// A [`EcmascriptClientReferenceProxyModule`] is used in RSC to represent /// A [`EcmascriptClientReferenceProxyModule`] is used in RSC to represent
/// a client or SSR asset. /// a client or SSR asset.
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct EcmascriptClientReferenceProxyModule { pub struct EcmascriptClientReferenceProxyModule {
server_module_ident: AssetIdentVc, server_module_ident: Vc<AssetIdent>,
server_asset_context: AssetContextVc, server_asset_context: Vc<Box<dyn AssetContext>>,
client_module: EcmascriptChunkPlaceableVc, client_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
ssr_module: EcmascriptChunkPlaceableVc, ssr_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl EcmascriptClientReferenceProxyModuleVc { impl EcmascriptClientReferenceProxyModule {
/// Create a new [`EcmascriptClientReferenceProxyModule`]. /// Create a new [`EcmascriptClientReferenceProxyModule`].
/// ///
/// # Arguments /// # Arguments
@ -54,11 +52,11 @@ impl EcmascriptClientReferenceProxyModuleVc {
/// * `ssr_module` - The SSR module. /// * `ssr_module` - The SSR module.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new( pub fn new(
server_module_ident: AssetIdentVc, server_module_ident: Vc<AssetIdent>,
server_asset_context: AssetContextVc, server_asset_context: Vc<Box<dyn AssetContext>>,
client_module: EcmascriptChunkPlaceableVc, client_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
ssr_module: EcmascriptChunkPlaceableVc, ssr_module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
) -> EcmascriptClientReferenceProxyModuleVc { ) -> Vc<EcmascriptClientReferenceProxyModule> {
EcmascriptClientReferenceProxyModule { EcmascriptClientReferenceProxyModule {
server_module_ident, server_module_ident,
server_asset_context, server_asset_context,
@ -69,7 +67,7 @@ impl EcmascriptClientReferenceProxyModuleVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn proxy_module_asset(self) -> Result<EcmascriptModuleAssetVc> { async fn proxy_module_asset(self: Vc<Self>) -> Result<Vc<EcmascriptModuleAsset>> {
let this = self.await?; let this = self.await?;
let mut code = CodeBuilder::default(); let mut code = CodeBuilder::default();
@ -96,18 +94,21 @@ impl EcmascriptClientReferenceProxyModuleVc {
let code = code.build(); let code = code.build();
let proxy_module_asset_content = let proxy_module_asset_content =
AssetContentVc::from(File::from(code.source_code().clone())); AssetContent::file(File::from(code.source_code().clone()).into());
let proxy_source = VirtualSourceVc::new( let proxy_source = VirtualSource::new(
this.server_module_ident.path().join("proxy.ts"), this.server_module_ident.path().join("proxy.ts".to_string()),
proxy_module_asset_content, proxy_module_asset_content,
); );
let proxy_module = this let proxy_module = this.server_asset_context.process(
.server_asset_context Vc::upcast(proxy_source),
.process(proxy_source.into(), Value::new(ReferenceType::Undefined)); Value::new(ReferenceType::Undefined),
);
let Some(proxy_module) = EcmascriptModuleAssetVc::resolve_from(&proxy_module).await? else { let Some(proxy_module) =
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(proxy_module).await?
else {
bail!("proxy asset is not an ecmascript module"); bail!("proxy asset is not an ecmascript module");
}; };
@ -118,48 +119,42 @@ impl EcmascriptClientReferenceProxyModuleVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for EcmascriptClientReferenceProxyModule { impl Asset for EcmascriptClientReferenceProxyModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.server_module_ident self.server_module_ident
.with_modifier(client_proxy_modifier()) .with_modifier(client_proxy_modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> Result<AssetContentVc> { fn content(&self) -> Result<Vc<AssetContent>> {
bail!("proxy module asset has no content") bail!("proxy module asset has no content")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn references( async fn references(self: Vc<Self>) -> Result<Vc<AssetReferences>> {
self_vc: EcmascriptClientReferenceProxyModuleVc,
) -> Result<AssetReferencesVc> {
let EcmascriptClientReferenceProxyModule { let EcmascriptClientReferenceProxyModule {
server_module_ident, server_module_ident,
server_asset_context: _, server_asset_context: _,
client_module, client_module,
ssr_module, ssr_module,
} = &*self_vc.await?; } = &*self.await?;
let references: Vec<_> = self_vc let references: Vec<_> = self
.proxy_module_asset() .proxy_module_asset()
.references() .references()
.await? .await?
.iter() .iter()
.copied() .copied()
.chain(once( .chain(once(Vc::upcast(SingleAssetReference::new(
SingleAssetReferenceVc::new( Vc::upcast(EcmascriptClientReferenceModule::new(
EcmascriptClientReferenceModuleVc::new( *server_module_ident,
*server_module_ident, *client_module,
*client_module, *ssr_module,
*ssr_module, )),
) client_reference_description(),
.into(), ))))
client_reference_description(),
)
.into(),
))
.collect(); .collect();
Ok(AssetReferencesVc::cell(references)) Ok(Vc::cell(references))
} }
} }
@ -170,16 +165,15 @@ impl Module for EcmascriptClientReferenceProxyModule {}
impl ChunkableModule for EcmascriptClientReferenceProxyModule { impl ChunkableModule for EcmascriptClientReferenceProxyModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk( fn as_chunk(
self_vc: EcmascriptClientReferenceProxyModuleVc, self: Vc<Self>,
context: ChunkingContextVc, context: Vc<Box<dyn ChunkingContext>>,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> ChunkVc { ) -> Vc<Box<dyn Chunk>> {
EcmascriptChunkVc::new( Vc::upcast(EcmascriptChunk::new(
context, context,
self_vc.as_ecmascript_chunk_placeable(), Vc::upcast(self),
availability_info, availability_info,
) ))
.into()
} }
} }
@ -187,56 +181,57 @@ impl ChunkableModule for EcmascriptClientReferenceProxyModule {
impl EcmascriptChunkPlaceable for EcmascriptClientReferenceProxyModule { impl EcmascriptChunkPlaceable for EcmascriptClientReferenceProxyModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk_item( fn as_chunk_item(
self_vc: EcmascriptClientReferenceProxyModuleVc, self: Vc<Self>,
chunking_context: EcmascriptChunkingContextVc, chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> EcmascriptChunkItemVc { ) -> Vc<Box<dyn EcmascriptChunkItem>> {
ProxyModuleChunkItem { Vc::upcast(
client_proxy_asset: self_vc, ProxyModuleChunkItem {
inner_proxy_module_chunk_item: self_vc client_proxy_asset: self,
.proxy_module_asset() inner_proxy_module_chunk_item: self
.as_chunk_item(chunking_context), .proxy_module_asset()
chunking_context, .as_chunk_item(chunking_context),
} chunking_context,
.cell() }
.into() .cell(),
)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_exports(self_vc: EcmascriptClientReferenceProxyModuleVc) -> EcmascriptExportsVc { fn get_exports(self: Vc<Self>) -> Vc<EcmascriptExports> {
self_vc.proxy_module_asset().get_exports() self.proxy_module_asset().get_exports()
} }
} }
/// This wrapper only exists to overwrite the `asset_ident` method of the /// This wrapper only exists to overwrite the `asset_ident` method of the
/// wrapped [`EcmascriptChunkItemVc`]. Otherwise, the asset ident of the /// wrapped [`Vc<Box<dyn EcmascriptChunkItem>>`]. Otherwise, the asset ident of
/// chunk item would not be the same as the asset ident of the /// the chunk item would not be the same as the asset ident of the
/// [`EcmascriptClientReferenceProxyModuleVc`]. /// [`Vc<EcmascriptClientReferenceProxyModule>`].
#[turbo_tasks::value] #[turbo_tasks::value]
struct ProxyModuleChunkItem { struct ProxyModuleChunkItem {
client_proxy_asset: EcmascriptClientReferenceProxyModuleVc, client_proxy_asset: Vc<EcmascriptClientReferenceProxyModule>,
inner_proxy_module_chunk_item: EcmascriptChunkItemVc, inner_proxy_module_chunk_item: Vc<Box<dyn EcmascriptChunkItem>>,
chunking_context: EcmascriptChunkingContextVc, chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn client_proxy_modifier() -> StringVc { fn client_proxy_modifier() -> Vc<String> {
StringVc::cell("client proxy".to_string()) Vc::cell("client proxy".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn client_reference_description() -> StringVc { fn client_reference_description() -> Vc<String> {
StringVc::cell("client references".to_string()) Vc::cell("client references".to_string())
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ChunkItem for ProxyModuleChunkItem { impl ChunkItem for ProxyModuleChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn asset_ident(&self) -> AssetIdentVc { async fn asset_ident(&self) -> Vc<AssetIdent> {
self.client_proxy_asset.ident() self.client_proxy_asset.ident()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc { fn references(&self) -> Vc<AssetReferences> {
self.client_proxy_asset.references() self.client_proxy_asset.references()
} }
} }
@ -244,7 +239,7 @@ impl ChunkItem for ProxyModuleChunkItem {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl EcmascriptChunkItem for ProxyModuleChunkItem { impl EcmascriptChunkItem for ProxyModuleChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> EcmascriptChunkItemContentVc { fn content(&self) -> Vc<EcmascriptChunkItemContent> {
self.inner_proxy_module_chunk_item.content() self.inner_proxy_module_chunk_item.content()
} }
@ -252,13 +247,13 @@ impl EcmascriptChunkItem for ProxyModuleChunkItem {
fn content_with_availability_info( fn content_with_availability_info(
&self, &self,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> EcmascriptChunkItemContentVc { ) -> Vc<EcmascriptChunkItemContent> {
self.inner_proxy_module_chunk_item self.inner_proxy_module_chunk_item
.content_with_availability_info(availability_info) .content_with_availability_info(availability_info)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn chunking_context(&self) -> EcmascriptChunkingContextVc { fn chunking_context(&self) -> Vc<Box<dyn EcmascriptChunkingContext>> {
self.inner_proxy_module_chunk_item.chunking_context() self.inner_proxy_module_chunk_item.chunking_context()
} }
} }

View file

@ -1,34 +1,34 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::Asset, asset::Asset,
module::ModuleVc, module::Module,
reference_type::{EntryReferenceSubType, ReferenceType}, reference_type::{EntryReferenceSubType, ReferenceType},
source::SourceVc, source::Source,
}, },
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{ turbopack::{
transition::{ContextTransitionVc, Transition, TransitionVc}, transition::{ContextTransition, Transition},
ModuleAssetContextVc, ModuleAssetContext,
}, },
}; };
use super::ecmascript_client_reference_proxy_module::EcmascriptClientReferenceProxyModuleVc; use super::ecmascript_client_reference_proxy_module::EcmascriptClientReferenceProxyModule;
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextEcmascriptClientReferenceTransition { pub struct NextEcmascriptClientReferenceTransition {
client_transition: ContextTransitionVc, client_transition: Vc<ContextTransition>,
ssr_transition: ContextTransitionVc, ssr_transition: Vc<ContextTransition>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextEcmascriptClientReferenceTransitionVc { impl NextEcmascriptClientReferenceTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new( pub fn new(
client_transition: ContextTransitionVc, client_transition: Vc<ContextTransition>,
ssr_transition: ContextTransitionVc, ssr_transition: Vc<ContextTransition>,
) -> Self { ) -> Vc<Self> {
NextEcmascriptClientReferenceTransition { NextEcmascriptClientReferenceTransition {
client_transition, client_transition,
ssr_transition, ssr_transition,
@ -42,10 +42,10 @@ impl Transition for NextEcmascriptClientReferenceTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process( async fn process(
&self, &self,
source: SourceVc, source: Vc<Box<dyn Source>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
_reference_type: Value<ReferenceType>, _reference_type: Value<ReferenceType>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let client_module = self.client_transition.process( let client_module = self.client_transition.process(
source, source,
context, context,
@ -62,31 +62,33 @@ impl Transition for NextEcmascriptClientReferenceTransition {
)), )),
); );
let Some(client_module) = EcmascriptChunkPlaceableVc::resolve_from(&client_module).await? let Some(client_module) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(client_module).await?
else { else {
bail!("client asset is not ecmascript chunk placeable"); bail!("client asset is not ecmascript chunk placeable");
}; };
let Some(ssr_module) = EcmascriptChunkPlaceableVc::resolve_from(&ssr_module).await? else { let Some(ssr_module) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(ssr_module).await?
else {
bail!("SSR asset is not ecmascript chunk placeable"); bail!("SSR asset is not ecmascript chunk placeable");
}; };
// TODO(alexkirsz) This is necessary to remove the transition currently set on // TODO(alexkirsz) This is necessary to remove the transition currently set on
// the context. // the context.
let context = context.await?; let context = context.await?;
let server_context = ModuleAssetContextVc::new( let server_context = ModuleAssetContext::new(
context.transitions, context.transitions,
context.compile_time_info, context.compile_time_info,
context.module_options_context, context.module_options_context,
context.resolve_options_context, context.resolve_options_context,
); );
Ok(EcmascriptClientReferenceProxyModuleVc::new( Ok(Vc::upcast(EcmascriptClientReferenceProxyModule::new(
source.ident(), source.ident(),
server_context.into(), Vc::upcast(server_context),
client_module, client_module,
ssr_module, ssr_module,
) )))
.into())
} }
} }

View file

@ -2,11 +2,9 @@ pub(crate) mod css_client_reference;
pub(crate) mod ecmascript_client_reference; pub(crate) mod ecmascript_client_reference;
pub(crate) mod visit_client_reference; pub(crate) mod visit_client_reference;
pub use css_client_reference::css_client_reference_module::CssClientReferenceModuleVc; pub use css_client_reference::css_client_reference_module::CssClientReferenceModule;
pub use ecmascript_client_reference::{ pub use ecmascript_client_reference::{
ecmascript_client_reference_module::EcmascriptClientReferenceModuleVc, ecmascript_client_reference_module::EcmascriptClientReferenceModule,
ecmascript_client_reference_transition::NextEcmascriptClientReferenceTransitionVc, ecmascript_client_reference_transition::NextEcmascriptClientReferenceTransition,
};
pub use visit_client_reference::{
ClientReference, ClientReferenceType, ClientReferencesByEntry, ClientReferencesByEntryVc,
}; };
pub use visit_client_reference::{ClientReference, ClientReferenceType, ClientReferencesByEntry};

View file

@ -7,29 +7,29 @@ use turbo_tasks::{
debug::ValueDebugFormat, debug::ValueDebugFormat,
graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow}, graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow},
trace::TraceRawVcs, trace::TraceRawVcs,
TryJoinIterExt, TryJoinIterExt, Vc,
}; };
use turbopack_binding::turbopack::core::{ use turbopack_binding::turbopack::core::{
asset::{Asset, AssetVc, AssetsVc}, asset::{Asset, Assets},
reference::AssetReference, reference::AssetReference,
}; };
use super::{ use super::{
css_client_reference::css_client_reference_module::CssClientReferenceModuleVc, css_client_reference::css_client_reference_module::CssClientReferenceModule,
ecmascript_client_reference::ecmascript_client_reference_module::EcmascriptClientReferenceModuleVc, ecmascript_client_reference::ecmascript_client_reference_module::EcmascriptClientReferenceModule,
}; };
use crate::next_server_component::server_component_module::NextServerComponentModuleVc; use crate::next_server_component::server_component_module::NextServerComponentModule;
#[derive( #[derive(
Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, ValueDebugFormat, TraceRawVcs, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, ValueDebugFormat, TraceRawVcs,
)] )]
pub struct ClientReference { pub struct ClientReference {
server_component: Option<NextServerComponentModuleVc>, server_component: Option<Vc<NextServerComponentModule>>,
ty: ClientReferenceType, ty: ClientReferenceType,
} }
impl ClientReference { impl ClientReference {
pub fn server_component(&self) -> Option<&NextServerComponentModuleVc> { pub fn server_component(&self) -> Option<&Vc<NextServerComponentModule>> {
self.server_component.as_ref() self.server_component.as_ref()
} }
@ -42,17 +42,17 @@ impl ClientReference {
Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, ValueDebugFormat, TraceRawVcs, Copy, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, Debug, ValueDebugFormat, TraceRawVcs,
)] )]
pub enum ClientReferenceType { pub enum ClientReferenceType {
EcmascriptClientReference(EcmascriptClientReferenceModuleVc), EcmascriptClientReference(Vc<EcmascriptClientReferenceModule>),
CssClientReference(CssClientReferenceModuleVc), CssClientReference(Vc<CssClientReferenceModule>),
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct ClientReferencesByEntry(IndexMap<AssetVc, Vec<ClientReference>>); pub struct ClientReferencesByEntry(IndexMap<Vc<Box<dyn Asset>>, Vec<ClientReference>>);
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ClientReferencesByEntryVc { impl ClientReferencesByEntry {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn new(entries: AssetsVc) -> Result<ClientReferencesByEntryVc> { pub async fn new(entries: Vc<Assets>) -> Result<Vc<ClientReferencesByEntry>> {
let entries = entries.await?; let entries = entries.await?;
let graph = AdjacencyMap::new() let graph = AdjacencyMap::new()
@ -95,7 +95,7 @@ impl ClientReferencesByEntryVc {
}) })
.collect(); .collect();
Ok(ClientReferencesByEntryVc::cell(client_references)) Ok(Vc::cell(client_references))
} }
} }
@ -103,14 +103,14 @@ struct VisitClientReference;
#[derive(Clone, Eq, PartialEq, Hash)] #[derive(Clone, Eq, PartialEq, Hash)]
struct VisitClientReferenceNode { struct VisitClientReferenceNode {
server_component: Option<NextServerComponentModuleVc>, server_component: Option<Vc<NextServerComponentModule>>,
ty: VisitClientReferenceNodeType, ty: VisitClientReferenceNodeType,
} }
#[derive(Clone, Eq, PartialEq, Hash)] #[derive(Clone, Eq, PartialEq, Hash)]
enum VisitClientReferenceNodeType { enum VisitClientReferenceNodeType {
ClientReference(ClientReference), ClientReference(ClientReference),
Internal(AssetVc), Internal(Vc<Box<dyn Asset>>),
} }
impl Visit<VisitClientReferenceNode> for VisitClientReference { impl Visit<VisitClientReferenceNode> for VisitClientReference {
@ -149,7 +149,8 @@ impl Visit<VisitClientReferenceNode> for VisitClientReference {
let referenced_assets = referenced_assets.map(|asset| async move { let referenced_assets = referenced_assets.map(|asset| async move {
if let Some(client_reference_asset) = if let Some(client_reference_asset) =
EcmascriptClientReferenceModuleVc::resolve_from(asset).await? Vc::try_resolve_downcast_type::<EcmascriptClientReferenceModule>(asset)
.await?
{ {
return Ok(VisitClientReferenceNode { return Ok(VisitClientReferenceNode {
server_component: node.server_component, server_component: node.server_component,
@ -165,7 +166,7 @@ impl Visit<VisitClientReferenceNode> for VisitClientReference {
} }
if let Some(css_client_reference_asset) = if let Some(css_client_reference_asset) =
CssClientReferenceModuleVc::resolve_from(asset).await? Vc::try_resolve_downcast_type::<CssClientReferenceModule>(asset).await?
{ {
return Ok(VisitClientReferenceNode { return Ok(VisitClientReferenceNode {
server_component: node.server_component, server_component: node.server_component,
@ -181,7 +182,8 @@ impl Visit<VisitClientReferenceNode> for VisitClientReference {
} }
if let Some(server_component_asset) = if let Some(server_component_asset) =
NextServerComponentModuleVc::resolve_from(asset).await? Vc::try_resolve_downcast_type::<NextServerComponentModule>(asset)
.await?
{ {
return Ok(VisitClientReferenceNode { return Ok(VisitClientReferenceNode {
server_component: Some(server_component_asset), server_component: Some(server_component_asset),

View file

@ -2,28 +2,24 @@ use anyhow::{Context, Result};
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
use turbo_tasks::{ use turbo_tasks::{trace::TraceRawVcs, Completion, Value, Vc};
primitives::{BoolVc, JsonValueVc, StringVc, StringsVc},
trace::TraceRawVcs,
CompletionVc, Value,
};
use turbo_tasks_fs::json::parse_json_with_source_context; use turbo_tasks_fs::json::parse_json_with_source_context;
use turbopack_binding::{ use turbopack_binding::{
turbo::{tasks_env::EnvMapVc, tasks_fs::FileSystemPathVc}, turbo::{tasks_env::EnvMap, tasks_fs::FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
asset::Asset, asset::Asset,
changed::any_content_changed, changed::any_content_changed,
chunk::ChunkingContext, chunk::ChunkingContext,
context::AssetContext, context::AssetContext,
file_source::FileSourceVc, file_source::FileSource,
ident::AssetIdentVc, ident::AssetIdent,
issue::{Issue, IssueContextExt, IssueSeverity, IssueSeverityVc, IssueVc}, issue::{Issue, IssueContextExt, IssueExt, IssueSeverity},
reference_type::{EntryReferenceSubType, InnerAssetsVc, ReferenceType}, reference_type::{EntryReferenceSubType, InnerAssets, ReferenceType},
resolve::{ resolve::{
find_context_file, find_context_file,
options::{ImportMap, ImportMapping}, options::{ImportMap, ImportMapping},
FindContextFileResult, ResolveAliasMap, ResolveAliasMapVc, FindContextFileResult, ResolveAliasMap,
}, },
}, },
ecmascript_plugin::transform::{ ecmascript_plugin::transform::{
@ -33,12 +29,12 @@ use turbopack_binding::{
node::{ node::{
debug::should_debug, debug::should_debug,
evaluate::evaluate, evaluate::evaluate,
execution_context::{ExecutionContext, ExecutionContextVc}, execution_context::ExecutionContext,
transforms::webpack::{WebpackLoaderItem, WebpackLoaderItemsVc}, transforms::webpack::{WebpackLoaderItem, WebpackLoaderItems},
}, },
turbopack::{ turbopack::{
evaluate_context::node_evaluate_asset_context, evaluate_context::node_evaluate_asset_context,
module_options::{LoaderRuleItem, OptionWebpackRulesVc, WebpackRulesVc}, module_options::{LoaderRuleItem, OptionWebpackRules},
}, },
}, },
}; };
@ -54,8 +50,8 @@ struct NextConfigAndCustomRoutesRaw {
#[turbo_tasks::value] #[turbo_tasks::value]
struct NextConfigAndCustomRoutes { struct NextConfigAndCustomRoutes {
config: NextConfigVc, config: Vc<NextConfig>,
custom_routes: CustomRoutesVc, custom_routes: Vc<CustomRoutes>,
} }
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)] #[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
@ -70,7 +66,7 @@ struct CustomRoutesRaw {
#[turbo_tasks::value] #[turbo_tasks::value]
struct CustomRoutes { struct CustomRoutes {
rewrites: RewritesVc, rewrites: Vc<Rewrites>,
} }
#[turbo_tasks::value(serialization = "custom", eq = "manual")] #[turbo_tasks::value(serialization = "custom", eq = "manual")]
@ -510,17 +506,17 @@ pub enum RemoveConsoleConfig {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextConfigVc { impl NextConfig {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn from_string(s: String) -> Result<Self> { pub fn from_string(s: String) -> Result<Vc<Self>> {
let config: NextConfig = serde_json::from_str(&s) let config: NextConfig = serde_json::from_str(&s)
.with_context(|| format!("failed to parse next.config.js: {}", s))?; .with_context(|| format!("failed to parse next.config.js: {}", s))?;
Ok(config.cell()) Ok(config.cell())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn server_component_externals(self) -> Result<StringsVc> { pub async fn server_component_externals(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
Ok(StringsVc::cell( Ok(Vc::cell(
self.await? self.await?
.experimental .experimental
.server_components_external_packages .server_components_external_packages
@ -531,8 +527,8 @@ impl NextConfigVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn app_dir(self) -> Result<BoolVc> { pub async fn app_dir(self: Vc<Self>) -> Result<Vc<bool>> {
Ok(BoolVc::cell( Ok(Vc::cell(
self.await? self.await?
.experimental .experimental
.app_dir .app_dir
@ -543,7 +539,7 @@ impl NextConfigVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn env(self) -> Result<EnvMapVc> { pub async fn env(self: Vc<Self>) -> Result<Vc<EnvMap>> {
// The value expected for env is Record<String, String>, but config itself // The value expected for env is Record<String, String>, but config itself
// allows arbitary object (https://github.com/vercel/next.js/blob/25ba8a74b7544dfb6b30d1b67c47b9cb5360cb4e/packages/next/src/server/config-schema.ts#L203) // allows arbitary object (https://github.com/vercel/next.js/blob/25ba8a74b7544dfb6b30d1b67c47b9cb5360cb4e/packages/next/src/server/config-schema.ts#L203)
// then stringifies it. We do the interop here as well. // then stringifies it. We do the interop here as well.
@ -564,28 +560,28 @@ impl NextConfigVc {
}) })
.collect(); .collect();
Ok(EnvMapVc::cell(env)) Ok(Vc::cell(env))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn image_config(self) -> Result<ImageConfigVc> { pub async fn image_config(self: Vc<Self>) -> Result<Vc<ImageConfig>> {
Ok(self.await?.images.clone().cell()) Ok(self.await?.images.clone().cell())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn page_extensions(self) -> Result<StringsVc> { pub async fn page_extensions(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
Ok(StringsVc::cell(self.await?.page_extensions.clone())) Ok(Vc::cell(self.await?.page_extensions.clone()))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn transpile_packages(self) -> Result<StringsVc> { pub async fn transpile_packages(self: Vc<Self>) -> Result<Vc<Vec<String>>> {
Ok(StringsVc::cell( Ok(Vc::cell(
self.await?.transpile_packages.clone().unwrap_or_default(), self.await?.transpile_packages.clone().unwrap_or_default(),
)) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn webpack_rules(self) -> Result<OptionWebpackRulesVc> { pub async fn webpack_rules(self: Vc<Self>) -> Result<Vc<OptionWebpackRules>> {
let this = self.await?; let this = self.await?;
let Some(turbo_rules) = this let Some(turbo_rules) = this
.experimental .experimental
@ -593,15 +589,15 @@ impl NextConfigVc {
.as_ref() .as_ref()
.and_then(|t| t.rules.as_ref()) .and_then(|t| t.rules.as_ref())
else { else {
return Ok(OptionWebpackRulesVc::cell(None)); return Ok(Vc::cell(None));
}; };
if turbo_rules.is_empty() { if turbo_rules.is_empty() {
return Ok(OptionWebpackRulesVc::cell(None)); return Ok(Vc::cell(None));
} }
let mut rules = IndexMap::new(); let mut rules = IndexMap::new();
for (ext, rule) in turbo_rules { for (ext, rule) in turbo_rules {
fn transform_loaders(loaders: &[LoaderItem]) -> WebpackLoaderItemsVc { fn transform_loaders(loaders: &[LoaderItem]) -> Vc<WebpackLoaderItems> {
WebpackLoaderItemsVc::cell( Vc::cell(
loaders loaders
.iter() .iter()
.map(|item| match item { .map(|item| match item {
@ -627,13 +623,11 @@ impl NextConfigVc {
rules.insert(ext.clone(), rule); rules.insert(ext.clone(), rule);
} }
Ok(OptionWebpackRulesVc::cell(Some(WebpackRulesVc::cell( Ok(Vc::cell(Some(Vc::cell(rules))))
rules,
))))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn resolve_alias_options(self) -> Result<ResolveAliasMapVc> { pub async fn resolve_alias_options(self: Vc<Self>) -> Result<Vc<ResolveAliasMap>> {
let this = self.await?; let this = self.await?;
let Some(resolve_alias) = this let Some(resolve_alias) = this
.experimental .experimental
@ -641,29 +635,27 @@ impl NextConfigVc {
.as_ref() .as_ref()
.and_then(|t| t.resolve_alias.as_ref()) .and_then(|t| t.resolve_alias.as_ref())
else { else {
return Ok(ResolveAliasMapVc::cell(ResolveAliasMap::default())); return Ok(ResolveAliasMap::cell(ResolveAliasMap::default()));
}; };
let alias_map: ResolveAliasMap = resolve_alias.try_into()?; let alias_map: ResolveAliasMap = resolve_alias.try_into()?;
Ok(alias_map.cell()) Ok(alias_map.cell())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn mdx_rs(self) -> Result<BoolVc> { pub async fn mdx_rs(self: Vc<Self>) -> Result<Vc<bool>> {
Ok(BoolVc::cell( Ok(Vc::cell(self.await?.experimental.mdx_rs.unwrap_or(false)))
self.await?.experimental.mdx_rs.unwrap_or(false),
))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn sass_config(self) -> Result<JsonValueVc> { pub async fn sass_config(self: Vc<Self>) -> Result<Vc<JsonValue>> {
Ok(JsonValueVc::cell( Ok(Vc::cell(
self.await?.sass_options.clone().unwrap_or_default(), self.await?.sass_options.clone().unwrap_or_default(),
)) ))
} }
} }
fn next_configs() -> StringsVc { fn next_configs() -> Vc<Vec<String>> {
StringsVc::cell( Vc::cell(
["next.config.mjs", "next.config.js"] ["next.config.mjs", "next.config.js"]
.into_iter() .into_iter()
.map(ToOwned::to_owned) .map(ToOwned::to_owned)
@ -672,14 +664,14 @@ fn next_configs() -> StringsVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn load_next_config(execution_context: ExecutionContextVc) -> Result<NextConfigVc> { pub async fn load_next_config(execution_context: Vc<ExecutionContext>) -> Result<Vc<NextConfig>> {
Ok(load_config_and_custom_routes(execution_context) Ok(load_config_and_custom_routes(execution_context)
.await? .await?
.config) .config)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn load_rewrites(execution_context: ExecutionContextVc) -> Result<RewritesVc> { pub async fn load_rewrites(execution_context: Vc<ExecutionContext>) -> Result<Vc<Rewrites>> {
Ok(load_config_and_custom_routes(execution_context) Ok(load_config_and_custom_routes(execution_context)
.await? .await?
.custom_routes .custom_routes
@ -689,8 +681,8 @@ pub async fn load_rewrites(execution_context: ExecutionContextVc) -> Result<Rewr
#[turbo_tasks::function] #[turbo_tasks::function]
async fn load_config_and_custom_routes( async fn load_config_and_custom_routes(
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<NextConfigAndCustomRoutesVc> { ) -> Result<Vc<NextConfigAndCustomRoutes>> {
let ExecutionContext { project_path, .. } = *execution_context.await?; let ExecutionContext { project_path, .. } = *execution_context.await?;
let find_config_result = find_context_file(project_path, next_configs()); let find_config_result = find_context_file(project_path, next_configs());
let config_file = match &*find_config_result.await? { let config_file = match &*find_config_result.await? {
@ -705,9 +697,9 @@ async fn load_config_and_custom_routes(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn load_next_config_and_custom_routes_internal( async fn load_next_config_and_custom_routes_internal(
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
config_file: Option<FileSystemPathVc>, config_file: Option<Vc<FileSystemPath>>,
) -> Result<NextConfigAndCustomRoutesVc> { ) -> Result<Vc<NextConfigAndCustomRoutes>> {
let ExecutionContext { let ExecutionContext {
project_path, project_path,
chunking_context, chunking_context,
@ -721,28 +713,28 @@ async fn load_next_config_and_custom_routes_internal(
import_map.insert_wildcard_alias("styled-jsx/", ImportMapping::External(None).into()); import_map.insert_wildcard_alias("styled-jsx/", ImportMapping::External(None).into());
let context = node_evaluate_asset_context(execution_context, Some(import_map.cell()), None); let context = node_evaluate_asset_context(execution_context, Some(import_map.cell()), None);
let config_asset = config_file.map(FileSourceVc::new); let config_asset = config_file.map(FileSource::new);
let config_changed = config_asset.map_or_else(CompletionVc::immutable, |config_asset| { let config_changed = config_asset.map_or_else(Completion::immutable, |config_asset| {
// This invalidates the execution when anything referenced by the config file // This invalidates the execution when anything referenced by the config file
// changes // changes
let config_asset = context.process( let config_asset = context.process(
config_asset.into(), Vc::upcast(config_asset),
Value::new(ReferenceType::Internal(InnerAssetsVc::empty())), Value::new(ReferenceType::Internal(InnerAssets::empty())),
); );
any_content_changed(config_asset.into()) any_content_changed(Vc::upcast(config_asset))
}); });
let load_next_config_asset = context.process( let load_next_config_asset = context.process(
next_asset("entry/config/next.js"), next_asset("entry/config/next.js".to_string()),
Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)), Value::new(ReferenceType::Entry(EntryReferenceSubType::Undefined)),
); );
let config_value = evaluate( let config_value = evaluate(
load_next_config_asset.into(), Vc::upcast(load_next_config_asset),
project_path, project_path,
env, env,
config_asset.map_or_else(|| AssetIdentVc::from_path(project_path), |c| c.ident()), config_asset.map_or_else(|| AssetIdent::from_path(project_path), |c| c.ident()),
context, context,
chunking_context.with_layer("next_config"), chunking_context.with_layer("next_config".to_string()),
None, None,
vec![], vec![],
config_changed, config_changed,
@ -778,13 +770,12 @@ async fn load_next_config_and_custom_routes_internal(
path: config_file.unwrap_or(project_path), path: config_file.unwrap_or(project_path),
old_name: "experimental.turbo.loaders".to_string(), old_name: "experimental.turbo.loaders".to_string(),
new_name: "experimental.turbo.rules".to_string(), new_name: "experimental.turbo.rules".to_string(),
description: "The new option is similar, but the key should be a glob instead of \ description: indoc::indoc! { r#"
an extension. The new option is similar, but the key should be a glob instead of an extension.
Example: loaders: { \".mdx\": [\"mdx-loader\"] } -> rules: { \"*.mdx\": [\"mdx-loader\"] }" Example: loaders: { ".mdx": ["mdx-loader"] } -> rules: { "*.mdx": ["mdx-loader"] }"# }
.to_string(), .to_string(),
} }
.cell() .cell()
.as_issue()
.emit() .emit()
} }
} }
@ -800,8 +791,8 @@ Example: loaders: { \".mdx\": [\"mdx-loader\"] } -> rules: { \"*.mdx\": [\"mdx-l
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn has_next_config(context: FileSystemPathVc) -> Result<BoolVc> { pub async fn has_next_config(context: Vc<FileSystemPath>) -> Result<Vc<bool>> {
Ok(BoolVc::cell(!matches!( Ok(Vc::cell(!matches!(
*find_context_file(context, next_configs()).await?, *find_context_file(context, next_configs()).await?,
FindContextFileResult::NotFound(_) FindContextFileResult::NotFound(_)
))) )))
@ -809,7 +800,7 @@ pub async fn has_next_config(context: FileSystemPathVc) -> Result<BoolVc> {
#[turbo_tasks::value] #[turbo_tasks::value]
struct OutdatedConfigIssue { struct OutdatedConfigIssue {
path: FileSystemPathVc, path: Vc<FileSystemPath>,
old_name: String, old_name: String,
new_name: String, new_name: String,
description: String, description: String,
@ -818,30 +809,30 @@ struct OutdatedConfigIssue {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Issue for OutdatedConfigIssue { impl Issue for OutdatedConfigIssue {
#[turbo_tasks::function] #[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc { fn severity(&self) -> Vc<IssueSeverity> {
IssueSeverity::Error.into() IssueSeverity::Error.into()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn category(&self) -> StringVc { fn category(&self) -> Vc<String> {
StringVc::cell("config".to_string()) Vc::cell("config".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc { fn context(&self) -> Vc<FileSystemPath> {
self.path self.path
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn title(&self) -> StringVc { fn title(&self) -> Vc<String> {
StringVc::cell(format!( Vc::cell(format!(
"\"{}\" has been replaced by \"{}\"", "\"{}\" has been replaced by \"{}\"",
self.old_name, self.new_name self.old_name, self.new_name
)) ))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn description(&self) -> StringVc { fn description(&self) -> Vc<String> {
StringVc::cell(self.description.to_string()) Vc::cell(self.description.to_string())
} }
} }

View file

@ -1,27 +1,27 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::primitives::StringVc; use turbo_tasks::Vc;
use turbopack_binding::turbopack::core::{ use turbopack_binding::turbopack::core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ChunkableModule, ChunkableModuleVc, ChunkingContext, ChunkingContextVc}, chunk::{ChunkableModule, ChunkingContext},
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
output::OutputAssetsVc, output::OutputAssets,
reference::AssetReferencesVc, reference::AssetReferences,
}; };
/// A [`NextDynamicEntryModule`] is a marker asset used to indicate which /// A [`NextDynamicEntryModule`] is a marker asset used to indicate which
/// dynamic assets should appear in the dynamic manifest. /// dynamic assets should appear in the dynamic manifest.
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct NextDynamicEntryModule { pub struct NextDynamicEntryModule {
pub client_entry_module: ModuleVc, pub client_entry_module: Vc<Box<dyn Module>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextDynamicEntryModuleVc { impl NextDynamicEntryModule {
/// Create a new [`NextDynamicEntryModule`] from the given source CSS /// Create a new [`NextDynamicEntryModule`] from the given source CSS
/// asset. /// asset.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(client_entry_module: ModuleVc) -> NextDynamicEntryModuleVc { pub fn new(client_entry_module: Vc<Box<dyn Module>>) -> Vc<NextDynamicEntryModule> {
NextDynamicEntryModule { NextDynamicEntryModule {
client_entry_module, client_entry_module,
} }
@ -30,13 +30,13 @@ impl NextDynamicEntryModuleVc {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn client_chunks( pub async fn client_chunks(
self, self: Vc<Self>,
client_chunking_context: ChunkingContextVc, client_chunking_context: Vc<Box<dyn ChunkingContext>>,
) -> Result<OutputAssetsVc> { ) -> Result<Vc<OutputAssets>> {
let this = self.await?; let this = self.await?;
let Some(client_entry_module) = let Some(client_entry_module) =
ChunkableModuleVc::resolve_from(this.client_entry_module).await? Vc::try_resolve_sidecast::<Box<dyn ChunkableModule>>(this.client_entry_module).await?
else { else {
bail!("dynamic client asset must be chunkable"); bail!("dynamic client asset must be chunkable");
}; };
@ -47,28 +47,28 @@ impl NextDynamicEntryModuleVc {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn dynamic_modifier() -> StringVc { fn dynamic_modifier() -> Vc<String> {
StringVc::cell("dynamic".to_string()) Vc::cell("dynamic".to_string())
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for NextDynamicEntryModule { impl Asset for NextDynamicEntryModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.client_entry_module self.client_entry_module
.ident() .ident()
.with_modifier(dynamic_modifier()) .with_modifier(dynamic_modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> Result<AssetContentVc> { fn content(&self) -> Result<Vc<AssetContent>> {
// The client reference asset only serves as a marker asset. // The client reference asset only serves as a marker asset.
bail!("NextDynamicEntryModule has no content") bail!("NextDynamicEntryModule has no content")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(_self_vc: NextDynamicEntryModuleVc) -> AssetReferencesVc { fn references(self: Vc<Self>) -> Vc<AssetReferences> {
AssetReferencesVc::empty() AssetReferences::empty()
} }
} }

View file

@ -1,27 +1,27 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{module::ModuleVc, reference_type::ReferenceType, source::SourceVc}, core::{module::Module, reference_type::ReferenceType, source::Source},
turbopack::{ turbopack::{
transition::{ContextTransitionVc, Transition, TransitionVc}, transition::{ContextTransition, Transition},
ModuleAssetContextVc, ModuleAssetContext,
}, },
}; };
use super::NextDynamicEntryModuleVc; use super::NextDynamicEntryModule;
/// This transition is used to create the marker asset for a next/dynamic /// This transition is used to create the marker asset for a next/dynamic
/// import. This will get picked up during module processing and will be used to /// import. This will get picked up during module processing and will be used to
/// create the dynamic entry, and the dynamic manifest entry. /// create the dynamic entry, and the dynamic manifest entry.
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct NextDynamicTransition { pub struct NextDynamicTransition {
client_transition: ContextTransitionVc, client_transition: Vc<ContextTransition>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextDynamicTransitionVc { impl NextDynamicTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(client_transition: ContextTransitionVc) -> Self { pub fn new(client_transition: Vc<ContextTransition>) -> Vc<Self> {
NextDynamicTransition { client_transition }.cell() NextDynamicTransition { client_transition }.cell()
} }
} }
@ -31,14 +31,14 @@ impl Transition for NextDynamicTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process( async fn process(
&self, &self,
source: SourceVc, source: Vc<Box<dyn Source>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
_reference_type: Value<ReferenceType>, _reference_type: Value<ReferenceType>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let client_module = let client_module =
self.client_transition self.client_transition
.process(source, context, Value::new(ReferenceType::Undefined)); .process(source, context, Value::new(ReferenceType::Undefined));
Ok(NextDynamicEntryModuleVc::new(client_module).into()) Ok(Vc::upcast(NextDynamicEntryModule::new(client_module)))
} }
} }

View file

@ -2,6 +2,6 @@ pub(crate) mod dynamic_module;
pub(crate) mod dynamic_transition; pub(crate) mod dynamic_transition;
pub(crate) mod visit_dynamic; pub(crate) mod visit_dynamic;
pub use dynamic_module::NextDynamicEntryModuleVc; pub use dynamic_module::NextDynamicEntryModule;
pub use dynamic_transition::NextDynamicTransitionVc; pub use dynamic_transition::NextDynamicTransition;
pub use visit_dynamic::NextDynamicEntriesVc; pub use visit_dynamic::NextDynamicEntries;

View file

@ -3,22 +3,22 @@ use std::future::Future;
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{ use turbo_tasks::{
graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow}, graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow},
TryJoinIterExt, TryJoinIterExt, Vc,
}; };
use turbopack_binding::turbopack::core::{ use turbopack_binding::turbopack::core::{
asset::{Asset, AssetVc, AssetsVc}, asset::{Asset, Assets},
reference::AssetReference, reference::AssetReference,
}; };
use super::NextDynamicEntryModuleVc; use super::NextDynamicEntryModule;
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub struct NextDynamicEntries(Vec<NextDynamicEntryModuleVc>); pub struct NextDynamicEntries(Vec<Vc<NextDynamicEntryModule>>);
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextDynamicEntriesVc { impl NextDynamicEntries {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn from_entries(entries: AssetsVc) -> Result<NextDynamicEntriesVc> { pub async fn from_entries(entries: Vc<Assets>) -> Result<Vc<NextDynamicEntries>> {
let nodes: Vec<_> = AdjacencyMap::new() let nodes: Vec<_> = AdjacencyMap::new()
.skip_duplicates() .skip_duplicates()
.visit( .visit(
@ -50,7 +50,7 @@ impl NextDynamicEntriesVc {
} }
} }
Ok(NextDynamicEntriesVc::cell(next_dynamics)) Ok(Vc::cell(next_dynamics))
} }
} }
@ -58,8 +58,8 @@ struct VisitDynamic;
#[derive(Clone, Eq, PartialEq, Hash)] #[derive(Clone, Eq, PartialEq, Hash)]
enum VisitDynamicNode { enum VisitDynamicNode {
Dynamic(NextDynamicEntryModuleVc), Dynamic(Vc<NextDynamicEntryModule>),
Internal(AssetVc), Internal(Vc<Box<dyn Asset>>),
} }
impl Visit<VisitDynamicNode> for VisitDynamic { impl Visit<VisitDynamicNode> for VisitDynamic {
@ -77,7 +77,7 @@ impl Visit<VisitDynamicNode> for VisitDynamic {
let node = node.clone(); let node = node.clone();
async move { async move {
let asset = match node { let asset = match node {
VisitDynamicNode::Dynamic(dynamic_asset) => dynamic_asset.into(), VisitDynamicNode::Dynamic(dynamic_asset) => Vc::upcast(dynamic_asset),
VisitDynamicNode::Internal(asset) => asset, VisitDynamicNode::Internal(asset) => asset,
}; };
@ -97,7 +97,7 @@ impl Visit<VisitDynamicNode> for VisitDynamic {
let referenced_assets = referenced_assets.map(|asset| async move { let referenced_assets = referenced_assets.map(|asset| async move {
if let Some(next_dynamic_asset) = if let Some(next_dynamic_asset) =
NextDynamicEntryModuleVc::resolve_from(asset).await? Vc::try_resolve_downcast_type::<NextDynamicEntryModule>(asset).await?
{ {
return Ok(VisitDynamicNode::Dynamic(next_dynamic_asset)); return Ok(VisitDynamicNode::Dynamic(next_dynamic_asset));
} }

View file

@ -1,28 +1,25 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{ core::{
compile_time_defines, compile_time_defines,
compile_time_info::{ compile_time_info::{
CompileTimeDefines, CompileTimeDefinesVc, CompileTimeInfo, CompileTimeInfoVc, CompileTimeDefines, CompileTimeInfo, FreeVarReference, FreeVarReferences,
FreeVarReference, FreeVarReferencesVc,
},
environment::{
EdgeWorkerEnvironment, EnvironmentVc, ExecutionEnvironment, ServerAddrVc,
}, },
environment::{EdgeWorkerEnvironment, Environment, ExecutionEnvironment, ServerAddr},
free_var_references, free_var_references,
}, },
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, turbopack::resolve_options_context::ResolveOptionsContext,
}, },
}; };
use crate::{ use crate::{
mode::NextMode, next_config::NextConfigVc, next_import_map::get_next_edge_import_map, mode::NextMode, next_config::NextConfig, next_import_map::get_next_edge_import_map,
next_server::context::ServerContextType, next_server::context::ServerContextType, next_shared::resolve::UnsupportedModulesResolvePlugin,
next_shared::resolve::UnsupportedModulesResolvePluginVc, util::foreign_code_context_condition, util::foreign_code_context_condition,
}; };
fn defines() -> CompileTimeDefines { fn defines() -> CompileTimeDefines {
@ -37,12 +34,12 @@ fn defines() -> CompileTimeDefines {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn next_edge_defines() -> CompileTimeDefinesVc { fn next_edge_defines() -> Vc<CompileTimeDefines> {
defines().cell() defines().cell()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn next_edge_free_vars(project_path: FileSystemPathVc) -> FreeVarReferencesVc { fn next_edge_free_vars(project_path: Vc<FileSystemPath>) -> Vc<FreeVarReferences> {
free_var_references!( free_var_references!(
..defines().into_iter(), ..defines().into_iter(),
Buffer = FreeVarReference::EcmaScriptModule { Buffer = FreeVarReference::EcmaScriptModule {
@ -61,10 +58,10 @@ fn next_edge_free_vars(project_path: FileSystemPathVc) -> FreeVarReferencesVc {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_edge_compile_time_info( pub fn get_edge_compile_time_info(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
server_addr: ServerAddrVc, server_addr: Vc<ServerAddr>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
CompileTimeInfo::builder(EnvironmentVc::new(Value::new( CompileTimeInfo::builder(Environment::new(Value::new(
ExecutionEnvironment::EdgeWorker(EdgeWorkerEnvironment { server_addr }.into()), ExecutionEnvironment::EdgeWorker(EdgeWorkerEnvironment { server_addr }.into()),
))) )))
.defines(next_edge_defines()) .defines(next_edge_defines())
@ -74,12 +71,12 @@ pub fn get_edge_compile_time_info(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_edge_resolve_options_context( pub async fn get_edge_resolve_options_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
ty: Value<ServerContextType>, ty: Value<ServerContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<ResolveOptionsContextVc> { ) -> Result<Vc<ResolveOptionsContext>> {
let next_edge_import_map = let next_edge_import_map =
get_next_edge_import_map(project_path, ty, mode, next_config, execution_context); get_next_edge_import_map(project_path, ty, mode, next_config, execution_context);
@ -94,7 +91,9 @@ pub async fn get_edge_resolve_options_context(
import_map: Some(next_edge_import_map), import_map: Some(next_edge_import_map),
module: true, module: true,
browser: true, browser: true,
plugins: vec![UnsupportedModulesResolvePluginVc::new(project_path).into()], plugins: vec![Vc::upcast(UnsupportedModulesResolvePlugin::new(
project_path,
))],
..Default::default() ..Default::default()
}; };

View file

@ -1,24 +1,22 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indexmap::indexmap; use indexmap::indexmap;
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{ core::{
chunk::{ChunkableModuleVc, ChunkingContextVc}, chunk::{ChunkableModule, ChunkingContext},
compile_time_info::CompileTimeInfoVc, compile_time_info::CompileTimeInfo,
context::AssetContext, context::AssetContext,
file_source::FileSourceVc, file_source::FileSource,
module::ModuleVc, module::Module,
reference_type::{EcmaScriptModulesReferenceSubType, InnerAssetsVc, ReferenceType}, reference_type::{EcmaScriptModulesReferenceSubType, ReferenceType},
source::SourceVc, source::Source,
}, },
ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset,
turbopack::{ turbopack::{
module_options::ModuleOptionsContextVc, module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext,
resolve_options_context::ResolveOptionsContextVc, transition::Transition, ModuleAssetContext,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}, },
}; };
@ -32,12 +30,12 @@ use crate::embed_js::next_js_file_path;
/// that for running them in the edge sandbox. /// that for running them in the edge sandbox.
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextEdgePageTransition { pub struct NextEdgePageTransition {
pub edge_compile_time_info: CompileTimeInfoVc, pub edge_compile_time_info: Vc<CompileTimeInfo>,
pub edge_chunking_context: ChunkingContextVc, pub edge_chunking_context: Vc<Box<dyn ChunkingContext>>,
pub edge_module_options_context: Option<ModuleOptionsContextVc>, pub edge_module_options_context: Option<Vc<ModuleOptionsContext>>,
pub edge_resolve_options_context: ResolveOptionsContextVc, pub edge_resolve_options_context: Vc<ResolveOptionsContext>,
pub output_path: FileSystemPathVc, pub output_path: Vc<FileSystemPath>,
pub bootstrap_asset: SourceVc, pub bootstrap_asset: Vc<Box<dyn Source>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
@ -45,47 +43,48 @@ impl Transition for NextEdgePageTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_compile_time_info( fn process_compile_time_info(
&self, &self,
_compile_time_info: CompileTimeInfoVc, _compile_time_info: Vc<CompileTimeInfo>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
self.edge_compile_time_info self.edge_compile_time_info
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_module_options_context( fn process_module_options_context(
&self, &self,
context: ModuleOptionsContextVc, context: Vc<ModuleOptionsContext>,
) -> ModuleOptionsContextVc { ) -> Vc<ModuleOptionsContext> {
self.edge_module_options_context.unwrap_or(context) self.edge_module_options_context.unwrap_or(context)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_resolve_options_context( fn process_resolve_options_context(
&self, &self,
_context: ResolveOptionsContextVc, _context: Vc<ResolveOptionsContext>,
) -> ResolveOptionsContextVc { ) -> Vc<ResolveOptionsContext> {
self.edge_resolve_options_context self.edge_resolve_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
&self, &self,
asset: ModuleVc, asset: Vc<Box<dyn Module>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let module = context.process( let module = context.process(
self.bootstrap_asset, self.bootstrap_asset,
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(indexmap! { Value::new(ReferenceType::Internal(Vc::cell(indexmap! {
"APP_ENTRY".to_string() => asset.into(), "APP_ENTRY".to_string() => Vc::upcast(asset),
"APP_BOOTSTRAP".to_string() => context.with_transition("next-client").process( "APP_BOOTSTRAP".to_string() => Vc::upcast(context.with_transition("next-client".to_string()).process(
FileSourceVc::new(next_js_file_path("entry/app/hydrate.tsx")).into(), Vc::upcast(FileSource::new(next_js_file_path("entry/app/hydrate.tsx".to_string()))),
Value::new(ReferenceType::EcmaScriptModules( Value::new(ReferenceType::EcmaScriptModules(
EcmaScriptModulesReferenceSubType::Undefined, EcmaScriptModulesReferenceSubType::Undefined,
)), )),
).into(), )),
}))), }))),
); );
let Some(module) = ChunkableModuleVc::resolve_from(module).await? else { let Some(module) = Vc::try_resolve_sidecast::<Box<dyn ChunkableModule>>(module).await?
else {
bail!("Internal module is not chunkable"); bail!("Internal module is not chunkable");
}; };
@ -96,6 +95,6 @@ impl Transition for NextEdgePageTransition {
runtime_entries: None, runtime_entries: None,
}; };
Ok(asset.cell().into()) Ok(Vc::upcast(asset.cell()))
} }
} }

View file

@ -1,33 +1,32 @@
use anyhow::Result; use anyhow::Result;
use indexmap::indexmap; use indexmap::indexmap;
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::{ turbopack::{
core::{ core::{
chunk::ChunkingContextVc, compile_time_info::CompileTimeInfoVc, module::ModuleVc, chunk::ChunkingContext, compile_time_info::CompileTimeInfo, module::Module,
source::SourceVc, source::Source,
}, },
ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset, ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset,
turbopack::{ turbopack::{
module_options::ModuleOptionsContextVc, module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext,
resolve_options_context::ResolveOptionsContextVc, transition::Transition, ModuleAssetContext,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
}, },
}, },
}; };
use crate::bootstrap::{route_bootstrap, BootstrapConfigVc}; use crate::bootstrap::route_bootstrap;
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextEdgeRouteTransition { pub struct NextEdgeRouteTransition {
pub edge_compile_time_info: CompileTimeInfoVc, pub edge_compile_time_info: Vc<CompileTimeInfo>,
pub edge_chunking_context: ChunkingContextVc, pub edge_chunking_context: Vc<Box<dyn ChunkingContext>>,
pub edge_module_options_context: Option<ModuleOptionsContextVc>, pub edge_module_options_context: Option<Vc<ModuleOptionsContext>>,
pub edge_resolve_options_context: ResolveOptionsContextVc, pub edge_resolve_options_context: Vc<ResolveOptionsContext>,
pub output_path: FileSystemPathVc, pub output_path: Vc<FileSystemPath>,
pub base_path: FileSystemPathVc, pub base_path: Vc<FileSystemPath>,
pub bootstrap_asset: SourceVc, pub bootstrap_asset: Vc<Box<dyn Source>>,
pub entry_name: String, pub entry_name: String,
} }
@ -36,50 +35,50 @@ impl Transition for NextEdgeRouteTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_compile_time_info( fn process_compile_time_info(
&self, &self,
_compile_time_info: CompileTimeInfoVc, _compile_time_info: Vc<CompileTimeInfo>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
self.edge_compile_time_info self.edge_compile_time_info
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_module_options_context( fn process_module_options_context(
&self, &self,
context: ModuleOptionsContextVc, context: Vc<ModuleOptionsContext>,
) -> ModuleOptionsContextVc { ) -> Vc<ModuleOptionsContext> {
self.edge_module_options_context.unwrap_or(context) self.edge_module_options_context.unwrap_or(context)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn process_resolve_options_context( fn process_resolve_options_context(
&self, &self,
_context: ResolveOptionsContextVc, _context: Vc<ResolveOptionsContext>,
) -> ResolveOptionsContextVc { ) -> Vc<ResolveOptionsContext> {
self.edge_resolve_options_context self.edge_resolve_options_context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
&self, &self,
asset: ModuleVc, asset: Vc<Box<dyn Module>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let new_asset = route_bootstrap( let new_asset = route_bootstrap(
asset.into(), Vc::upcast(asset),
context.into(), Vc::upcast(context),
self.base_path, self.base_path,
self.bootstrap_asset, self.bootstrap_asset,
BootstrapConfigVc::cell(indexmap! { Vc::cell(indexmap! {
"NAME".to_string() => self.entry_name.clone(), "NAME".to_string() => self.entry_name.clone(),
}), }),
); );
let asset = ChunkGroupFilesAsset { let asset = ChunkGroupFilesAsset {
module: new_asset.into(), module: Vc::upcast(new_asset),
client_root: self.output_path, client_root: self.output_path,
chunking_context: self.edge_chunking_context, chunking_context: self.edge_chunking_context,
runtime_entries: None, runtime_entries: None,
}; };
Ok(asset.cell().into()) Ok(Vc::upcast(asset.cell()))
} }
} }

View file

@ -1,10 +1,7 @@
use anyhow::Result;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbopack_binding::turbo::tasks::{ use turbo_tasks::Vc;
primitives::{StringVc, StringsVc}, use turbopack_binding::turbo::tasks::trace::TraceRawVcs;
trace::TraceRawVcs,
};
pub(crate) struct DefaultFallbackFont { pub(crate) struct DefaultFallbackFont {
pub name: String, pub name: String,
@ -34,9 +31,9 @@ pub(crate) static DEFAULT_SERIF_FONT: Lazy<DefaultFallbackFont> =
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub(crate) struct AutomaticFontFallback { pub(crate) struct AutomaticFontFallback {
/// e.g. `__Roboto_Fallback_c123b8` /// e.g. `__Roboto_Fallback_c123b8`
pub scoped_font_family: StringVc, pub scoped_font_family: Vc<String>,
/// The name of font locally, used in `src: local("{}")` /// The name of font locally, used in `src: local("{}")`
pub local_font_family: StringVc, pub local_font_family: Vc<String>,
pub adjustment: Option<FontAdjustment>, pub adjustment: Option<FontAdjustment>,
} }
@ -45,17 +42,17 @@ pub(crate) struct AutomaticFontFallback {
pub(crate) enum FontFallback { pub(crate) enum FontFallback {
/// An automatically generated fallback font generated by next/font. May /// An automatically generated fallback font generated by next/font. May
/// include an optional [[FontAdjustment]]. /// include an optional [[FontAdjustment]].
Automatic(AutomaticFontFallbackVc), Automatic(Vc<AutomaticFontFallback>),
/// There was an issue preparing the font fallback. Since resolving the /// There was an issue preparing the font fallback. Since resolving the
/// font css cannot fail, proper Errors cannot be returned. Emit an issue, /// font css cannot fail, proper Errors cannot be returned. Emit an issue,
/// return this and omit fallback information instead. /// return this and omit fallback information instead.
Error, Error,
/// A list of manually provided font names to use a fallback, as-is. /// A list of manually provided font names to use a fallback, as-is.
Manual(StringsVc), Manual(Vc<Vec<String>>),
} }
#[turbo_tasks::value(transparent)] #[turbo_tasks::value(transparent)]
pub(crate) struct FontFallbacks(Vec<FontFallbackVc>); pub(crate) struct FontFallbacks(Vec<Vc<FontFallback>>);
/// An adjustment to be made to a fallback font to approximate the geometry of /// An adjustment to be made to a fallback font to approximate the geometry of
/// the main webfont. Rendered as e.g. `ascent-override: 56.8%;` in the /// the main webfont. Rendered as e.g. `ascent-override: 56.8%;` in the

View file

@ -4,18 +4,18 @@ use anyhow::{Context, Result};
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbo_tasks::{ use turbo_tasks::{trace::TraceRawVcs, Vc};
primitives::{StringVc, StringsVc, U32Vc}, use turbopack_binding::{
trace::TraceRawVcs, turbo::tasks_fs::FileSystemPath,
turbopack::core::issue::{IssueExt, IssueSeverity},
}; };
use turbopack_binding::{turbo::tasks_fs::FileSystemPathVc, turbopack::core::issue::IssueSeverity};
use super::options::NextFontGoogleOptionsVc; use super::options::NextFontGoogleOptions;
use crate::{ use crate::{
next_font::{ next_font::{
font_fallback::{ font_fallback::{
AutomaticFontFallback, FontAdjustment, FontFallback, FontFallbackVc, AutomaticFontFallback, FontAdjustment, FontFallback, DEFAULT_SANS_SERIF_FONT,
DEFAULT_SANS_SERIF_FONT, DEFAULT_SERIF_FONT, DEFAULT_SERIF_FONT,
}, },
issue::NextFontIssue, issue::NextFontIssue,
util::{get_scoped_font_family, FontFamilyType}, util::{get_scoped_font_family, FontFamilyType},
@ -46,13 +46,13 @@ struct Fallback {
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn get_font_fallback( pub(super) async fn get_font_fallback(
context: FileSystemPathVc, context: Vc<FileSystemPath>,
options_vc: NextFontGoogleOptionsVc, options_vc: Vc<NextFontGoogleOptions>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<FontFallbackVc> { ) -> Result<Vc<FontFallback>> {
let options = options_vc.await?; let options = options_vc.await?;
Ok(match &options.fallback { Ok(match &options.fallback {
Some(fallback) => FontFallback::Manual(StringsVc::cell(fallback.clone())).cell(), Some(fallback) => FontFallback::Manual(Vc::cell(fallback.clone())).cell(),
None => { None => {
let metrics_json = let metrics_json =
load_next_json(context, "/dist/server/capsize-font-metrics.json").await?; load_next_json(context, "/dist/server/capsize-font-metrics.json").await?;
@ -70,7 +70,7 @@ pub(super) async fn get_font_fallback(
options_vc.font_family(), options_vc.font_family(),
request_hash, request_hash,
), ),
local_font_family: StringVc::cell(fallback.font_family), local_font_family: Vc::cell(fallback.font_family),
adjustment: fallback.adjustment, adjustment: fallback.adjustment,
} }
.cell(), .cell(),
@ -79,17 +79,14 @@ pub(super) async fn get_font_fallback(
Err(_) => { Err(_) => {
NextFontIssue { NextFontIssue {
path: context, path: context,
title: StringVc::cell(format!( title: Vc::cell(format!(
"Failed to find font override values for font `{}`", "Failed to find font override values for font `{}`",
&options.font_family, &options.font_family,
)), )),
description: StringVc::cell( description: Vc::cell("Skipping generating a fallback font.".to_owned()),
"Skipping generating a fallback font.".to_owned(),
),
severity: IssueSeverity::Warning.cell(), severity: IssueSeverity::Warning.cell(),
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
FontFallback::Error.cell() FontFallback::Error.cell()
} }

View file

@ -4,57 +4,48 @@ use anyhow::{bail, Context, Result};
use futures::FutureExt; use futures::FutureExt;
use indexmap::IndexMap; use indexmap::IndexMap;
use indoc::formatdoc; use indoc::formatdoc;
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{
tasks::{ tasks::{Completion, Value},
primitives::{OptionStringVc, StringVc, U32Vc},
CompletionVc, Value,
},
tasks_bytes::stream::SingleValue, tasks_bytes::stream::SingleValue,
tasks_env::{CommandLineProcessEnvVc, ProcessEnv}, tasks_env::{CommandLineProcessEnv, ProcessEnv},
tasks_fetch::fetch, tasks_fetch::fetch,
tasks_fs::{ tasks_fs::{
json::parse_json_with_source_context, DiskFileSystemVc, File, FileContent, FileSystem, json::parse_json_with_source_context, DiskFileSystem, File, FileContent, FileSystem,
FileSystemPathVc, FileSystemPath,
}, },
}, },
turbopack::{ turbopack::{
core::{ core::{
asset::AssetContent,
context::AssetContext, context::AssetContext,
ident::AssetIdentVc, ident::AssetIdent,
issue::IssueSeverity, issue::{IssueExt, IssueSeverity},
reference_type::{InnerAssetsVc, ReferenceType}, reference_type::{InnerAssets, ReferenceType},
resolve::{ resolve::{
options::{ options::{ImportMapResult, ImportMapping, ImportMappingReplacement},
ImportMapResult, ImportMapResultVc, ImportMapping, ImportMappingReplacement, parse::Request,
ImportMappingReplacementVc, ImportMappingVc, pattern::QueryMap,
},
parse::{Request, RequestVc},
pattern::QueryMapVc,
ResolveResult, ResolveResult,
}, },
virtual_source::VirtualSourceVc, virtual_source::VirtualSource,
},
node::{
debug::should_debug,
evaluate::evaluate,
execution_context::{ExecutionContext, ExecutionContextVc},
}, },
node::{debug::should_debug, evaluate::evaluate, execution_context::ExecutionContext},
turbopack::evaluate_context::node_evaluate_asset_context, turbopack::evaluate_context::node_evaluate_asset_context,
}, },
}; };
use self::{ use self::{
font_fallback::get_font_fallback, font_fallback::get_font_fallback,
options::{options_from_request, FontDataEntry, FontWeights, NextFontGoogleOptionsVc}, options::{options_from_request, FontDataEntry, FontWeights, NextFontGoogleOptions},
stylesheet::build_stylesheet, stylesheet::build_stylesheet,
util::{get_font_axes, get_stylesheet_url}, util::{get_font_axes, get_stylesheet_url},
}; };
use super::{ use super::{
font_fallback::{FontFallback, FontFallbackVc}, font_fallback::FontFallback,
util::{ util::{
get_request_hash, get_request_id, get_scoped_font_family, FontCssProperties, get_request_hash, get_request_id, get_scoped_font_family, FontCssProperties, FontFamilyType,
FontCssPropertiesVc, FontFamilyType,
}, },
}; };
use crate::{embed_js::next_js_file_path, util::load_next_json}; use crate::{embed_js::next_js_file_path, util::load_next_json};
@ -78,13 +69,13 @@ struct FontData(IndexMap<String, FontDataEntry>);
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub(crate) struct NextFontGoogleReplacer { pub(crate) struct NextFontGoogleReplacer {
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFontGoogleReplacerVc { impl NextFontGoogleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(project_path: FileSystemPathVc) -> Self { pub fn new(project_path: Vc<FileSystemPath>) -> Vc<Self> {
Self::cell(NextFontGoogleReplacer { project_path }) Self::cell(NextFontGoogleReplacer { project_path })
} }
} }
@ -92,7 +83,7 @@ impl NextFontGoogleReplacerVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ImportMappingReplacement for NextFontGoogleReplacer { impl ImportMappingReplacement for NextFontGoogleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
fn replace(&self, _capture: &str) -> ImportMappingVc { fn replace(&self, _capture: String) -> Vc<ImportMapping> {
ImportMapping::Ignore.into() ImportMapping::Ignore.into()
} }
@ -102,9 +93,9 @@ impl ImportMappingReplacement for NextFontGoogleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn result( async fn result(
&self, &self,
_context: FileSystemPathVc, _context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
) -> Result<ImportMapResultVc> { ) -> Result<Vc<ImportMapResult>> {
let request = &*request.await?; let request = &*request.await?;
let Request::Module { let Request::Module {
module: _, module: _,
@ -121,62 +112,65 @@ impl ImportMappingReplacement for NextFontGoogleReplacer {
let request_hash = get_request_hash(*query_vc); let request_hash = get_request_hash(*query_vc);
let fallback = get_font_fallback(self.project_path, options, request_hash); let fallback = get_font_fallback(self.project_path, options, request_hash);
let properties = get_font_css_properties(options, fallback, request_hash).await?; let properties = get_font_css_properties(options, fallback, request_hash).await?;
let js_asset = VirtualSourceVc::new( let js_asset = VirtualSource::new(
next_js_file_path("internal/font/google") next_js_file_path("internal/font/google".to_string())
.join(&format!("{}.js", get_request_id(options.font_family(), request_hash).await?)), .join(format!("{}.js", get_request_id(options.font_family(), request_hash).await?)),
FileContent::Content( AssetContent::file(FileContent::Content(
formatdoc!( formatdoc!(
r#" r#"
import cssModule from "@vercel/turbopack-next/internal/font/google/cssmodule.module.css?{}"; import cssModule from "@vercel/turbopack-next/internal/font/google/cssmodule.module.css?{}";
const fontData = {{ const fontData = {{
className: cssModule.className, className: cssModule.className,
style: {{ style: {{
fontFamily: "{}", fontFamily: "{}",
{}{} {}{}
}}, }},
}}; }};
if (cssModule.variable != null) {{ if (cssModule.variable != null) {{
fontData.variable = cssModule.variable; fontData.variable = cssModule.variable;
}} }}
export default fontData; export default fontData;
"#, "#,
// Pass along whichever options we received to the css handler // Pass along whichever options we received to the css handler
qstring::QString::new(query.as_ref().unwrap().iter().collect()), qstring::QString::new(query.as_ref().unwrap().iter().collect()),
properties.font_family.await?, properties.font_family.await?,
properties properties
.weight .weight
.await? .await?
.as_ref() .as_ref()
.map(|w| format!("fontWeight: {},\n", w)) .map(|w| format!("fontWeight: {},\n", w))
.unwrap_or_else(|| "".to_owned()), .unwrap_or_else(|| "".to_owned()),
properties properties
.style .style
.await? .await?
.as_ref() .as_ref()
.map(|s| format!("fontStyle: \"{}\",\n", s)) .map(|s| format!("fontStyle: \"{}\",\n", s))
.unwrap_or_else(|| "".to_owned()), .unwrap_or_else(|| "".to_owned()),
)
.into(),
) )
.into(), .into(),
); )
.into()),
);
Ok(ImportMapResult::Result(ResolveResult::asset(js_asset.into()).into()).into()) Ok(ImportMapResult::Result(ResolveResult::asset(Vc::upcast(js_asset)).into()).into())
} }
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextFontGoogleCssModuleReplacer { pub struct NextFontGoogleCssModuleReplacer {
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFontGoogleCssModuleReplacerVc { impl NextFontGoogleCssModuleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(project_path: FileSystemPathVc, execution_context: ExecutionContextVc) -> Self { pub fn new(
project_path: Vc<FileSystemPath>,
execution_context: Vc<ExecutionContext>,
) -> Vc<Self> {
Self::cell(NextFontGoogleCssModuleReplacer { Self::cell(NextFontGoogleCssModuleReplacer {
project_path, project_path,
execution_context, execution_context,
@ -187,7 +181,7 @@ impl NextFontGoogleCssModuleReplacerVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer { impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
fn replace(&self, _capture: &str) -> ImportMappingVc { fn replace(&self, _capture: String) -> Vc<ImportMapping> {
ImportMapping::Ignore.into() ImportMapping::Ignore.into()
} }
@ -198,9 +192,9 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn result( async fn result(
&self, &self,
_context: FileSystemPathVc, _context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
) -> Result<ImportMapResultVc> { ) -> Result<Vc<ImportMapResult>> {
let request = &*request.await?; let request = &*request.await?;
let Request::Module { let Request::Module {
module: _, module: _,
@ -220,7 +214,7 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
options.font_family(), options.font_family(),
request_hash, request_hash,
); );
let css_virtual_path = next_js_file_path("internal/font/google").join(&format!( let css_virtual_path = next_js_file_path("internal/font/google".to_string()).join(format!(
"/{}.module.css", "/{}.module.css",
get_request_id(options.font_family(), request_hash).await? get_request_id(options.font_family(), request_hash).await?
)); ));
@ -228,8 +222,10 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
// When running Next.js integration tests, use the mock data available in // When running Next.js integration tests, use the mock data available in
// process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES instead of making real // process.env.NEXT_FONT_GOOGLE_MOCKED_RESPONSES instead of making real
// requests to Google Fonts. // requests to Google Fonts.
let env = CommandLineProcessEnvVc::new().as_process_env(); let env = Vc::upcast::<Box<dyn ProcessEnv>>(CommandLineProcessEnv::new());
let mocked_responses_path = &*env.read("NEXT_FONT_GOOGLE_MOCKED_RESPONSES").await?; let mocked_responses_path = &*env
.read("NEXT_FONT_GOOGLE_MOCKED_RESPONSES".to_string())
.await?;
let stylesheet_str = mocked_responses_path let stylesheet_str = mocked_responses_path
.as_ref() .as_ref()
.map_or_else( .map_or_else(
@ -248,26 +244,28 @@ impl ImportMappingReplacement for NextFontGoogleCssModuleReplacer {
}; };
let font_fallback = get_font_fallback(self.project_path, options, request_hash); let font_fallback = get_font_fallback(self.project_path, options, request_hash);
let css_asset = VirtualSourceVc::new( let css_asset = VirtualSource::new(
css_virtual_path, css_virtual_path,
FileContent::Content( AssetContent::file(
build_stylesheet( FileContent::Content(
OptionStringVc::cell(stylesheet), build_stylesheet(
get_font_css_properties(options, font_fallback, request_hash), Vc::cell(stylesheet),
font_fallback, get_font_css_properties(options, font_fallback, request_hash),
font_fallback,
)
.await?
.into(),
) )
.await?
.into(), .into(),
) ),
.into(),
); );
Ok(ImportMapResult::Result(ResolveResult::asset(css_asset.into()).into()).into()) Ok(ImportMapResult::Result(ResolveResult::asset(Vc::upcast(css_asset)).into()).into())
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn load_font_data(project_root: FileSystemPathVc) -> Result<FontDataVc> { async fn load_font_data(project_root: Vc<FileSystemPath>) -> Result<Vc<FontData>> {
let data: FontData = load_next_json( let data: FontData = load_next_json(
project_root, project_root,
"/dist/compiled/@next/font/dist/google/font-data.json", "/dist/compiled/@next/font/dist/google/font-data.json",
@ -281,13 +279,13 @@ async fn load_font_data(project_root: FileSystemPathVc) -> Result<FontDataVc> {
/// font family names. /// font family names.
#[turbo_tasks::function] #[turbo_tasks::function]
async fn update_google_stylesheet( async fn update_google_stylesheet(
stylesheet: StringVc, stylesheet: Vc<String>,
options: NextFontGoogleOptionsVc, options: Vc<NextFontGoogleOptions>,
scoped_font_family: StringVc, scoped_font_family: Vc<String>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
// Update font-family definitions to the scoped name // Update font-family definitions to the scoped name
// TODO: Do this more resiliently, e.g. transforming an swc ast // TODO: Do this more resiliently, e.g. transforming an swc ast
Ok(StringVc::cell(stylesheet.await?.replace( Ok(Vc::cell(stylesheet.await?.replace(
&format!("font-family: '{}';", &*options.await?.font_family), &format!("font-family: '{}';", &*options.await?.font_family),
&format!("font-family: '{}';", &*scoped_font_family.await?), &format!("font-family: '{}';", &*scoped_font_family.await?),
))) )))
@ -295,23 +293,26 @@ async fn update_google_stylesheet(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get_stylesheet_url_from_options( async fn get_stylesheet_url_from_options(
options: NextFontGoogleOptionsVc, options: Vc<NextFontGoogleOptions>,
font_data: FontDataVc, font_data: Vc<FontData>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
#[allow(unused_mut, unused_assignments)] // This is used in test environments #[allow(unused_mut, unused_assignments)] // This is used in test environments
let mut css_url: Option<String> = None; let mut css_url: Option<String> = None;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
{ {
use turbopack_binding::turbo::tasks_env::{CommandLineProcessEnvVc, ProcessEnv}; use turbopack_binding::turbo::tasks_env::{CommandLineProcessEnv, ProcessEnv};
let env = CommandLineProcessEnvVc::new(); let env = CommandLineProcessEnv::new();
if let Some(url) = &*env.read("TURBOPACK_TEST_ONLY_MOCK_SERVER").await? { if let Some(url) = &*env
.read("TURBOPACK_TEST_ONLY_MOCK_SERVER".to_string())
.await?
{
css_url = Some(format!("{}/css2", url)); css_url = Some(format!("{}/css2", url));
} }
} }
let options = options.await?; let options = options.await?;
Ok(StringVc::cell(get_stylesheet_url( Ok(Vc::cell(get_stylesheet_url(
css_url.as_deref().unwrap_or(GOOGLE_FONTS_STYLESHEET_URL), css_url.as_deref().unwrap_or(GOOGLE_FONTS_STYLESHEET_URL),
&options.font_family, &options.font_family,
&get_font_axes( &get_font_axes(
@ -327,10 +328,10 @@ async fn get_stylesheet_url_from_options(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get_font_css_properties( async fn get_font_css_properties(
options_vc: NextFontGoogleOptionsVc, options_vc: Vc<NextFontGoogleOptions>,
font_fallback: FontFallbackVc, font_fallback: Vc<FontFallback>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<FontCssPropertiesVc> { ) -> Result<Vc<FontCssProperties>> {
let options = &*options_vc.await?; let options = &*options_vc.await?;
let scoped_font_family = &*get_scoped_font_family( let scoped_font_family = &*get_scoped_font_family(
FontFamilyType::WebFont.cell(), FontFamilyType::WebFont.cell(),
@ -352,22 +353,22 @@ async fn get_font_css_properties(
FontFallback::Error => {} FontFallback::Error => {}
} }
Ok(FontCssPropertiesVc::cell(FontCssProperties { Ok(FontCssProperties::cell(FontCssProperties {
font_family: StringVc::cell(font_families.join(", ")), font_family: Vc::cell(font_families.join(", ")),
weight: OptionStringVc::cell(match &options.weights { weight: Vc::cell(match &options.weights {
FontWeights::Variable => None, FontWeights::Variable => None,
FontWeights::Fixed(weights) => weights.first().map(|w| w.to_string()), FontWeights::Fixed(weights) => weights.first().map(|w| w.to_string()),
}), }),
style: OptionStringVc::cell(options.styles.first().cloned()), style: Vc::cell(options.styles.first().cloned()),
variable: OptionStringVc::cell(options.variable.clone()), variable: Vc::cell(options.variable.clone()),
})) }))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn font_options_from_query_map( async fn font_options_from_query_map(
query: QueryMapVc, query: Vc<QueryMap>,
font_data: FontDataVc, font_data: Vc<FontData>,
) -> Result<NextFontGoogleOptionsVc> { ) -> Result<Vc<NextFontGoogleOptions>> {
let query_map = &*query.await?; let query_map = &*query.await?;
// These are invariants from the next/font swc transform. Regular errors instead // These are invariants from the next/font swc transform. Regular errors instead
// of Issues should be okay. // of Issues should be okay.
@ -384,16 +385,16 @@ async fn font_options_from_query_map(
}; };
options_from_request(&parse_json_with_source_context(json)?, &*font_data.await?) options_from_request(&parse_json_with_source_context(json)?, &*font_data.await?)
.map(|o| NextFontGoogleOptionsVc::new(Value::new(o))) .map(|o| NextFontGoogleOptions::new(Value::new(o)))
} }
async fn fetch_real_stylesheet( async fn fetch_real_stylesheet(
stylesheet_url: StringVc, stylesheet_url: Vc<String>,
css_virtual_path: FileSystemPathVc, css_virtual_path: Vc<FileSystemPath>,
) -> Result<Option<StringVc>> { ) -> Result<Option<Vc<String>>> {
let stylesheet = fetch( let stylesheet = fetch(
stylesheet_url, stylesheet_url,
OptionStringVc::cell(Some(USER_AGENT_FOR_GOOGLE_FONTS.to_owned())), Vc::cell(Some(USER_AGENT_FOR_GOOGLE_FONTS.to_owned())),
) )
.await?; .await?;
@ -408,7 +409,6 @@ async fn fetch_real_stylesheet(
// TODO(WEB-283): Use fallback in dev in this case // TODO(WEB-283): Use fallback in dev in this case
// TODO(WEB-293): Fail production builds (not dev) in this case // TODO(WEB-293): Fail production builds (not dev) in this case
err.to_issue(IssueSeverity::Warning.into(), css_virtual_path) err.to_issue(IssueSeverity::Warning.into(), css_virtual_path)
.as_issue()
.emit(); .emit();
None None
@ -417,12 +417,12 @@ async fn fetch_real_stylesheet(
} }
async fn get_mock_stylesheet( async fn get_mock_stylesheet(
stylesheet_url: StringVc, stylesheet_url: Vc<String>,
mocked_responses_path: &str, mocked_responses_path: &str,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<Option<StringVc>> { ) -> Result<Option<Vc<String>>> {
let response_path = Path::new(&mocked_responses_path); let response_path = Path::new(&mocked_responses_path);
let mock_fs = DiskFileSystemVc::new( let mock_fs = Vc::upcast::<Box<dyn FileSystem>>(DiskFileSystem::new(
"mock".to_string(), "mock".to_string(),
response_path response_path
.parent() .parent()
@ -430,8 +430,7 @@ async fn get_mock_stylesheet(
.to_str() .to_str()
.context("Must exist")? .context("Must exist")?
.to_string(), .to_string(),
) ));
.as_file_system();
let ExecutionContext { let ExecutionContext {
env, env,
@ -439,34 +438,35 @@ async fn get_mock_stylesheet(
chunking_context, chunking_context,
} = *execution_context.await?; } = *execution_context.await?;
let context = node_evaluate_asset_context(execution_context, None, None); let context = node_evaluate_asset_context(execution_context, None, None);
let loader_path = mock_fs.root().join("loader.js"); let loader_path = mock_fs.root().join("loader.js".to_string());
let mocked_response_asset = context.process( let mocked_response_asset = context.process(
VirtualSourceVc::new( Vc::upcast(VirtualSource::new(
loader_path, loader_path,
File::from(format!( AssetContent::file(
"import data from './{}'; export default function load() {{ return data; }};", File::from(format!(
response_path "import data from './{}'; export default function load() {{ return data; }};",
.file_name() response_path
.context("Must exist")? .file_name()
.to_string_lossy(), .context("Must exist")?
)) .to_string_lossy(),
.into(), ))
) .into(),
.into(), ),
Value::new(ReferenceType::Internal(InnerAssetsVc::empty())), )),
Value::new(ReferenceType::Internal(InnerAssets::empty())),
); );
let root = mock_fs.root(); let root = mock_fs.root();
let val = evaluate( let val = evaluate(
mocked_response_asset.into(), Vc::upcast(mocked_response_asset),
root, root,
env, env,
AssetIdentVc::from_path(loader_path), AssetIdent::from_path(loader_path),
context, context,
chunking_context, chunking_context,
None, None,
vec![], vec![],
CompletionVc::immutable(), Completion::immutable(),
should_debug("next_font::google"), should_debug("next_font::google"),
) )
.await?; .await?;
@ -479,7 +479,7 @@ async fn get_mock_stylesheet(
.get(&*stylesheet_url.await?) .get(&*stylesheet_url.await?)
.context("url not found")? .context("url not found")?
.clone() .clone()
.map(StringVc::cell)) .map(Vc::cell))
} }
_ => { _ => {
panic!("Unexpected error evaluating JS") panic!("Unexpected error evaluating JS")

View file

@ -1,7 +1,8 @@
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use indexmap::{indexset, IndexMap, IndexSet}; use indexmap::{indexset, IndexMap, IndexSet};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbopack_binding::turbo::tasks::{primitives::StringVc, trace::TraceRawVcs, Value}; use turbo_tasks::Vc;
use turbopack_binding::turbo::tasks::{trace::TraceRawVcs, Value};
use super::request::{NextFontRequest, OneOrManyStrings}; use super::request::{NextFontRequest, OneOrManyStrings};
@ -28,15 +29,15 @@ pub(super) struct NextFontGoogleOptions {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFontGoogleOptionsVc { impl NextFontGoogleOptions {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(options: Value<NextFontGoogleOptions>) -> NextFontGoogleOptionsVc { pub fn new(options: Value<NextFontGoogleOptions>) -> Vc<NextFontGoogleOptions> {
Self::cell(options.into_value()) Self::cell(options.into_value())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn font_family(self) -> Result<StringVc> { pub async fn font_family(self: Vc<Self>) -> Result<Vc<String>> {
Ok(StringVc::cell((*self.await?.font_family).to_owned())) Ok(Vc::cell((*self.await?.font_family).to_owned()))
} }
} }

View file

@ -1,25 +1,24 @@
use anyhow::Result; use anyhow::Result;
use turbopack_binding::turbo::tasks::primitives::{OptionStringVc, StringVc}; use turbo_tasks::Vc;
use super::FontCssPropertiesVc; use super::FontCssProperties;
use crate::next_font::{ use crate::next_font::{
font_fallback::{FontFallbackVc, FontFallbacksVc}, font_fallback::FontFallback,
stylesheet::{build_fallback_definition, build_font_class_rules}, stylesheet::{build_fallback_definition, build_font_class_rules},
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn build_stylesheet( pub(super) async fn build_stylesheet(
base_stylesheet: OptionStringVc, base_stylesheet: Vc<Option<String>>,
font_css_properties: FontCssPropertiesVc, font_css_properties: Vc<FontCssProperties>,
font_fallback: FontFallbackVc, font_fallback: Vc<FontFallback>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
let base_stylesheet = &*base_stylesheet.await?; let base_stylesheet = &*base_stylesheet.await?;
let mut stylesheet = base_stylesheet let mut stylesheet = base_stylesheet
.as_ref() .as_ref()
.map_or_else(|| "".to_owned(), |s| s.to_owned()); .map_or_else(|| "".to_owned(), |s| s.to_owned());
stylesheet stylesheet.push_str(&build_fallback_definition(Vc::cell(vec![font_fallback])).await?);
.push_str(&build_fallback_definition(FontFallbacksVc::cell(vec![font_fallback])).await?);
stylesheet.push_str(&build_font_class_rules(font_css_properties).await?); stylesheet.push_str(&build_font_class_rules(font_css_properties).await?);
Ok(StringVc::cell(stylesheet)) Ok(Vc::cell(stylesheet))
} }

View file

@ -1,41 +1,41 @@
use turbo_tasks::primitives::StringVc; use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::core::issue::{Issue, IssueSeverityVc, IssueVc}, turbopack::core::issue::{Issue, IssueSeverity},
}; };
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub(crate) struct NextFontIssue { pub(crate) struct NextFontIssue {
pub(crate) path: FileSystemPathVc, pub(crate) path: Vc<FileSystemPath>,
pub(crate) title: StringVc, pub(crate) title: Vc<String>,
pub(crate) description: StringVc, pub(crate) description: Vc<String>,
pub(crate) severity: IssueSeverityVc, pub(crate) severity: Vc<IssueSeverity>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Issue for NextFontIssue { impl Issue for NextFontIssue {
#[turbo_tasks::function] #[turbo_tasks::function]
fn category(&self) -> StringVc { fn category(&self) -> Vc<String> {
StringVc::cell("other".to_string()) Vc::cell("other".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc { fn severity(&self) -> Vc<IssueSeverity> {
self.severity self.severity
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc { fn context(&self) -> Vc<FileSystemPath> {
self.path self.path
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn title(&self) -> StringVc { fn title(&self) -> Vc<String> {
self.title self.title
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn description(&self) -> StringVc { fn description(&self) -> Vc<String> {
self.description self.description
} }
} }

View file

@ -3,18 +3,16 @@ use allsorts::{
Font, Font,
}; };
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use turbopack_binding::turbo::{ use turbo_tasks::Vc;
tasks::primitives::{StringVc, StringsVc, U32Vc}, use turbopack_binding::turbo::tasks_fs::{FileContent, FileSystemPath};
tasks_fs::{FileContent, FileSystemPathVc},
};
use super::{ use super::{
options::{FontDescriptor, FontDescriptors, FontWeight, NextFontLocalOptionsVc}, options::{FontDescriptor, FontDescriptors, FontWeight, NextFontLocalOptions},
request::AdjustFontFallback, request::AdjustFontFallback,
}; };
use crate::next_font::{ use crate::next_font::{
font_fallback::{ font_fallback::{
AutomaticFontFallback, DefaultFallbackFont, FontAdjustment, FontFallback, FontFallbacksVc, AutomaticFontFallback, DefaultFallbackFont, FontAdjustment, FontFallback, FontFallbacks,
DEFAULT_SANS_SERIF_FONT, DEFAULT_SERIF_FONT, DEFAULT_SANS_SERIF_FONT, DEFAULT_SERIF_FONT,
}, },
util::{get_scoped_font_family, FontFamilyType}, util::{get_scoped_font_family, FontFamilyType},
@ -28,10 +26,10 @@ static BOLD_WEIGHT: f64 = 700.0;
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn get_font_fallbacks( pub(super) async fn get_font_fallbacks(
context: FileSystemPathVc, context: Vc<FileSystemPath>,
options_vc: NextFontLocalOptionsVc, options_vc: Vc<NextFontLocalOptions>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<FontFallbacksVc> { ) -> Result<Vc<FontFallbacks>> {
let options = &*options_vc.await?; let options = &*options_vc.await?;
let mut font_fallbacks = vec![]; let mut font_fallbacks = vec![];
let scoped_font_family = get_scoped_font_family( let scoped_font_family = get_scoped_font_family(
@ -45,7 +43,7 @@ pub(super) async fn get_font_fallbacks(
FontFallback::Automatic( FontFallback::Automatic(
AutomaticFontFallback { AutomaticFontFallback {
scoped_font_family, scoped_font_family,
local_font_family: StringVc::cell("Arial".to_owned()), local_font_family: Vc::cell("Arial".to_owned()),
adjustment: Some( adjustment: Some(
get_font_adjustment(context, options_vc, &DEFAULT_SANS_SERIF_FONT).await?, get_font_adjustment(context, options_vc, &DEFAULT_SANS_SERIF_FONT).await?,
), ),
@ -58,7 +56,7 @@ pub(super) async fn get_font_fallbacks(
FontFallback::Automatic( FontFallback::Automatic(
AutomaticFontFallback { AutomaticFontFallback {
scoped_font_family, scoped_font_family,
local_font_family: StringVc::cell("Times New Roman".to_owned()), local_font_family: Vc::cell("Times New Roman".to_owned()),
adjustment: Some( adjustment: Some(
get_font_adjustment(context, options_vc, &DEFAULT_SERIF_FONT).await?, get_font_adjustment(context, options_vc, &DEFAULT_SERIF_FONT).await?,
), ),
@ -71,20 +69,20 @@ pub(super) async fn get_font_fallbacks(
}; };
if let Some(fallback) = &options.fallback { if let Some(fallback) = &options.fallback {
font_fallbacks.push(FontFallback::Manual(StringsVc::cell(fallback.clone())).into()); font_fallbacks.push(FontFallback::Manual(Vc::cell(fallback.clone())).into());
} }
Ok(FontFallbacksVc::cell(font_fallbacks)) Ok(Vc::cell(font_fallbacks))
} }
async fn get_font_adjustment( async fn get_font_adjustment(
context: FileSystemPathVc, context: Vc<FileSystemPath>,
options: NextFontLocalOptionsVc, options: Vc<NextFontLocalOptions>,
fallback_font: &DefaultFallbackFont, fallback_font: &DefaultFallbackFont,
) -> Result<FontAdjustment> { ) -> Result<FontAdjustment> {
let options = &*options.await?; let options = &*options.await?;
let main_descriptor = pick_font_for_fallback_generation(&options.fonts)?; let main_descriptor = pick_font_for_fallback_generation(&options.fonts)?;
let font_file = &*context.join(&main_descriptor.path).read().await?; let font_file = &*context.join(main_descriptor.path.clone()).read().await?;
let font_file_rope = match font_file { let font_file_rope = match font_file {
FileContent::NotFound => bail!("Expected font file content"), FileContent::NotFound => bail!("Expected font file content"),
FileContent::Content(file) => file.content(), FileContent::Content(file) => file.content(),

View file

@ -1,37 +1,30 @@
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use indoc::formatdoc; use indoc::formatdoc;
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::{
tasks::{ tasks::Value,
primitives::{OptionStringVc, U32Vc}, tasks_fs::{json::parse_json_with_source_context, FileContent, FileSystemPath},
Value,
},
tasks_fs::{json::parse_json_with_source_context, FileContent, FileSystemPathVc},
}, },
turbopack::core::{ turbopack::core::{
asset::AssetContent,
resolve::{ resolve::{
options::{ options::{ImportMapResult, ImportMapping, ImportMappingReplacement},
ImportMapResult, ImportMapResultVc, ImportMapping, ImportMappingReplacement, parse::Request,
ImportMappingReplacementVc, ImportMappingVc, pattern::QueryMap,
},
parse::{Request, RequestVc},
pattern::QueryMapVc,
ResolveResult, ResolveResult,
}, },
virtual_source::VirtualSourceVc, virtual_source::VirtualSource,
}, },
}; };
use self::{ use self::{
font_fallback::get_font_fallbacks, font_fallback::get_font_fallbacks,
options::{options_from_request, FontDescriptors, NextFontLocalOptionsVc}, options::{options_from_request, FontDescriptors, NextFontLocalOptions},
stylesheet::build_stylesheet, stylesheet::build_stylesheet,
util::build_font_family_string, util::build_font_family_string,
}; };
use super::{ use super::{font_fallback::FontFallbacks, util::FontCssProperties};
font_fallback::FontFallbacksVc,
util::{FontCssProperties, FontCssPropertiesVc},
};
use crate::next_font::{ use crate::next_font::{
local::options::FontWeight, local::options::FontWeight,
util::{get_request_hash, get_request_id}, util::{get_request_hash, get_request_id},
@ -45,13 +38,13 @@ pub mod util;
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub(crate) struct NextFontLocalReplacer { pub(crate) struct NextFontLocalReplacer {
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFontLocalReplacerVc { impl NextFontLocalReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(project_path: FileSystemPathVc) -> Self { pub fn new(project_path: Vc<FileSystemPath>) -> Vc<Self> {
Self::cell(NextFontLocalReplacer { project_path }) Self::cell(NextFontLocalReplacer { project_path })
} }
} }
@ -59,7 +52,7 @@ impl NextFontLocalReplacerVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ImportMappingReplacement for NextFontLocalReplacer { impl ImportMappingReplacement for NextFontLocalReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
fn replace(&self, _capture: &str) -> ImportMappingVc { fn replace(&self, _capture: String) -> Vc<ImportMapping> {
ImportMapping::Ignore.into() ImportMapping::Ignore.into()
} }
@ -69,9 +62,9 @@ impl ImportMappingReplacement for NextFontLocalReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn result( async fn result(
&self, &self,
context: FileSystemPathVc, context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
) -> Result<ImportMapResultVc> { ) -> Result<Vc<ImportMapResult>> {
let Request::Module { let Request::Module {
module: _, module: _,
path: _, path: _,
@ -119,27 +112,27 @@ impl ImportMappingReplacement for NextFontLocalReplacer {
.map(|s| format!("fontStyle: \"{}\",\n", s)) .map(|s| format!("fontStyle: \"{}\",\n", s))
.unwrap_or_else(|| "".to_owned()), .unwrap_or_else(|| "".to_owned()),
); );
let js_asset = VirtualSourceVc::new( let js_asset = VirtualSource::new(
context.join(&format!( context.join(format!(
"{}.js", "{}.js",
get_request_id(options_vc.font_family(), request_hash).await? get_request_id(options_vc.font_family(), request_hash).await?
)), )),
FileContent::Content(file_content.into()).into(), AssetContent::file(FileContent::Content(file_content.into()).into()),
); );
Ok(ImportMapResult::Result(ResolveResult::asset(js_asset.into()).into()).into()) Ok(ImportMapResult::Result(ResolveResult::asset(Vc::upcast(js_asset)).into()).into())
} }
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextFontLocalCssModuleReplacer { pub struct NextFontLocalCssModuleReplacer {
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFontLocalCssModuleReplacerVc { impl NextFontLocalCssModuleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(project_path: FileSystemPathVc) -> Self { pub fn new(project_path: Vc<FileSystemPath>) -> Vc<Self> {
Self::cell(NextFontLocalCssModuleReplacer { project_path }) Self::cell(NextFontLocalCssModuleReplacer { project_path })
} }
} }
@ -147,7 +140,7 @@ impl NextFontLocalCssModuleReplacerVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ImportMappingReplacement for NextFontLocalCssModuleReplacer { impl ImportMappingReplacement for NextFontLocalCssModuleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
fn replace(&self, _capture: &str) -> ImportMappingVc { fn replace(&self, _capture: String) -> Vc<ImportMapping> {
ImportMapping::Ignore.into() ImportMapping::Ignore.into()
} }
@ -158,9 +151,9 @@ impl ImportMappingReplacement for NextFontLocalCssModuleReplacer {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn result( async fn result(
&self, &self,
context: FileSystemPathVc, context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
) -> Result<ImportMapResultVc> { ) -> Result<Vc<ImportMapResult>> {
let request = &*request.await?; let request = &*request.await?;
let Request::Module { let Request::Module {
module: _, module: _,
@ -173,7 +166,7 @@ impl ImportMappingReplacement for NextFontLocalCssModuleReplacer {
let options = font_options_from_query_map(*query_vc); let options = font_options_from_query_map(*query_vc);
let request_hash = get_request_hash(*query_vc); let request_hash = get_request_hash(*query_vc);
let css_virtual_path = context.join(&format!( let css_virtual_path = context.join(format!(
"/{}.module.css", "/{}.module.css",
get_request_id(options.font_family(), request_hash).await? get_request_id(options.font_family(), request_hash).await?
)); ));
@ -187,26 +180,26 @@ impl ImportMappingReplacement for NextFontLocalCssModuleReplacer {
) )
.await?; .await?;
let css_asset = VirtualSourceVc::new( let css_asset = VirtualSource::new(
css_virtual_path, css_virtual_path,
FileContent::Content(stylesheet.into()).into(), AssetContent::file(FileContent::Content(stylesheet.into()).into()),
); );
Ok(ImportMapResult::Result(ResolveResult::asset(css_asset.into()).into()).into()) Ok(ImportMapResult::Result(ResolveResult::asset(Vc::upcast(css_asset)).into()).into())
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get_font_css_properties( async fn get_font_css_properties(
options_vc: NextFontLocalOptionsVc, options_vc: Vc<NextFontLocalOptions>,
font_fallbacks: FontFallbacksVc, font_fallbacks: Vc<FontFallbacks>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<FontCssPropertiesVc> { ) -> Result<Vc<FontCssProperties>> {
let options = &*options_vc.await?; let options = &*options_vc.await?;
Ok(FontCssPropertiesVc::cell(FontCssProperties { Ok(FontCssProperties::cell(FontCssProperties {
font_family: build_font_family_string(options_vc, font_fallbacks, request_hash), font_family: build_font_family_string(options_vc, font_fallbacks, request_hash),
weight: OptionStringVc::cell(match &options.fonts { weight: Vc::cell(match &options.fonts {
FontDescriptors::Many(_) => None, FontDescriptors::Many(_) => None,
// When the user only provided a top-level font file, include the font weight in the // When the user only provided a top-level font file, include the font weight in the
// className selector rules // className selector rules
@ -218,18 +211,18 @@ async fn get_font_css_properties(
.filter(|w| !matches!(w, FontWeight::Variable(_, _))) .filter(|w| !matches!(w, FontWeight::Variable(_, _)))
.map(|w| w.to_string()), .map(|w| w.to_string()),
}), }),
style: OptionStringVc::cell(match &options.fonts { style: Vc::cell(match &options.fonts {
FontDescriptors::Many(_) => None, FontDescriptors::Many(_) => None,
// When the user only provided a top-level font file, include the font style in the // When the user only provided a top-level font file, include the font style in the
// className selector rules // className selector rules
FontDescriptors::One(descriptor) => descriptor.style.clone(), FontDescriptors::One(descriptor) => descriptor.style.clone(),
}), }),
variable: OptionStringVc::cell(options.variable.clone()), variable: Vc::cell(options.variable.clone()),
})) }))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn font_options_from_query_map(query: QueryMapVc) -> Result<NextFontLocalOptionsVc> { async fn font_options_from_query_map(query: Vc<QueryMap>) -> Result<Vc<NextFontLocalOptions>> {
let query_map = &*query.await?; let query_map = &*query.await?;
// These are invariants from the next/font swc transform. Regular errors instead // These are invariants from the next/font swc transform. Regular errors instead
// of Issues should be okay. // of Issues should be okay.
@ -246,5 +239,5 @@ async fn font_options_from_query_map(query: QueryMapVc) -> Result<NextFontLocalO
}; };
options_from_request(&parse_json_with_source_context(json)?) options_from_request(&parse_json_with_source_context(json)?)
.map(|o| NextFontLocalOptionsVc::new(Value::new(o))) .map(|o| NextFontLocalOptions::new(Value::new(o)))
} }

View file

@ -2,7 +2,8 @@ use std::{fmt::Display, str::FromStr};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbopack_binding::turbo::tasks::{primitives::StringVc, trace::TraceRawVcs, Value}; use turbo_tasks::Vc;
use turbopack_binding::turbo::tasks::{trace::TraceRawVcs, Value};
use super::request::{ use super::request::{
AdjustFontFallback, NextFontLocalRequest, NextFontLocalRequestArguments, SrcDescriptor, AdjustFontFallback, NextFontLocalRequest, NextFontLocalRequestArguments, SrcDescriptor,
@ -34,15 +35,15 @@ pub(super) struct NextFontLocalOptions {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFontLocalOptionsVc { impl NextFontLocalOptions {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(options: Value<NextFontLocalOptions>) -> NextFontLocalOptionsVc { pub fn new(options: Value<NextFontLocalOptions>) -> Vc<NextFontLocalOptions> {
Self::cell(options.into_value()) Self::cell(options.into_value())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn font_family(self) -> Result<StringVc> { pub async fn font_family(self: Vc<Self>) -> Result<Vc<String>> {
Ok(StringVc::cell((*self.await?.variable_name).to_owned())) Ok(Vc::cell((*self.await?.variable_name).to_owned()))
} }
} }

View file

@ -1,28 +1,28 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indoc::formatdoc; use indoc::formatdoc;
use turbopack_binding::turbo::tasks::primitives::{StringVc, U32Vc}; use turbo_tasks::Vc;
use super::options::{FontDescriptors, NextFontLocalOptionsVc}; use super::options::{FontDescriptors, NextFontLocalOptions};
use crate::next_font::{ use crate::next_font::{
font_fallback::FontFallbacksVc, font_fallback::FontFallbacks,
stylesheet::{build_fallback_definition, build_font_class_rules}, stylesheet::{build_fallback_definition, build_font_class_rules},
util::{get_scoped_font_family, FontCssPropertiesVc, FontFamilyType}, util::{get_scoped_font_family, FontCssProperties, FontFamilyType},
}; };
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn build_stylesheet( pub(super) async fn build_stylesheet(
options: NextFontLocalOptionsVc, options: Vc<NextFontLocalOptions>,
fallbacks: FontFallbacksVc, fallbacks: Vc<FontFallbacks>,
css_properties: FontCssPropertiesVc, css_properties: Vc<FontCssProperties>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
let scoped_font_family = get_scoped_font_family( let scoped_font_family = get_scoped_font_family(
FontFamilyType::WebFont.cell(), FontFamilyType::WebFont.cell(),
options.font_family(), options.font_family(),
request_hash, request_hash,
); );
Ok(StringVc::cell(formatdoc!( Ok(Vc::cell(formatdoc!(
r#" r#"
{} {}
{} {}
@ -37,9 +37,9 @@ pub(super) async fn build_stylesheet(
/// Builds a string of `@font-face` definitions for each local font file /// Builds a string of `@font-face` definitions for each local font file
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn build_font_face_definitions( pub(super) async fn build_font_face_definitions(
scoped_font_family: StringVc, scoped_font_family: Vc<String>,
options: NextFontLocalOptionsVc, options: Vc<NextFontLocalOptions>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
let options = &*options.await?; let options = &*options.await?;
let mut definitions = String::new(); let mut definitions = String::new();
@ -75,7 +75,7 @@ pub(super) async fn build_font_face_definitions(
)); ));
} }
Ok(StringVc::cell(definitions)) Ok(Vc::cell(definitions))
} }
/// Used as e.g. `format('woff')` in `src` properties in `@font-face` /// Used as e.g. `format('woff')` in `src` properties in `@font-face`

View file

@ -1,19 +1,19 @@
use anyhow::Result; use anyhow::Result;
use turbopack_binding::turbo::tasks::primitives::{StringVc, U32Vc}; use turbo_tasks::Vc;
use super::options::NextFontLocalOptionsVc; use super::options::NextFontLocalOptions;
use crate::next_font::{ use crate::next_font::{
font_fallback::{FontFallback, FontFallbacksVc}, font_fallback::{FontFallback, FontFallbacks},
util::{get_scoped_font_family, FontFamilyType}, util::{get_scoped_font_family, FontFamilyType},
}; };
/// Returns a string to be used as the `font-family` property in css. /// Returns a string to be used as the `font-family` property in css.
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn build_font_family_string( pub(super) async fn build_font_family_string(
options: NextFontLocalOptionsVc, options: Vc<NextFontLocalOptions>,
font_fallbacks: FontFallbacksVc, font_fallbacks: Vc<FontFallbacks>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
let mut font_families = vec![format!( let mut font_families = vec![format!(
"'{}'", "'{}'",
*get_scoped_font_family( *get_scoped_font_family(
@ -36,5 +36,5 @@ pub(super) async fn build_font_family_string(
} }
} }
Ok(StringVc::cell(font_families.join(", "))) Ok(Vc::cell(font_families.join(", ")))
} }

View file

@ -1,15 +1,15 @@
use anyhow::Result; use anyhow::Result;
use indoc::formatdoc; use indoc::formatdoc;
use turbopack_binding::turbo::tasks::primitives::StringVc; use turbo_tasks::Vc;
use super::{ use super::{
font_fallback::{FontFallback, FontFallbacksVc}, font_fallback::{FontFallback, FontFallbacks},
util::FontCssPropertiesVc, util::FontCssProperties,
}; };
/// Builds `@font-face` stylesheet definition for a given FontFallback /// Builds `@font-face` stylesheet definition for a given FontFallback
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) async fn build_fallback_definition(fallbacks: FontFallbacksVc) -> Result<StringVc> { pub(crate) async fn build_fallback_definition(fallbacks: Vc<FontFallbacks>) -> Result<Vc<String>> {
let mut res = "".to_owned(); let mut res = "".to_owned();
for fallback_vc in &*fallbacks.await? { for fallback_vc in &*fallbacks.await? {
if let FontFallback::Automatic(fallback) = &*fallback_vc.await? { if let FontFallback::Automatic(fallback) = &*fallback_vc.await? {
@ -46,13 +46,13 @@ pub(crate) async fn build_fallback_definition(fallbacks: FontFallbacksVc) -> Res
} }
} }
Ok(StringVc::cell(res)) Ok(Vc::cell(res))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub(super) async fn build_font_class_rules( pub(super) async fn build_font_class_rules(
css_properties: FontCssPropertiesVc, css_properties: Vc<FontCssProperties>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
let css_properties = &*css_properties.await?; let css_properties = &*css_properties.await?;
let font_family_string = &*css_properties.font_family.await?; let font_family_string = &*css_properties.font_family.await?;
@ -90,7 +90,7 @@ pub(super) async fn build_font_class_rules(
)) ))
} }
Ok(StringVc::cell(rules)) Ok(Vc::cell(rules))
} }
fn format_fixed_percentage(value: f64) -> String { fn format_fixed_percentage(value: f64) -> String {

View file

@ -1,7 +1,7 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use turbo_tasks::primitives::{OptionStringVc, StringVc, U32Vc}; use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_hash::hash_xxh3_hash64, turbopack::core::resolve::pattern::QueryMapVc, turbo::tasks_hash::hash_xxh3_hash64, turbopack::core::resolve::pattern::QueryMap,
}; };
/// CSS properties and values for a given font variation. These are rendered as /// CSS properties and values for a given font variation. These are rendered as
@ -9,17 +9,17 @@ use turbopack_binding::{
/// module. /// module.
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub(crate) struct FontCssProperties { pub(crate) struct FontCssProperties {
pub font_family: StringVc, pub font_family: Vc<String>,
pub weight: OptionStringVc, pub weight: Vc<Option<String>>,
pub style: OptionStringVc, pub style: Vc<Option<String>>,
pub variable: OptionStringVc, pub variable: Vc<Option<String>>,
} }
/// A hash of the requested querymap derived from how the user invoked /// A hash of the requested querymap derived from how the user invoked
/// next/font. Used to uniquely identify font requests for generated filenames /// next/font. Used to uniquely identify font requests for generated filenames
/// and scoped font family names. /// and scoped font family names.
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) async fn get_request_hash(query_vc: QueryMapVc) -> Result<U32Vc> { pub(crate) async fn get_request_hash(query_vc: Vc<QueryMap>) -> Result<Vc<u32>> {
let query = &*query_vc.await?; let query = &*query_vc.await?;
let query = query.as_ref().context("Query map must be present")?; let query = query.as_ref().context("Query map must be present")?;
let mut to_hash = vec![]; let mut to_hash = vec![];
@ -28,7 +28,7 @@ pub(crate) async fn get_request_hash(query_vc: QueryMapVc) -> Result<U32Vc> {
to_hash.push(v); to_hash.push(v);
} }
Ok(U32Vc::cell( Ok(Vc::cell(
// Truncate the hash to u32. These hashes are ultimately displayed as 6- or 8-character // Truncate the hash to u32. These hashes are ultimately displayed as 6- or 8-character
// hexadecimal values. // hexadecimal values.
hash_xxh3_hash64(to_hash) as u32, hash_xxh3_hash64(to_hash) as u32,
@ -48,10 +48,10 @@ pub(crate) enum FontFamilyType {
/// * `request_hash` - The hash value of the font request /// * `request_hash` - The hash value of the font request
#[turbo_tasks::function] #[turbo_tasks::function]
pub(crate) async fn get_scoped_font_family( pub(crate) async fn get_scoped_font_family(
ty: FontFamilyTypeVc, ty: Vc<FontFamilyType>,
font_family_name: StringVc, font_family_name: Vc<String>,
request_hash: U32Vc, request_hash: Vc<u32>,
) -> Result<StringVc> { ) -> Result<Vc<String>> {
let hash = { let hash = {
let mut hash = format!("{:x?}", request_hash.await?); let mut hash = format!("{:x?}", request_hash.await?);
hash.truncate(6); hash.truncate(6);
@ -64,13 +64,13 @@ pub(crate) async fn get_scoped_font_family(
FontFamilyType::Fallback => format!("{}_Fallback", font_family_base), FontFamilyType::Fallback => format!("{}_Fallback", font_family_base),
}; };
Ok(StringVc::cell(format!("__{}_{}", font_family_name, hash))) Ok(Vc::cell(format!("__{}_{}", font_family_name, hash)))
} }
/// Returns a [[StringVc]] uniquely identifying the request for the font. /// Returns a [[Vc<String>]] uniquely identifying the request for the font.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_request_id(font_family: StringVc, request_hash: U32Vc) -> Result<StringVc> { pub async fn get_request_id(font_family: Vc<String>, request_hash: Vc<u32>) -> Result<Vc<String>> {
Ok(StringVc::cell(format!( Ok(Vc::cell(format!(
"{}_{:x?}", "{}_{:x?}",
font_family.await?.to_lowercase().replace(' ', "_"), font_family.await?.to_lowercase().replace(' ', "_"),
request_hash.await? request_hash.await?

View file

@ -1,24 +1,17 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks::{Value, Vc};
use turbo_tasks_fs::FileSystem; use turbo_tasks_fs::FileSystem;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::AssetContent, asset::AssetContent, ident::AssetIdent, introspect::Introspectable,
ident::AssetIdentVc, server_fs::ServerFileSystem, version::VersionedContent,
introspect::{Introspectable, IntrospectableVc},
server_fs::ServerFileSystemVc,
version::VersionedContent,
}, },
dev_server::source::{ dev_server::source::{
query::QueryValue, query::QueryValue,
route_tree::{RouteTreeVc, RouteType}, route_tree::{RouteTree, RouteType},
wrapping_source::{ wrapping_source::{ContentSourceProcessor, WrappedGetContentSourceContent},
ContentSourceProcessor, ContentSourceProcessorVc, WrappedGetContentSourceContentVc, ContentSource, ContentSourceContent, ContentSourceData, ContentSourceDataFilter,
}, ContentSourceDataVary, GetContentSourceContent, ProxyResult, RewriteBuilder,
ContentSource, ContentSourceContent, ContentSourceContentVc, ContentSourceData,
ContentSourceDataFilter, ContentSourceDataVary, ContentSourceDataVaryVc, ContentSourceVc,
GetContentSourceContent, GetContentSourceContentVc, GetContentSourceContentsVc,
ProxyResult, RewriteBuilder,
}, },
image::process::optimize, image::process::optimize,
}; };
@ -27,13 +20,13 @@ use turbopack_binding::turbopack::{
/// next/image. /// next/image.
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextImageContentSource { pub struct NextImageContentSource {
asset_source: ContentSourceVc, asset_source: Vc<Box<dyn ContentSource>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextImageContentSourceVc { impl NextImageContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(asset_source: ContentSourceVc) -> NextImageContentSourceVc { pub fn new(asset_source: Vc<Box<dyn ContentSource>>) -> Vc<NextImageContentSource> {
NextImageContentSource { asset_source }.cell() NextImageContentSource { asset_source }.cell()
} }
} }
@ -41,15 +34,15 @@ impl NextImageContentSourceVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ContentSource for NextImageContentSource { impl ContentSource for NextImageContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_routes(self_vc: NextImageContentSourceVc) -> RouteTreeVc { fn get_routes(self: Vc<Self>) -> Vc<RouteTree> {
RouteTreeVc::new_route(Vec::new(), RouteType::Exact, self_vc.into()) RouteTree::new_route(Vec::new(), RouteType::Exact, Vc::upcast(self))
} }
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl GetContentSourceContent for NextImageContentSource { impl GetContentSourceContent for NextImageContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn vary(&self) -> ContentSourceDataVaryVc { async fn vary(&self) -> Vc<ContentSourceDataVary> {
ContentSourceDataVary { ContentSourceDataVary {
query: Some(ContentSourceDataFilter::Subset( query: Some(ContentSourceDataFilter::Subset(
["url".to_string(), "w".to_string(), "q".to_string()].into(), ["url".to_string(), "w".to_string(), "q".to_string()].into(),
@ -61,11 +54,11 @@ impl GetContentSourceContent for NextImageContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn get( async fn get(
self_vc: NextImageContentSourceVc, self: Vc<Self>,
_path: &str, _path: String,
data: Value<ContentSourceData>, data: Value<ContentSourceData>,
) -> Result<ContentSourceContentVc> { ) -> Result<Vc<ContentSourceContent>> {
let this = self_vc.await?; let this = self.await?;
let Some(query) = &data.query else { let Some(query) = &data.query else {
bail!("missing query"); bail!("missing query");
@ -99,18 +92,17 @@ impl GetContentSourceContent for NextImageContentSource {
// TODO: re-encode into next-gen formats. // TODO: re-encode into next-gen formats.
if let Some(path) = url.strip_prefix('/') { if let Some(path) = url.strip_prefix('/') {
let sources = this.asset_source.get_routes().get(path).await?; let sources = this.asset_source.get_routes().get(path.to_string()).await?;
let sources = sources let sources = sources
.iter() .iter()
.map(|s| { .map(|s| {
WrappedGetContentSourceContentVc::new( Vc::upcast(WrappedGetContentSourceContent::new(
*s, *s,
NextImageContentSourceProcessorVc::new(path.to_string(), w, q).into(), Vc::upcast(NextImageContentSourceProcessor::new(path.to_string(), w, q)),
) ))
.into()
}) })
.collect(); .collect();
let sources = GetContentSourceContentsVc::cell(sources); let sources = Vc::cell(sources);
return Ok( return Ok(
ContentSourceContent::Rewrite(RewriteBuilder::new_sources(sources).build()).cell(), ContentSourceContent::Rewrite(RewriteBuilder::new_sources(sources).build()).cell(),
); );
@ -132,13 +124,13 @@ impl GetContentSourceContent for NextImageContentSource {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Introspectable for NextImageContentSource { impl Introspectable for NextImageContentSource {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ty(&self) -> StringVc { fn ty(&self) -> Vc<String> {
StringVc::cell("next image content source".to_string()) Vc::cell("next image content source".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn details(&self) -> StringVc { fn details(&self) -> Vc<String> {
StringVc::cell("supports dynamic serving of any statically imported image".to_string()) Vc::cell("supports dynamic serving of any statically imported image".to_string())
} }
} }
@ -150,9 +142,9 @@ struct NextImageContentSourceProcessor {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextImageContentSourceProcessorVc { impl NextImageContentSourceProcessor {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(path: String, width: u32, quality: u8) -> NextImageContentSourceProcessorVc { pub fn new(path: String, width: u32, quality: u8) -> Vc<NextImageContentSourceProcessor> {
NextImageContentSourceProcessor { NextImageContentSourceProcessor {
path, path,
width, width,
@ -165,7 +157,7 @@ impl NextImageContentSourceProcessorVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ContentSourceProcessor for NextImageContentSourceProcessor { impl ContentSourceProcessor for NextImageContentSourceProcessor {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process(&self, content: ContentSourceContentVc) -> Result<ContentSourceContentVc> { async fn process(&self, content: Vc<ContentSourceContent>) -> Result<Vc<ContentSourceContent>> {
let ContentSourceContent::Static(static_content) = *content.await? else { let ContentSourceContent::Static(static_content) = *content.await? else {
return Ok(content); return Ok(content);
}; };
@ -175,13 +167,13 @@ impl ContentSourceProcessor for NextImageContentSourceProcessor {
return Ok(content); return Ok(content);
}; };
let optimized_file_content = optimize( let optimized_file_content = optimize(
AssetIdentVc::from_path(ServerFileSystemVc::new().root().join(&self.path)), AssetIdent::from_path(ServerFileSystem::new().root().join(self.path.clone())),
file_content, file_content,
self.width, self.width,
u32::MAX, u32::MAX,
self.quality, self.quality,
); );
Ok(ContentSourceContentVc::static_content( Ok(ContentSourceContent::static_content(
AssetContent::File(optimized_file_content).into(), AssetContent::File(optimized_file_content).into(),
)) ))
} }

View file

@ -2,5 +2,5 @@ pub(crate) mod content_source;
pub(crate) mod module; pub(crate) mod module;
pub(crate) mod source_asset; pub(crate) mod source_asset;
pub use content_source::NextImageContentSourceVc; pub use content_source::NextImageContentSource;
pub use module::StructuredImageModuleTypeVc; pub use module::StructuredImageModuleType;

View file

@ -1,20 +1,14 @@
use anyhow::Result;
use indexmap::indexmap; use indexmap::indexmap;
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks::Value, turbo::tasks::Value,
turbopack::{ turbopack::{
core::{ core::{
context::AssetContext, context::AssetContext, module::Module, reference_type::ReferenceType,
module::ModuleVc, resolve::ModulePart, source::Source,
reference_type::{InnerAssetsVc, ReferenceType},
resolve::ModulePartVc,
source::SourceVc,
},
r#static::StaticModuleAssetVc,
turbopack::{
module_options::{CustomModuleType, CustomModuleTypeVc},
ModuleAssetContextVc,
}, },
r#static::StaticModuleAsset,
turbopack::{module_options::CustomModuleType, ModuleAssetContext},
}, },
}; };
@ -45,30 +39,31 @@ pub struct StructuredImageModuleType {
impl StructuredImageModuleType { impl StructuredImageModuleType {
pub(crate) fn create_module( pub(crate) fn create_module(
source: SourceVc, source: Vc<Box<dyn Source>>,
blur_placeholder_mode: BlurPlaceholderMode, blur_placeholder_mode: BlurPlaceholderMode,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
) -> ModuleVc { ) -> Vc<Box<dyn Module>> {
let static_asset = StaticModuleAssetVc::new(source, context.into()); let static_asset = StaticModuleAsset::new(source, Vc::upcast(context));
context.process( context.process(
StructuredImageFileSource { Vc::upcast(
image: source, StructuredImageFileSource {
blur_placeholder_mode, image: source,
} blur_placeholder_mode,
.cell() }
.into(), .cell(),
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(indexmap!( ),
"IMAGE".to_string() => static_asset.into() Value::new(ReferenceType::Internal(Vc::cell(indexmap!(
"IMAGE".to_string() => Vc::upcast(static_asset)
)))), )))),
) )
} }
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl StructuredImageModuleTypeVc { impl StructuredImageModuleType {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(blur_placeholder_mode: Value<BlurPlaceholderMode>) -> Self { pub fn new(blur_placeholder_mode: Value<BlurPlaceholderMode>) -> Vc<Self> {
StructuredImageModuleTypeVc::cell(StructuredImageModuleType { StructuredImageModuleType::cell(StructuredImageModuleType {
blur_placeholder_mode: blur_placeholder_mode.into_value(), blur_placeholder_mode: blur_placeholder_mode.into_value(),
}) })
} }
@ -79,10 +74,10 @@ impl CustomModuleType for StructuredImageModuleType {
#[turbo_tasks::function] #[turbo_tasks::function]
fn create_module( fn create_module(
&self, &self,
source: SourceVc, source: Vc<Box<dyn Source>>,
context: ModuleAssetContextVc, context: Vc<ModuleAssetContext>,
_part: Option<ModulePartVc>, _part: Option<Vc<ModulePart>>,
) -> ModuleVc { ) -> Vc<Box<dyn Module>> {
StructuredImageModuleType::create_module(source, self.blur_placeholder_mode, context) StructuredImageModuleType::create_module(source, self.blur_placeholder_mode, context)
} }
} }

View file

@ -1,30 +1,28 @@
use std::io::Write; use std::io::Write;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::{ turbo::tasks_fs::{rope::RopeBuilder, FileContent},
tasks::primitives::StringVc,
tasks_fs::{rope::RopeBuilder, FileContent},
},
turbopack::{ turbopack::{
core::{ core::{
asset::{Asset, AssetContent, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
ident::AssetIdentVc, ident::AssetIdent,
source::{Source, SourceVc}, source::Source,
}, },
ecmascript::utils::StringifyJs, ecmascript::utils::StringifyJs,
image::process::{get_meta_data, BlurPlaceholderOptions, BlurPlaceholderOptionsVc}, image::process::{get_meta_data, BlurPlaceholderOptions},
}, },
}; };
use super::module::BlurPlaceholderMode; use super::module::BlurPlaceholderMode;
fn modifier() -> StringVc { fn modifier() -> Vc<String> {
StringVc::cell("structured image object".to_string()) Vc::cell("structured image object".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn blur_options() -> BlurPlaceholderOptionsVc { fn blur_options() -> Vc<BlurPlaceholderOptions> {
BlurPlaceholderOptions { BlurPlaceholderOptions {
quality: 70, quality: 70,
size: 8, size: 8,
@ -36,7 +34,7 @@ fn blur_options() -> BlurPlaceholderOptionsVc {
/// an object with meta information like width, height and a blur placeholder. /// an object with meta information like width, height and a blur placeholder.
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct StructuredImageFileSource { pub struct StructuredImageFileSource {
pub image: SourceVc, pub image: Vc<Box<dyn Source>>,
pub blur_placeholder_mode: BlurPlaceholderMode, pub blur_placeholder_mode: BlurPlaceholderMode,
} }
@ -46,15 +44,15 @@ impl Source for StructuredImageFileSource {}
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for StructuredImageFileSource { impl Asset for StructuredImageFileSource {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.image self.image
.ident() .ident()
.with_modifier(modifier()) .with_modifier(modifier())
.rename_as("*.mjs") .rename_as("*.mjs".to_string())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn content(&self) -> Result<AssetContentVc> { async fn content(&self) -> Result<Vc<AssetContent>> {
let content = self.image.content().await?; let content = self.image.content().await?;
let AssetContent::File(content) = *content else { let AssetContent::File(content) = *content else {
bail!("Input source is not a file and can't be transformed into image information"); bail!("Input source is not a file and can't be transformed into image information");

View file

@ -1,23 +1,20 @@
use std::collections::{BTreeMap, HashMap}; use std::collections::{BTreeMap, HashMap};
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use turbo_tasks::Value; use turbo_tasks::{Value, Vc};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{glob::GlobVc, FileSystem, FileSystemPathVc}, turbo::tasks_fs::{glob::Glob, FileSystem, FileSystemPath},
turbopack::{ turbopack::{
core::{ core::{
asset::Asset, asset::Asset,
resolve::{ resolve::{
options::{ options::{ConditionValue, ImportMap, ImportMapping, ResolveOptions, ResolvedMap},
ConditionValue, ImportMap, ImportMapVc, ImportMapping, ImportMappingVc, parse::Request,
ResolveOptionsVc, ResolvedMap, ResolvedMapVc,
},
parse::RequestVc,
pattern::Pattern, pattern::Pattern,
resolve, AliasPattern, ResolveAliasMapVc, SubpathValue, resolve, AliasPattern, ResolveAliasMap, SubpathValue,
}, },
}, },
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::{resolve_options, resolve_options_context::ResolveOptionsContext}, turbopack::{resolve_options, resolve_options_context::ResolveOptionsContext},
}, },
}; };
@ -26,10 +23,10 @@ use crate::{
embed_js::{next_js_fs, VIRTUAL_PACKAGE_NAME}, embed_js::{next_js_fs, VIRTUAL_PACKAGE_NAME},
mode::NextMode, mode::NextMode,
next_client::context::ClientContextType, next_client::context::ClientContextType,
next_config::NextConfigVc, next_config::NextConfig,
next_font::{ next_font::{
google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc}, google::{NextFontGoogleCssModuleReplacer, NextFontGoogleReplacer},
local::{NextFontLocalCssModuleReplacerVc, NextFontLocalReplacerVc}, local::{NextFontLocalCssModuleReplacer, NextFontLocalReplacer},
}, },
next_server::context::ServerContextType, next_server::context::ServerContextType,
}; };
@ -38,11 +35,11 @@ use crate::{
/// Computes the Next-specific client import map. /// Computes the Next-specific client import map.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_next_client_import_map( pub async fn get_next_client_import_map(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
ty: Value<ClientContextType>, ty: Value<ClientContextType>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<ImportMapVc> { ) -> Result<Vc<ImportMap>> {
let mut import_map = ImportMap::empty(); let mut import_map = ImportMap::empty();
insert_next_shared_aliases( insert_next_shared_aliases(
@ -139,7 +136,7 @@ pub async fn get_next_client_import_map(
/// Computes the Next-specific client import map. /// Computes the Next-specific client import map.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_next_build_import_map() -> ImportMapVc { pub fn get_next_build_import_map() -> Vc<ImportMap> {
let mut import_map = ImportMap::empty(); let mut import_map = ImportMap::empty();
insert_package_alias( insert_package_alias(
@ -161,7 +158,7 @@ pub fn get_next_build_import_map() -> ImportMapVc {
/// Computes the Next-specific client fallback import map, which provides /// Computes the Next-specific client fallback import map, which provides
/// polyfills to Node.js externals. /// polyfills to Node.js externals.
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_next_client_fallback_import_map(ty: Value<ClientContextType>) -> ImportMapVc { pub fn get_next_client_fallback_import_map(ty: Value<ClientContextType>) -> Vc<ImportMap> {
let mut import_map = ImportMap::empty(); let mut import_map = ImportMap::empty();
match ty.into_value() { match ty.into_value() {
@ -188,12 +185,12 @@ pub fn get_next_client_fallback_import_map(ty: Value<ClientContextType>) -> Impo
/// Computes the Next-specific server-side import map. /// Computes the Next-specific server-side import map.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_next_server_import_map( pub async fn get_next_server_import_map(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
ty: Value<ServerContextType>, ty: Value<ServerContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<ImportMapVc> { ) -> Result<Vc<ImportMap>> {
let mut import_map = ImportMap::empty(); let mut import_map = ImportMap::empty();
insert_next_shared_aliases( insert_next_shared_aliases(
@ -253,12 +250,12 @@ pub async fn get_next_server_import_map(
/// Computes the Next-specific edge-side import map. /// Computes the Next-specific edge-side import map.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_next_edge_import_map( pub async fn get_next_edge_import_map(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
ty: Value<ServerContextType>, ty: Value<ServerContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<ImportMapVc> { ) -> Result<Vc<ImportMap>> {
let mut import_map = ImportMap::empty(); let mut import_map = ImportMap::empty();
insert_next_shared_aliases( insert_next_shared_aliases(
@ -302,14 +299,17 @@ pub async fn get_next_edge_import_map(
} }
pub fn get_next_client_resolved_map( pub fn get_next_client_resolved_map(
context: FileSystemPathVc, context: Vc<FileSystemPath>,
root: FileSystemPathVc, root: Vc<FileSystemPath>,
) -> ResolvedMapVc { ) -> Vc<ResolvedMap> {
let glob_mappings = vec![ let glob_mappings = vec![
// Temporary hack to replace the hot reloader until this is passable by props in next.js // Temporary hack to replace the hot reloader until this is passable by props in next.js
( (
context.root(), context.root(),
GlobVc::new("**/next/dist/client/components/react-dev-overlay/hot-reloader-client.js"), Glob::new(
"**/next/dist/client/components/react-dev-overlay/hot-reloader-client.js"
.to_string(),
),
ImportMapping::PrimaryAlternative( ImportMapping::PrimaryAlternative(
"@vercel/turbopack-next/dev/hot-reloader.tsx".to_string(), "@vercel/turbopack-next/dev/hot-reloader.tsx".to_string(),
Some(root), Some(root),
@ -515,9 +515,9 @@ pub fn mdx_import_source_file() -> String {
// Make sure to not add any external requests here. // Make sure to not add any external requests here.
pub async fn insert_next_shared_aliases( pub async fn insert_next_shared_aliases(
import_map: &mut ImportMap, import_map: &mut ImportMap,
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<()> { ) -> Result<()> {
let package_root = next_js_fs().root(); let package_root = next_js_fs().root();
@ -549,38 +549,42 @@ pub async fn insert_next_shared_aliases(
import_map.insert_alias( import_map.insert_alias(
// Request path from js via next-font swc transform // Request path from js via next-font swc transform
AliasPattern::exact("next/font/google/target.css"), AliasPattern::exact("next/font/google/target.css"),
ImportMapping::Dynamic(NextFontGoogleReplacerVc::new(project_path).into()).into(), ImportMapping::Dynamic(Vc::upcast(NextFontGoogleReplacer::new(project_path))).into(),
); );
import_map.insert_alias( import_map.insert_alias(
// Request path from js via next-font swc transform // Request path from js via next-font swc transform
AliasPattern::exact("@next/font/google/target.css"), AliasPattern::exact("@next/font/google/target.css"),
ImportMapping::Dynamic(NextFontGoogleReplacerVc::new(project_path).into()).into(), ImportMapping::Dynamic(Vc::upcast(NextFontGoogleReplacer::new(project_path))).into(),
); );
import_map.insert_alias( import_map.insert_alias(
AliasPattern::exact("@vercel/turbopack-next/internal/font/google/cssmodule.module.css"), AliasPattern::exact("@vercel/turbopack-next/internal/font/google/cssmodule.module.css"),
ImportMapping::Dynamic( ImportMapping::Dynamic(Vc::upcast(NextFontGoogleCssModuleReplacer::new(
NextFontGoogleCssModuleReplacerVc::new(project_path, execution_context).into(), project_path,
) execution_context,
)))
.into(), .into(),
); );
import_map.insert_alias( import_map.insert_alias(
// Request path from js via next-font swc transform // Request path from js via next-font swc transform
AliasPattern::exact("next/font/local/target.css"), AliasPattern::exact("next/font/local/target.css"),
ImportMapping::Dynamic(NextFontLocalReplacerVc::new(project_path).into()).into(), ImportMapping::Dynamic(Vc::upcast(NextFontLocalReplacer::new(project_path))).into(),
); );
import_map.insert_alias( import_map.insert_alias(
// Request path from js via next-font swc transform // Request path from js via next-font swc transform
AliasPattern::exact("@next/font/local/target.css"), AliasPattern::exact("@next/font/local/target.css"),
ImportMapping::Dynamic(NextFontLocalReplacerVc::new(project_path).into()).into(), ImportMapping::Dynamic(Vc::upcast(NextFontLocalReplacer::new(project_path))).into(),
); );
import_map.insert_alias( import_map.insert_alias(
AliasPattern::exact("@vercel/turbopack-next/internal/font/local/cssmodule.module.css"), AliasPattern::exact("@vercel/turbopack-next/internal/font/local/cssmodule.module.css"),
ImportMapping::Dynamic(NextFontLocalCssModuleReplacerVc::new(project_path).into()).into(), ImportMapping::Dynamic(Vc::upcast(NextFontLocalCssModuleReplacer::new(
project_path,
)))
.into(),
); );
import_map.insert_singleton_alias("@swc/helpers", get_next_package(project_path)); import_map.insert_singleton_alias("@swc/helpers", get_next_package(project_path));
@ -601,8 +605,8 @@ pub async fn insert_next_shared_aliases(
#[turbo_tasks::function] #[turbo_tasks::function]
async fn package_lookup_resolve_options( async fn package_lookup_resolve_options(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
) -> Result<ResolveOptionsVc> { ) -> Result<Vc<ResolveOptions>> {
Ok(resolve_options( Ok(resolve_options(
project_path, project_path,
ResolveOptionsContext { ResolveOptionsContext {
@ -616,10 +620,10 @@ async fn package_lookup_resolve_options(
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_next_package(project_path: FileSystemPathVc) -> Result<FileSystemPathVc> { pub async fn get_next_package(project_path: Vc<FileSystemPath>) -> Result<Vc<FileSystemPath>> {
let result = resolve( let result = resolve(
project_path, project_path,
RequestVc::parse(Value::new(Pattern::Constant( Request::parse(Value::new(Pattern::Constant(
"next/package.json".to_string(), "next/package.json".to_string(),
))), ))),
package_lookup_resolve_options(project_path), package_lookup_resolve_options(project_path),
@ -631,8 +635,8 @@ pub async fn get_next_package(project_path: FileSystemPathVc) -> Result<FileSyst
pub async fn insert_alias_option<const N: usize>( pub async fn insert_alias_option<const N: usize>(
import_map: &mut ImportMap, import_map: &mut ImportMap,
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
alias_options: ResolveAliasMapVc, alias_options: Vc<ResolveAliasMap>,
conditions: [&'static str; N], conditions: [&'static str; N],
) -> Result<()> { ) -> Result<()> {
let conditions = BTreeMap::from(conditions.map(|c| (c.to_string(), ConditionValue::Set))); let conditions = BTreeMap::from(conditions.map(|c| (c.to_string(), ConditionValue::Set)));
@ -647,8 +651,8 @@ pub async fn insert_alias_option<const N: usize>(
fn export_value_to_import_mapping( fn export_value_to_import_mapping(
value: &SubpathValue, value: &SubpathValue,
conditions: &BTreeMap<String, ConditionValue>, conditions: &BTreeMap<String, ConditionValue>,
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
) -> Option<ImportMappingVc> { ) -> Option<Vc<ImportMapping>> {
let mut result = Vec::new(); let mut result = Vec::new();
value.add_results( value.add_results(
conditions, conditions,
@ -679,13 +683,17 @@ fn export_value_to_import_mapping(
fn insert_alias_to_alternatives<'a>( fn insert_alias_to_alternatives<'a>(
import_map: &mut ImportMap, import_map: &mut ImportMap,
alias: impl Into<String> + 'a, alias: impl Into<String> + 'a,
alternatives: Vec<ImportMappingVc>, alternatives: Vec<Vc<ImportMapping>>,
) { ) {
import_map.insert_exact_alias(alias, ImportMapping::Alternatives(alternatives).into()); import_map.insert_exact_alias(alias, ImportMapping::Alternatives(alternatives).into());
} }
/// Inserts an alias to an import mapping into an import map. /// Inserts an alias to an import mapping into an import map.
fn insert_package_alias(import_map: &mut ImportMap, prefix: &str, package_root: FileSystemPathVc) { fn insert_package_alias(
import_map: &mut ImportMap,
prefix: &str,
package_root: Vc<FileSystemPath>,
) {
import_map.insert_wildcard_alias( import_map.insert_wildcard_alias(
prefix, prefix,
ImportMapping::PrimaryAlternative("./*".to_string(), Some(package_root)).cell(), ImportMapping::PrimaryAlternative("./*".to_string(), Some(package_root)).cell(),
@ -703,12 +711,12 @@ fn insert_turbopack_dev_alias(import_map: &mut ImportMap) {
/// Creates a direct import mapping to the result of resolving a request /// Creates a direct import mapping to the result of resolving a request
/// in a context. /// in a context.
fn request_to_import_mapping(context_path: FileSystemPathVc, request: &str) -> ImportMappingVc { fn request_to_import_mapping(context_path: Vc<FileSystemPath>, request: &str) -> Vc<ImportMapping> {
ImportMapping::PrimaryAlternative(request.to_string(), Some(context_path)).cell() ImportMapping::PrimaryAlternative(request.to_string(), Some(context_path)).cell()
} }
/// Creates a direct import mapping to the result of resolving an external /// Creates a direct import mapping to the result of resolving an external
/// request. /// request.
fn external_request_to_import_mapping(request: &str) -> ImportMappingVc { fn external_request_to_import_mapping(request: &str) -> Vc<ImportMapping> {
ImportMapping::External(Some(request.to_string())).into() ImportMapping::External(Some(request.to_string())).into()
} }

View file

@ -1,18 +1,15 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbopack_binding::{ use turbopack_binding::turbopack::node::route_matcher::{Params, RouteMatcherRef};
turbo::tasks::primitives::BoolVc,
turbopack::node::route_matcher::{ParamsVc, RouteMatcher},
};
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct AllMatch; pub struct AllMatch;
impl RouteMatcher for AllMatch { impl RouteMatcherRef for AllMatch {
fn matches(&self, _path: &str) -> BoolVc { fn matches(&self, _path: &str) -> bool {
BoolVc::cell(true) true
} }
fn params(&self, _path: &str) -> ParamsVc { fn params(&self, _path: &str) -> Params {
ParamsVc::cell(Some(Default::default())) Params(Some(Default::default()))
} }
} }

View file

@ -1,8 +1,6 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbopack_binding::{ use turbo_tasks::Vc;
turbo::tasks::primitives::{BoolVc, StringVc}, use turbopack_binding::turbopack::node::route_matcher::{Params, RouteMatcher, RouteMatcherRef};
turbopack::node::route_matcher::{ParamsVc, RouteMatcher, RouteMatcherVc},
};
use self::{ use self::{
all::AllMatch, all::AllMatch,
@ -17,13 +15,13 @@ mod prefix_suffix;
/// A route matcher that matches a path against an exact route. /// A route matcher that matches a path against an exact route.
#[turbo_tasks::value] #[turbo_tasks::value]
pub(crate) struct NextExactMatcher { pub(crate) struct NextExactMatcher {
path: StringVc, path: Vc<String>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextExactMatcherVc { impl NextExactMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn new(path: StringVc) -> Result<Self> { pub async fn new(path: Vc<String>) -> Result<Vc<Self>> {
Ok(Self::cell(NextExactMatcher { path })) Ok(Self::cell(NextExactMatcher { path }))
} }
} }
@ -31,13 +29,13 @@ impl NextExactMatcherVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl RouteMatcher for NextExactMatcher { impl RouteMatcher for NextExactMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn matches(&self, path: &str) -> Result<BoolVc> { async fn matches(&self, path: String) -> Result<Vc<bool>> {
Ok(BoolVc::cell(path == *self.path.await?)) Ok(Vc::cell(path == *self.path.await?))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn params(&self, path: &str) -> Result<ParamsVc> { async fn params(&self, path: String) -> Result<Vc<Params>> {
Ok(ParamsVc::cell(if path == *self.path.await? { Ok(Vc::cell(if path == *self.path.await? {
Some(Default::default()) Some(Default::default())
} else { } else {
None None
@ -53,9 +51,9 @@ pub(crate) struct NextParamsMatcher {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextParamsMatcherVc { impl NextParamsMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn new(path: StringVc) -> Result<Self> { pub async fn new(path: Vc<String>) -> Result<Vc<Self>> {
Ok(Self::cell(NextParamsMatcher { Ok(Self::cell(NextParamsMatcher {
matcher: build_path_regex(path.await?.as_str())?, matcher: build_path_regex(path.await?.as_str())?,
})) }))
@ -65,13 +63,13 @@ impl NextParamsMatcherVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl RouteMatcher for NextParamsMatcher { impl RouteMatcher for NextParamsMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
fn matches(&self, path: &str) -> BoolVc { fn matches(&self, path: String) -> Vc<bool> {
self.matcher.matches(path) Vc::cell(self.matcher.matches(&path))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn params(&self, path: &str) -> ParamsVc { fn params(&self, path: String) -> Vc<Params> {
self.matcher.params(path) Params::cell(self.matcher.params(&path))
} }
} }
@ -84,11 +82,11 @@ pub(crate) struct NextPrefixSuffixParamsMatcher {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextPrefixSuffixParamsMatcherVc { impl NextPrefixSuffixParamsMatcher {
/// Converts a filename within the server root into a regular expression /// Converts a filename within the server root into a regular expression
/// with named capture groups for every dynamic segment. /// with named capture groups for every dynamic segment.
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn new(path: StringVc, prefix: &str, suffix: &str) -> Result<Self> { pub async fn new(path: Vc<String>, prefix: String, suffix: String) -> Result<Vc<Self>> {
Ok(Self::cell(NextPrefixSuffixParamsMatcher { Ok(Self::cell(NextPrefixSuffixParamsMatcher {
matcher: PrefixSuffixMatcher::new( matcher: PrefixSuffixMatcher::new(
prefix.to_string(), prefix.to_string(),
@ -102,13 +100,13 @@ impl NextPrefixSuffixParamsMatcherVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl RouteMatcher for NextPrefixSuffixParamsMatcher { impl RouteMatcher for NextPrefixSuffixParamsMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
fn matches(&self, path: &str) -> BoolVc { fn matches(&self, path: String) -> Vc<bool> {
self.matcher.matches(path) Vc::cell(self.matcher.matches(&path))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn params(&self, path: &str) -> ParamsVc { fn params(&self, path: String) -> Vc<Params> {
self.matcher.params(path) Params::cell(self.matcher.params(&path))
} }
} }
@ -120,9 +118,9 @@ pub(crate) struct NextFallbackMatcher {
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextFallbackMatcherVc { impl NextFallbackMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new() -> Self { pub fn new() -> Vc<Self> {
Self::cell(NextFallbackMatcher { matcher: AllMatch }) Self::cell(NextFallbackMatcher { matcher: AllMatch })
} }
} }
@ -130,13 +128,13 @@ impl NextFallbackMatcherVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl RouteMatcher for NextFallbackMatcher { impl RouteMatcher for NextFallbackMatcher {
#[turbo_tasks::function] #[turbo_tasks::function]
fn matches(&self, path: &str) -> BoolVc { fn matches(&self, path: String) -> Vc<bool> {
self.matcher.matches(path) Vc::cell(self.matcher.matches(&path))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn params(&self, path: &str) -> ParamsVc { fn params(&self, path: String) -> Vc<Params> {
self.matcher.params(path) Params::cell(self.matcher.params(&path))
} }
} }

View file

@ -1,8 +1,8 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks::primitives::{BoolVc, Regex}, turbo::tasks::primitives::Regex,
turbopack::node::route_matcher::{Param, ParamsVc, RouteMatcher}, turbopack::node::route_matcher::{Param, Params, RouteMatcherRef},
}; };
/// A regular expression that matches a path, with named capture groups for the /// A regular expression that matches a path, with named capture groups for the
@ -31,13 +31,13 @@ impl std::fmt::Display for PathRegex {
} }
} }
impl RouteMatcher for PathRegex { impl RouteMatcherRef for PathRegex {
fn matches(&self, path: &str) -> BoolVc { fn matches(&self, path: &str) -> bool {
BoolVc::cell(self.regex.is_match(path)) self.regex.is_match(path)
} }
fn params(&self, path: &str) -> ParamsVc { fn params(&self, path: &str) -> Params {
ParamsVc::cell(self.regex.captures(path).map(|capture| { Params(self.regex.captures(path).map(|capture| {
self.named_params self.named_params
.iter() .iter()
.enumerate() .enumerate()

View file

@ -1,15 +1,12 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use turbopack_binding::{ use turbopack_binding::turbopack::node::route_matcher::{Params, RouteMatcherRef};
turbo::tasks::primitives::BoolVc,
turbopack::node::route_matcher::{ParamsVc, RouteMatcher},
};
/// A composite route matcher that matches a path if it has a given prefix and /// A composite route matcher that matches a path if it has a given prefix and
/// suffix. /// suffix.
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq)] #[derive(Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct PrefixSuffixMatcher<T> pub struct PrefixSuffixMatcher<T>
where where
T: RouteMatcher, T: RouteMatcherRef,
{ {
prefix: String, prefix: String,
suffix: String, suffix: String,
@ -18,7 +15,7 @@ where
impl<T> PrefixSuffixMatcher<T> impl<T> PrefixSuffixMatcher<T>
where where
T: RouteMatcher, T: RouteMatcherRef,
{ {
/// Creates a new [PrefixSuffixMatcher]. /// Creates a new [PrefixSuffixMatcher].
pub fn new(prefix: String, suffix: String, inner: T) -> Self { pub fn new(prefix: String, suffix: String, inner: T) -> Self {
@ -35,23 +32,23 @@ where
} }
} }
impl<T> RouteMatcher for PrefixSuffixMatcher<T> impl<T> RouteMatcherRef for PrefixSuffixMatcher<T>
where where
T: RouteMatcher, T: RouteMatcherRef,
{ {
fn matches(&self, path: &str) -> BoolVc { fn matches(&self, path: &str) -> bool {
if let Some(path) = self.strip_prefix_and_suffix(path) { if let Some(path) = self.strip_prefix_and_suffix(path) {
self.inner.matches(path) self.inner.matches(path)
} else { } else {
BoolVc::cell(false) false
} }
} }
fn params(&self, path: &str) -> ParamsVc { fn params(&self, path: &str) -> Params {
if let Some(path) = self.strip_prefix_and_suffix(path) { if let Some(path) = self.strip_prefix_and_suffix(path) {
self.inner.params(path) self.inner.params(path)
} else { } else {
ParamsVc::cell(None) Params(None)
} }
} }
} }

View file

@ -1,42 +1,38 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks::{Value, Vc};
use turbo_tasks_fs::FileSystem; use turbo_tasks_fs::FileSystem;
use turbopack_binding::{ use turbopack_binding::{
turbo::{tasks_env::ProcessEnvVc, tasks_fs::FileSystemPathVc}, turbo::{tasks_env::ProcessEnv, tasks_fs::FileSystemPath},
turbopack::{ turbopack::{
build::BuildChunkingContextVc, build::BuildChunkingContext,
core::{ core::{
compile_time_defines, compile_time_defines,
compile_time_info::{ compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReferences},
CompileTimeDefines, CompileTimeDefinesVc, CompileTimeInfo, CompileTimeInfoVc, environment::{Environment, ExecutionEnvironment, NodeJsEnvironment, ServerAddr},
FreeVarReferencesVc,
},
environment::{EnvironmentVc, ExecutionEnvironment, NodeJsEnvironmentVc, ServerAddrVc},
free_var_references, free_var_references,
resolve::{parse::RequestVc, pattern::Pattern}, resolve::{parse::Request, pattern::Pattern},
}, },
ecmascript::TransformPluginVc, ecmascript::TransformPlugin,
ecmascript_plugin::transform::directives::{ ecmascript_plugin::transform::directives::{
client::ClientDirectiveTransformer, server::ServerDirectiveTransformer, client::ClientDirectiveTransformer, server::ServerDirectiveTransformer,
}, },
env::ProcessEnvAssetVc, env::ProcessEnvAsset,
node::execution_context::ExecutionContextVc, node::execution_context::ExecutionContext,
turbopack::{ turbopack::{
condition::ContextCondition, condition::ContextCondition,
module_options::{ module_options::{
CustomEcmascriptTransformPlugins, CustomEcmascriptTransformPluginsVc, CustomEcmascriptTransformPlugins, JsxTransformOptions, MdxTransformModuleOptions,
JsxTransformOptions, MdxTransformModuleOptions, ModuleOptionsContext, ModuleOptionsContext, PostCssTransformOptions, TypescriptTransformOptions,
ModuleOptionsContextVc, PostCssTransformOptions, TypescriptTransformOptions,
WebpackLoadersOptions, WebpackLoadersOptions,
}, },
resolve_options_context::{ResolveOptionsContext, ResolveOptionsContextVc}, resolve_options_context::ResolveOptionsContext,
transition::TransitionVc, transition::Transition,
}, },
}, },
}; };
use super::{ use super::{
resolve::ExternalCjsModulesResolvePluginVc, resolve::ExternalCjsModulesResolvePlugin,
transforms::{get_next_server_internal_transforms_rules, get_next_server_transforms_rules}, transforms::{get_next_server_internal_transforms_rules, get_next_server_transforms_rules},
}; };
use crate::{ use crate::{
@ -45,12 +41,12 @@ use crate::{
env::env_for_js, env::env_for_js,
mode::NextMode, mode::NextMode,
next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping}, next_build::{get_external_next_compiled_package_mapping, get_postcss_package_mapping},
next_client::{RuntimeEntriesVc, RuntimeEntry}, next_client::{RuntimeEntries, RuntimeEntry},
next_config::NextConfigVc, next_config::NextConfig,
next_import_map::{get_next_server_import_map, mdx_import_source_file}, next_import_map::{get_next_server_import_map, mdx_import_source_file},
next_server::resolve::ExternalPredicate, next_server::resolve::ExternalPredicate,
next_shared::{ next_shared::{
resolve::UnsupportedModulesResolvePluginVc, resolve::UnsupportedModulesResolvePlugin,
transforms::{ transforms::{
emotion::get_emotion_transform_plugin, get_relay_transform_plugin, emotion::get_emotion_transform_plugin, get_relay_transform_plugin,
styled_components::get_styled_components_transform_plugin, styled_components::get_styled_components_transform_plugin,
@ -70,46 +66,46 @@ use crate::{
#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)] #[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord)]
pub enum ServerContextType { pub enum ServerContextType {
Pages { Pages {
pages_dir: FileSystemPathVc, pages_dir: Vc<FileSystemPath>,
}, },
PagesData { PagesData {
pages_dir: FileSystemPathVc, pages_dir: Vc<FileSystemPath>,
}, },
AppSSR { AppSSR {
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
}, },
AppRSC { AppRSC {
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
ecmascript_client_reference_transition_name: Option<StringVc>, ecmascript_client_reference_transition_name: Option<Vc<String>>,
client_transition: Option<TransitionVc>, client_transition: Option<Vc<Box<dyn Transition>>>,
}, },
AppRoute { AppRoute {
app_dir: FileSystemPathVc, app_dir: Vc<FileSystemPath>,
}, },
Middleware, Middleware,
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_server_resolve_options_context( pub async fn get_server_resolve_options_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
ty: Value<ServerContextType>, ty: Value<ServerContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
) -> Result<ResolveOptionsContextVc> { ) -> Result<Vc<ResolveOptionsContext>> {
let next_server_import_map = let next_server_import_map =
get_next_server_import_map(project_path, ty, mode, next_config, execution_context); get_next_server_import_map(project_path, ty, mode, next_config, execution_context);
let foreign_code_context_condition = foreign_code_context_condition(next_config).await?; let foreign_code_context_condition = foreign_code_context_condition(next_config).await?;
let root_dir = project_path.root().resolve().await?; let root_dir = project_path.root().resolve().await?;
let unsupported_modules_resolve_plugin = UnsupportedModulesResolvePluginVc::new(project_path); let unsupported_modules_resolve_plugin = UnsupportedModulesResolvePlugin::new(project_path);
let server_component_externals_plugin = ExternalCjsModulesResolvePluginVc::new( let server_component_externals_plugin = ExternalCjsModulesResolvePlugin::new(
project_path, project_path,
ExternalPredicate::Only(next_config.server_component_externals()).cell(), ExternalPredicate::Only(next_config.server_component_externals()).cell(),
); );
Ok(match ty.into_value() { Ok(match ty.into_value() {
ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => {
let external_cjs_modules_plugin = ExternalCjsModulesResolvePluginVc::new( let external_cjs_modules_plugin = ExternalCjsModulesResolvePlugin::new(
project_path, project_path,
ExternalPredicate::AllExcept(next_config.transpile_packages()).cell(), ExternalPredicate::AllExcept(next_config.transpile_packages()).cell(),
); );
@ -122,8 +118,8 @@ pub async fn get_server_resolve_options_context(
custom_conditions: vec![mode.node_env().to_string(), "node".to_string()], custom_conditions: vec![mode.node_env().to_string(), "node".to_string()],
import_map: Some(next_server_import_map), import_map: Some(next_server_import_map),
plugins: vec![ plugins: vec![
external_cjs_modules_plugin.into(), Vc::upcast(external_cjs_modules_plugin),
unsupported_modules_resolve_plugin.into(), Vc::upcast(unsupported_modules_resolve_plugin),
], ],
..Default::default() ..Default::default()
}; };
@ -150,8 +146,8 @@ pub async fn get_server_resolve_options_context(
], ],
import_map: Some(next_server_import_map), import_map: Some(next_server_import_map),
plugins: vec![ plugins: vec![
server_component_externals_plugin.into(), Vc::upcast(server_component_externals_plugin),
unsupported_modules_resolve_plugin.into(), Vc::upcast(unsupported_modules_resolve_plugin),
], ],
..Default::default() ..Default::default()
}; };
@ -179,8 +175,8 @@ pub async fn get_server_resolve_options_context(
], ],
import_map: Some(next_server_import_map), import_map: Some(next_server_import_map),
plugins: vec![ plugins: vec![
server_component_externals_plugin.into(), Vc::upcast(server_component_externals_plugin),
unsupported_modules_resolve_plugin.into(), Vc::upcast(unsupported_modules_resolve_plugin),
], ],
..Default::default() ..Default::default()
}; };
@ -201,8 +197,8 @@ pub async fn get_server_resolve_options_context(
custom_conditions: vec![mode.node_env().to_string(), "node".to_string()], custom_conditions: vec![mode.node_env().to_string(), "node".to_string()],
import_map: Some(next_server_import_map), import_map: Some(next_server_import_map),
plugins: vec![ plugins: vec![
server_component_externals_plugin.into(), Vc::upcast(server_component_externals_plugin),
unsupported_modules_resolve_plugin.into(), Vc::upcast(unsupported_modules_resolve_plugin),
], ],
..Default::default() ..Default::default()
}; };
@ -222,7 +218,7 @@ pub async fn get_server_resolve_options_context(
enable_node_externals: true, enable_node_externals: true,
module: true, module: true,
custom_conditions: vec![mode.node_env().to_string()], custom_conditions: vec![mode.node_env().to_string()],
plugins: vec![unsupported_modules_resolve_plugin.into()], plugins: vec![Vc::upcast(unsupported_modules_resolve_plugin)],
..Default::default() ..Default::default()
}; };
ResolveOptionsContext { ResolveOptionsContext {
@ -251,23 +247,23 @@ fn defines(mode: NextMode) -> CompileTimeDefines {
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn next_server_defines(mode: NextMode) -> CompileTimeDefinesVc { fn next_server_defines(mode: NextMode) -> Vc<CompileTimeDefines> {
defines(mode).cell() defines(mode).cell()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn next_server_free_vars(mode: NextMode) -> Result<FreeVarReferencesVc> { async fn next_server_free_vars(mode: NextMode) -> Result<Vc<FreeVarReferences>> {
Ok(free_var_references!(..defines(mode).into_iter()).cell()) Ok(free_var_references!(..defines(mode).into_iter()).cell())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_server_compile_time_info( pub fn get_server_compile_time_info(
mode: NextMode, mode: NextMode,
process_env: ProcessEnvVc, process_env: Vc<Box<dyn ProcessEnv>>,
server_addr: ServerAddrVc, server_addr: Vc<ServerAddr>,
) -> CompileTimeInfoVc { ) -> Vc<CompileTimeInfo> {
CompileTimeInfo::builder(EnvironmentVc::new(Value::new( CompileTimeInfo::builder(Environment::new(Value::new(
ExecutionEnvironment::NodeJsLambda(NodeJsEnvironmentVc::current(process_env, server_addr)), ExecutionEnvironment::NodeJsLambda(NodeJsEnvironment::current(process_env, server_addr)),
))) )))
.defines(next_server_defines(mode)) .defines(next_server_defines(mode))
.free_var_references(next_server_free_vars(mode)) .free_var_references(next_server_free_vars(mode))
@ -276,12 +272,12 @@ pub fn get_server_compile_time_info(
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn get_server_module_options_context( pub async fn get_server_module_options_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
execution_context: ExecutionContextVc, execution_context: Vc<ExecutionContext>,
ty: Value<ServerContextType>, ty: Value<ServerContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> Result<ModuleOptionsContextVc> { ) -> Result<Vc<ModuleOptionsContext>> {
let custom_rules = get_next_server_transforms_rules(next_config, ty.into_value(), mode).await?; 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()).await?;
@ -297,9 +293,9 @@ pub async fn get_server_module_options_context(
let enable_webpack_loaders = webpack_rules.map(|rules| { let enable_webpack_loaders = webpack_rules.map(|rules| {
WebpackLoadersOptions { WebpackLoadersOptions {
rules, rules,
loader_runner_package: Some(get_external_next_compiled_package_mapping( loader_runner_package: Some(get_external_next_compiled_package_mapping(Vc::cell(
StringVc::cell("loader-runner".to_owned()), "loader-runner".to_owned(),
)), ))),
} }
.cell() .cell()
}); });
@ -308,13 +304,12 @@ pub async fn get_server_module_options_context(
let styled_components_transform_plugin = let styled_components_transform_plugin =
*get_styled_components_transform_plugin(next_config).await?; *get_styled_components_transform_plugin(next_config).await?;
let styled_jsx_transform_plugin = *get_styled_jsx_transform_plugin().await?; let styled_jsx_transform_plugin = *get_styled_jsx_transform_plugin().await?;
let server_directive_transform_plugin = Some(TransformPluginVc::cell(Box::new( let server_directive_transform_plugin =
ServerDirectiveTransformer::new( Some(Vc::cell(Box::new(ServerDirectiveTransformer::new(
// ServerDirective is not implemented yet and always reports an issue. // ServerDirective is not implemented yet and always reports an issue.
// We don't have to pass a valid transition name yet, but the API is prepared. // We don't have to pass a valid transition name yet, but the API is prepared.
&StringVc::cell("TODO".to_string()), &Vc::cell("TODO".to_string()),
), )) as _));
)));
// ModuleOptionsContext related options // ModuleOptionsContext related options
let tsconfig = get_typescript_transform_options(project_path); let tsconfig = get_typescript_transform_options(project_path);
@ -331,7 +326,7 @@ pub async fn get_server_module_options_context(
}; };
let jsx_runtime_options = get_jsx_transform_options(project_path, mode, None); let jsx_runtime_options = get_jsx_transform_options(project_path, mode, None);
let source_transforms: Vec<TransformPluginVc> = vec![ let source_transforms: Vec<Vc<TransformPlugin>> = vec![
*get_swc_ecma_transform_plugin(project_path, next_config).await?, *get_swc_ecma_transform_plugin(project_path, next_config).await?,
*get_relay_transform_plugin(next_config).await?, *get_relay_transform_plugin(next_config).await?,
*get_emotion_transform_plugin(next_config).await?, *get_emotion_transform_plugin(next_config).await?,
@ -342,7 +337,7 @@ pub async fn get_server_module_options_context(
let output_transforms = vec![]; let output_transforms = vec![];
let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: source_transforms.clone(), source_transforms: source_transforms.clone(),
output_transforms: output_transforms.clone(), output_transforms: output_transforms.clone(),
@ -351,7 +346,7 @@ pub async fn get_server_module_options_context(
let module_options_context = match ty.into_value() { let module_options_context = match ty.into_value() {
ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => { ServerContextType::Pages { .. } | ServerContextType::PagesData { .. } => {
let mut base_source_transforms: Vec<TransformPluginVc> = vec![ let mut base_source_transforms: Vec<Vc<TransformPlugin>> = vec![
styled_components_transform_plugin, styled_components_transform_plugin,
styled_jsx_transform_plugin, styled_jsx_transform_plugin,
] ]
@ -361,7 +356,7 @@ pub async fn get_server_module_options_context(
base_source_transforms.extend(source_transforms); base_source_transforms.extend(source_transforms);
let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: base_source_transforms, source_transforms: base_source_transforms,
output_transforms, output_transforms,
@ -403,7 +398,7 @@ pub async fn get_server_module_options_context(
} }
} }
ServerContextType::AppSSR { .. } => { ServerContextType::AppSSR { .. } => {
let mut base_source_transforms: Vec<TransformPluginVc> = vec![ let mut base_source_transforms: Vec<Vc<TransformPlugin>> = vec![
styled_components_transform_plugin, styled_components_transform_plugin,
styled_jsx_transform_plugin, styled_jsx_transform_plugin,
server_directive_transform_plugin, server_directive_transform_plugin,
@ -412,7 +407,7 @@ pub async fn get_server_module_options_context(
.flatten() .flatten()
.collect(); .collect();
let base_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let base_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: base_source_transforms.clone(), source_transforms: base_source_transforms.clone(),
output_transforms: vec![], output_transforms: vec![],
@ -421,7 +416,7 @@ pub async fn get_server_module_options_context(
base_source_transforms.extend(source_transforms); base_source_transforms.extend(source_transforms);
let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: base_source_transforms, source_transforms: base_source_transforms,
output_transforms, output_transforms,
@ -465,7 +460,7 @@ pub async fn get_server_module_options_context(
ecmascript_client_reference_transition_name, ecmascript_client_reference_transition_name,
.. ..
} => { } => {
let mut base_source_transforms: Vec<TransformPluginVc> = vec![ let mut base_source_transforms: Vec<Vc<TransformPlugin>> = vec![
styled_components_transform_plugin, styled_components_transform_plugin,
server_directive_transform_plugin, server_directive_transform_plugin,
] ]
@ -476,12 +471,12 @@ pub async fn get_server_module_options_context(
if let Some(ecmascript_client_reference_transition_name) = if let Some(ecmascript_client_reference_transition_name) =
ecmascript_client_reference_transition_name ecmascript_client_reference_transition_name
{ {
base_source_transforms.push(TransformPluginVc::cell(Box::new( base_source_transforms.push(Vc::cell(Box::new(ClientDirectiveTransformer::new(
ClientDirectiveTransformer::new(ecmascript_client_reference_transition_name), ecmascript_client_reference_transition_name,
))); )) as _));
} }
let base_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let base_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: base_source_transforms.clone(), source_transforms: base_source_transforms.clone(),
output_transforms: vec![], output_transforms: vec![],
@ -490,7 +485,7 @@ pub async fn get_server_module_options_context(
base_source_transforms.extend(source_transforms); base_source_transforms.extend(source_transforms);
let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: base_source_transforms, source_transforms: base_source_transforms,
output_transforms, output_transforms,
@ -561,7 +556,7 @@ pub async fn get_server_module_options_context(
} }
} }
ServerContextType::Middleware => { ServerContextType::Middleware => {
let mut base_source_transforms: Vec<TransformPluginVc> = vec![ let mut base_source_transforms: Vec<Vc<TransformPlugin>> = vec![
styled_components_transform_plugin, styled_components_transform_plugin,
styled_jsx_transform_plugin, styled_jsx_transform_plugin,
] ]
@ -571,7 +566,7 @@ pub async fn get_server_module_options_context(
base_source_transforms.extend(source_transforms); base_source_transforms.extend(source_transforms);
let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPluginsVc::cell( let custom_ecma_transform_plugins = Some(CustomEcmascriptTransformPlugins::cell(
CustomEcmascriptTransformPlugins { CustomEcmascriptTransformPlugins {
source_transforms: base_source_transforms, source_transforms: base_source_transforms,
output_transforms, output_transforms,
@ -616,7 +611,7 @@ pub async fn get_server_module_options_context(
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_build_module_options_context() -> ModuleOptionsContextVc { pub fn get_build_module_options_context() -> Vc<ModuleOptionsContext> {
ModuleOptionsContext { ModuleOptionsContext {
enable_typescript_transform: Some(Default::default()), enable_typescript_transform: Some(Default::default()),
..Default::default() ..Default::default()
@ -626,15 +621,16 @@ pub fn get_build_module_options_context() -> ModuleOptionsContextVc {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_server_runtime_entries( pub fn get_server_runtime_entries(
project_root: FileSystemPathVc, project_root: Vc<FileSystemPath>,
env: ProcessEnvVc, env: Vc<Box<dyn ProcessEnv>>,
ty: Value<ServerContextType>, ty: Value<ServerContextType>,
mode: NextMode, mode: NextMode,
next_config: NextConfigVc, next_config: Vc<NextConfig>,
) -> RuntimeEntriesVc { ) -> Vc<RuntimeEntries> {
let mut runtime_entries = vec![RuntimeEntry::Source( let mut runtime_entries = vec![RuntimeEntry::Source(Vc::upcast(ProcessEnvAsset::new(
ProcessEnvAssetVc::new(project_root, env_for_js(env, false, next_config)).into(), project_root,
) env_for_js(env, false, next_config),
)))
.cell()]; .cell()];
match mode { match mode {
@ -643,10 +639,10 @@ pub fn get_server_runtime_entries(
if let ServerContextType::AppRSC { .. } = ty.into_value() { if let ServerContextType::AppRSC { .. } = ty.into_value() {
runtime_entries.push( runtime_entries.push(
RuntimeEntry::Request( RuntimeEntry::Request(
RequestVc::parse(Value::new(Pattern::Constant( Request::parse(Value::new(Pattern::Constant(
"./build/server/app-bootstrap.ts".to_string(), "./build/server/app-bootstrap.ts".to_string(),
))), ))),
next_js_fs().root().join("_"), next_js_fs().root().join("_".to_string()),
) )
.cell(), .cell(),
); );
@ -654,26 +650,26 @@ pub fn get_server_runtime_entries(
} }
} }
RuntimeEntriesVc::cell(runtime_entries) Vc::cell(runtime_entries)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn get_server_chunking_context( pub fn get_server_chunking_context(
project_path: FileSystemPathVc, project_path: Vc<FileSystemPath>,
node_root: FileSystemPathVc, node_root: Vc<FileSystemPath>,
// TODO(alexkirsz) Is this even necessary? Are assets not always on the client chunking context // TODO(alexkirsz) Is this even necessary? Are assets not always on the client chunking context
// anyway? // anyway?
client_root: FileSystemPathVc, client_root: Vc<FileSystemPath>,
environment: EnvironmentVc, environment: Vc<Environment>,
) -> BuildChunkingContextVc { ) -> Vc<BuildChunkingContext> {
// TODO(alexkirsz) This should return a trait that can be implemented by the // TODO(alexkirsz) This should return a trait that can be implemented by the
// different server chunking contexts. OR the build chunking context should // different server chunking contexts. OR the build chunking context should
// support both production and development modes. // support both production and development modes.
BuildChunkingContextVc::builder( BuildChunkingContext::builder(
project_path, project_path,
node_root, node_root,
node_root.join("server/chunks"), node_root.join("server/chunks".to_string()),
client_root.join("static/media"), client_root.join("static/media".to_string()),
environment, environment,
) )
.build() .build()

View file

@ -1,19 +1,19 @@
use anyhow::Result; use anyhow::Result;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use regex::Regex; use regex::Regex;
use turbo_tasks::primitives::{BoolVc, StringsVc}; use turbo_tasks::Vc;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::{glob::GlobVc, FileJsonContent, FileSystemPathVc}, turbo::tasks_fs::{glob::Glob, FileJsonContent, FileSystemPath},
turbopack::core::{ turbopack::core::{
asset::Asset, asset::Asset,
resolve::{ resolve::{
find_context_file, find_context_file,
node::node_cjs_resolve_options, node::node_cjs_resolve_options,
package_json, package_json,
parse::{Request, RequestVc}, parse::Request,
plugin::{ResolvePlugin, ResolvePluginConditionVc, ResolvePluginVc}, plugin::{ResolvePlugin, ResolvePluginCondition},
resolve, FindContextFileResult, PrimaryResolveResult, ResolveResult, resolve, FindContextFileResult, PrimaryResolveResult, ResolveResult,
ResolveResultOptionVc, ResolveResultOption,
}, },
}, },
}; };
@ -23,9 +23,9 @@ use turbopack_binding::{
#[turbo_tasks::value(into = "shared")] #[turbo_tasks::value(into = "shared")]
pub enum ExternalPredicate { pub enum ExternalPredicate {
/// Mark all modules as external if they're not listed in the list. /// Mark all modules as external if they're not listed in the list.
AllExcept(StringsVc), AllExcept(Vc<Vec<String>>),
/// Only mark modules listed as external. /// Only mark modules listed as external.
Only(StringsVc), Only(Vc<Vec<String>>),
} }
/// Mark modules as external, so they're resolved at runtime instead of bundled. /// Mark modules as external, so they're resolved at runtime instead of bundled.
@ -34,65 +34,65 @@ pub enum ExternalPredicate {
/// possible to resolve them at runtime. /// possible to resolve them at runtime.
#[turbo_tasks::value] #[turbo_tasks::value]
pub(crate) struct ExternalCjsModulesResolvePlugin { pub(crate) struct ExternalCjsModulesResolvePlugin {
root: FileSystemPathVc, root: Vc<FileSystemPath>,
predicate: ExternalPredicateVc, predicate: Vc<ExternalPredicate>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ExternalCjsModulesResolvePluginVc { impl ExternalCjsModulesResolvePlugin {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(root: FileSystemPathVc, predicate: ExternalPredicateVc) -> Self { pub fn new(root: Vc<FileSystemPath>, predicate: Vc<ExternalPredicate>) -> Vc<Self> {
ExternalCjsModulesResolvePlugin { root, predicate }.cell() ExternalCjsModulesResolvePlugin { root, predicate }.cell()
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn is_node_resolveable( async fn is_node_resolveable(
context: FileSystemPathVc, context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
expected: FileSystemPathVc, expected: Vc<FileSystemPath>,
) -> Result<BoolVc> { ) -> Result<Vc<bool>> {
let node_resolve_result = resolve(context, request, node_cjs_resolve_options(context.root())); let node_resolve_result = resolve(context, request, node_cjs_resolve_options(context.root()));
let primary_node_assets = node_resolve_result.primary_assets().await?; let primary_node_assets = node_resolve_result.primary_assets().await?;
let Some(node_asset) = primary_node_assets.first() else { let Some(node_asset) = primary_node_assets.first() else {
// can't resolve request with node.js options // can't resolve request with node.js options
return Ok(BoolVc::cell(false)); return Ok(Vc::cell(false));
}; };
if node_asset.ident().path().resolve().await? != expected.resolve().await? { if node_asset.ident().path().resolve().await? != expected.resolve().await? {
// node.js resolves to a different file // node.js resolves to a different file
return Ok(BoolVc::cell(false)); return Ok(Vc::cell(false));
} }
Ok(BoolVc::cell(true)) Ok(Vc::cell(true))
} }
static PNPM: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?:/|^)node_modules/(.pnpm/.+)").unwrap()); static PNPM: Lazy<Regex> = Lazy::new(|| Regex::new(r"(?:/|^)node_modules/(.pnpm/.+)").unwrap());
#[turbo_tasks::function] #[turbo_tasks::function]
fn condition(root: FileSystemPathVc) -> ResolvePluginConditionVc { fn condition(root: Vc<FileSystemPath>) -> Vc<ResolvePluginCondition> {
ResolvePluginConditionVc::new(root.root(), GlobVc::new("**/node_modules/**")) ResolvePluginCondition::new(root.root(), Glob::new("**/node_modules/**".to_string()))
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ResolvePlugin for ExternalCjsModulesResolvePlugin { impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
#[turbo_tasks::function] #[turbo_tasks::function]
fn after_resolve_condition(&self) -> ResolvePluginConditionVc { fn after_resolve_condition(&self) -> Vc<ResolvePluginCondition> {
condition(self.root) condition(self.root)
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn after_resolve( async fn after_resolve(
&self, &self,
fs_path: FileSystemPathVc, fs_path: Vc<FileSystemPath>,
context: FileSystemPathVc, context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
) -> Result<ResolveResultOptionVc> { ) -> Result<Vc<ResolveResultOption>> {
if *condition(self.root).matches(context).await? { if *condition(self.root).matches(context).await? {
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
} }
if !matches!(&*request.await?, Request::Module { .. }) { if !matches!(&*request.await?, Request::Module { .. }) {
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
} }
let raw_fs_path = &*fs_path.await?; let raw_fs_path = &*fs_path.await?;
@ -103,14 +103,14 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
let exception_glob = packages_glob(*exceptions).await?; let exception_glob = packages_glob(*exceptions).await?;
if exception_glob.execute(&raw_fs_path.path) { if exception_glob.execute(&raw_fs_path.path) {
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
} }
} }
ExternalPredicate::Only(externals) => { ExternalPredicate::Only(externals) => {
let external_glob = packages_glob(*externals).await?; let external_glob = packages_glob(*externals).await?;
if !external_glob.execute(&raw_fs_path.path) { if !external_glob.execute(&raw_fs_path.path) {
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
} }
} }
} }
@ -118,33 +118,33 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
// node.js only supports these file extensions // node.js only supports these file extensions
// mjs is an esm module and we can't bundle that yet // mjs is an esm module and we can't bundle that yet
if !matches!( if !matches!(
raw_fs_path.extension(), raw_fs_path.extension_ref(),
Some("cjs" | "js" | "node" | "json") Some("cjs" | "js" | "node" | "json")
) { ) {
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
} }
let FindContextFileResult::Found(package_json, _) = let FindContextFileResult::Found(package_json, _) =
*find_context_file(fs_path.parent(), package_json()).await? *find_context_file(fs_path.parent(), package_json()).await?
else { else {
// can't find package.json // can't find package.json
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
}; };
let FileJsonContent::Content(package) = &*package_json.read_json().await? else { let FileJsonContent::Content(package) = &*package_json.read_json().await? else {
// can't parse package.json // can't parse package.json
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
}; };
// always bundle esm modules // always bundle esm modules
if let Some("module") = package["type"].as_str() { if let Some("module") = package["type"].as_str() {
return Ok(ResolveResultOptionVc::none()); return Ok(ResolveResultOption::none());
} }
// check if we can resolve the package from the project dir with node.js resolve // check if we can resolve the package from the project dir with node.js resolve
// options (might be hidden by pnpm) // options (might be hidden by pnpm)
if *is_node_resolveable(self.root.root(), request, fs_path).await? { if *is_node_resolveable(self.root.root(), request, fs_path).await? {
// mark as external // mark as external
return Ok(ResolveResultOptionVc::some( return Ok(ResolveResultOption::some(
ResolveResult::primary(PrimaryResolveResult::OriginalReferenceExternal).cell(), ResolveResult::primary(PrimaryResolveResult::OriginalReferenceExternal).cell(),
)); ));
} }
@ -161,7 +161,7 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
// options, to come here like the `module` field in package.json // options, to come here like the `module` field in package.json
if *is_node_resolveable(context, request, fs_path).await? { if *is_node_resolveable(context, request, fs_path).await? {
// mark as external // mark as external
return Ok(ResolveResultOptionVc::some( return Ok(ResolveResultOption::some(
ResolveResult::primary( ResolveResult::primary(
PrimaryResolveResult::OriginalReferenceTypeExternal( PrimaryResolveResult::OriginalReferenceTypeExternal(
import_path.as_str().to_string(), import_path.as_str().to_string(),
@ -172,13 +172,13 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
} }
} }
} }
Ok(ResolveResultOptionVc::none()) Ok(ResolveResultOption::none())
} }
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn packages_glob(packages: StringsVc) -> Result<GlobVc> { async fn packages_glob(packages: Vc<Vec<String>>) -> Result<Vc<Glob>> {
Ok(GlobVc::new(&format!( Ok(Glob::new(format!(
"**/node_modules/{{{}}}/**", "**/node_modules/{{{}}}/**",
packages.await?.join(",") packages.await?.join(",")
))) )))

View file

@ -1,11 +1,12 @@
use anyhow::Result; use anyhow::Result;
use next_transform_strip_page_exports::ExportFilter; use next_transform_strip_page_exports::ExportFilter;
use turbo_tasks::Vc;
use turbopack_binding::turbopack::turbopack::module_options::ModuleRule; use turbopack_binding::turbopack::turbopack::module_options::ModuleRule;
use crate::{ use crate::{
mode::NextMode, mode::NextMode,
next_client_reference::css_client_reference::css_client_reference_rule::get_next_css_client_reference_transforms_rule, next_client_reference::css_client_reference::css_client_reference_rule::get_next_css_client_reference_transforms_rule,
next_config::NextConfigVc, next_config::NextConfig,
next_server::context::ServerContextType, next_server::context::ServerContextType,
next_shared::transforms::{ next_shared::transforms::{
get_next_dynamic_transform_rule, get_next_font_transform_rule, get_next_image_rule, get_next_dynamic_transform_rule, get_next_font_transform_rule, get_next_image_rule,
@ -16,7 +17,7 @@ use crate::{
/// Returns a list of module rules which apply server-side, Next.js-specific /// Returns a list of module rules which apply server-side, Next.js-specific
/// transforms. /// transforms.
pub async fn get_next_server_transforms_rules( pub async fn get_next_server_transforms_rules(
next_config: NextConfigVc, next_config: Vc<NextConfig>,
context_ty: ServerContextType, context_ty: ServerContextType,
mode: NextMode, mode: NextMode,
) -> Result<Vec<ModuleRule>> { ) -> Result<Vec<ModuleRule>> {

View file

@ -2,4 +2,4 @@ pub(crate) mod server_component_module;
pub(crate) mod server_component_reference; pub(crate) mod server_component_reference;
pub(crate) mod server_component_transition; pub(crate) mod server_component_transition;
pub use server_component_transition::NextServerComponentTransitionVc; pub use server_component_transition::NextServerComponentTransition;

View file

@ -1,50 +1,49 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use indoc::formatdoc; use indoc::formatdoc;
use turbo_tasks::{primitives::StringVc, Value}; use turbo_tasks::{Value, Vc};
use turbo_tasks_fs::FileSystemPathVc; use turbo_tasks_fs::FileSystemPath;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::{ core::{
asset::{Asset, AssetContentVc, AssetVc}, asset::{Asset, AssetContent},
chunk::{ chunk::{
availability_info::AvailabilityInfo, ChunkItem, ChunkItemVc, ChunkVc, ChunkableModule, availability_info::AvailabilityInfo, Chunk, ChunkItem, ChunkableModule, ChunkingContext,
ChunkableModuleVc, ChunkingContextVc,
}, },
ident::AssetIdentVc, ident::AssetIdent,
module::{Module, ModuleVc}, module::Module,
reference::{AssetReferenceVc, AssetReferencesVc}, reference::{AssetReference, AssetReferences},
}, },
ecmascript::chunk::EcmascriptChunkItemExt,
turbopack::ecmascript::{ turbopack::ecmascript::{
chunk::{ chunk::{
EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemContentVc, EcmascriptChunk, EcmascriptChunkItem, EcmascriptChunkItemContent,
EcmascriptChunkItemVc, EcmascriptChunkPlaceable, EcmascriptChunkPlaceableVc, EcmascriptChunkPlaceable, EcmascriptChunkingContext, EcmascriptExports,
EcmascriptChunkVc, EcmascriptChunkingContextVc, EcmascriptExports, EcmascriptExportsVc,
}, },
utils::StringifyJs, utils::StringifyJs,
}, },
}; };
use super::server_component_reference::NextServerComponentModuleReferenceVc; use super::server_component_reference::NextServerComponentModuleReference;
#[turbo_tasks::function] #[turbo_tasks::function]
fn modifier() -> StringVc { fn modifier() -> Vc<String> {
StringVc::cell("Next.js server component".to_string()) Vc::cell("Next.js server component".to_string())
} }
#[turbo_tasks::value(shared)] #[turbo_tasks::value(shared)]
pub struct NextServerComponentModule { pub struct NextServerComponentModule {
module: EcmascriptChunkPlaceableVc, module: Vc<Box<dyn EcmascriptChunkPlaceable>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextServerComponentModuleVc { impl NextServerComponentModule {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(module: EcmascriptChunkPlaceableVc) -> Self { pub fn new(module: Vc<Box<dyn EcmascriptChunkPlaceable>>) -> Vc<Self> {
NextServerComponentModule { module }.cell() NextServerComponentModule { module }.cell()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
pub async fn server_path(self_vc: NextServerComponentModuleVc) -> Result<FileSystemPathVc> { pub async fn server_path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
let this = self_vc.await?; let this = self.await?;
Ok(this.module.ident().path()) Ok(this.module.ident().path())
} }
} }
@ -52,20 +51,21 @@ impl NextServerComponentModuleVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl Asset for NextServerComponentModule { impl Asset for NextServerComponentModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc { fn ident(&self) -> Vc<AssetIdent> {
self.module.ident().with_modifier(modifier()) self.module.ident().with_modifier(modifier())
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn content(&self) -> Result<AssetContentVc> { fn content(&self) -> Result<Vc<AssetContent>> {
bail!("Next.js server component module has no content") bail!("Next.js server component module has no content")
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc { fn references(&self) -> Vc<AssetReferences> {
let references: Vec<AssetReferenceVc> = let references: Vec<Vc<Box<dyn AssetReference>>> = vec![Vc::upcast(
vec![NextServerComponentModuleReferenceVc::new(self.module.into()).into()]; NextServerComponentModuleReference::new(Vc::upcast(self.module)),
AssetReferencesVc::cell(references) )];
Vc::cell(references)
} }
} }
@ -76,16 +76,15 @@ impl Module for NextServerComponentModule {}
impl ChunkableModule for NextServerComponentModule { impl ChunkableModule for NextServerComponentModule {
#[turbo_tasks::function] #[turbo_tasks::function]
fn as_chunk( fn as_chunk(
self_vc: NextServerComponentModuleVc, self: Vc<Self>,
context: ChunkingContextVc, context: Vc<Box<dyn ChunkingContext>>,
availability_info: Value<AvailabilityInfo>, availability_info: Value<AvailabilityInfo>,
) -> ChunkVc { ) -> Vc<Box<dyn Chunk>> {
EcmascriptChunkVc::new( Vc::upcast(EcmascriptChunk::new(
context, context,
self_vc.as_ecmascript_chunk_placeable(), Vc::upcast(self),
availability_info, availability_info,
) ))
.into()
} }
} }
@ -93,19 +92,20 @@ impl ChunkableModule for NextServerComponentModule {
impl EcmascriptChunkPlaceable for NextServerComponentModule { impl EcmascriptChunkPlaceable for NextServerComponentModule {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn as_chunk_item( async fn as_chunk_item(
self_vc: NextServerComponentModuleVc, self: Vc<Self>,
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
) -> Result<EcmascriptChunkItemVc> { ) -> Result<Vc<Box<dyn EcmascriptChunkItem>>> {
Ok(BuildServerComponentChunkItem { Ok(Vc::upcast(
context, BuildServerComponentChunkItem {
inner: self_vc, context,
} inner: self,
.cell() }
.into()) .cell(),
))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn get_exports(&self) -> EcmascriptExportsVc { fn get_exports(&self) -> Vc<EcmascriptExports> {
// TODO This should be EsmExports // TODO This should be EsmExports
EcmascriptExports::Value.cell() EcmascriptExports::Value.cell()
} }
@ -113,22 +113,20 @@ impl EcmascriptChunkPlaceable for NextServerComponentModule {
#[turbo_tasks::value] #[turbo_tasks::value]
struct BuildServerComponentChunkItem { struct BuildServerComponentChunkItem {
context: EcmascriptChunkingContextVc, context: Vc<Box<dyn EcmascriptChunkingContext>>,
inner: NextServerComponentModuleVc, inner: Vc<NextServerComponentModule>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl EcmascriptChunkItem for BuildServerComponentChunkItem { impl EcmascriptChunkItem for BuildServerComponentChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn chunking_context(&self) -> EcmascriptChunkingContextVc { fn chunking_context(&self) -> Vc<Box<dyn EcmascriptChunkingContext>> {
self.context self.context
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn content( async fn content(self: Vc<Self>) -> Result<Vc<EcmascriptChunkItemContent>> {
self_vc: BuildServerComponentChunkItemVc, let this = self.await?;
) -> Result<EcmascriptChunkItemContentVc> {
let this = self_vc.await?;
let inner = this.inner.await?; let inner = this.inner.await?;
let module_id = inner.module.as_chunk_item(this.context).id().await?; let module_id = inner.module.as_chunk_item(this.context).id().await?;
@ -151,12 +149,12 @@ impl EcmascriptChunkItem for BuildServerComponentChunkItem {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ChunkItem for BuildServerComponentChunkItem { impl ChunkItem for BuildServerComponentChunkItem {
#[turbo_tasks::function] #[turbo_tasks::function]
fn asset_ident(&self) -> AssetIdentVc { fn asset_ident(&self) -> Vc<AssetIdent> {
self.inner.ident() self.inner.ident()
} }
#[turbo_tasks::function] #[turbo_tasks::function]
fn references(&self) -> AssetReferencesVc { fn references(&self) -> Vc<AssetReferences> {
self.inner.references() self.inner.references()
} }
} }

View file

@ -1,23 +1,21 @@
use anyhow::Result; use anyhow::Result;
use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc}; use turbo_tasks::{ValueToString, Vc};
use turbopack_binding::turbopack::core::{ use turbopack_binding::turbopack::core::{
asset::{Asset, AssetVc}, asset::Asset,
chunk::{ chunk::{ChunkableModuleReference, ChunkingType, ChunkingTypeOption},
ChunkableModuleReference, ChunkableModuleReferenceVc, ChunkingType, ChunkingTypeOptionVc, reference::AssetReference,
}, resolve::ResolveResult,
reference::{AssetReference, AssetReferenceVc},
resolve::{ResolveResult, ResolveResultVc},
}; };
#[turbo_tasks::value] #[turbo_tasks::value]
pub struct NextServerComponentModuleReference { pub struct NextServerComponentModuleReference {
asset: AssetVc, asset: Vc<Box<dyn Asset>>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextServerComponentModuleReferenceVc { impl NextServerComponentModuleReference {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(asset: AssetVc) -> Self { pub fn new(asset: Vc<Box<dyn Asset>>) -> Vc<Self> {
NextServerComponentModuleReference { asset }.cell() NextServerComponentModuleReference { asset }.cell()
} }
} }
@ -25,8 +23,8 @@ impl NextServerComponentModuleReferenceVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ValueToString for NextServerComponentModuleReference { impl ValueToString for NextServerComponentModuleReference {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn to_string(&self) -> Result<StringVc> { async fn to_string(&self) -> Result<Vc<String>> {
Ok(StringVc::cell(format!( Ok(Vc::cell(format!(
"Next.js server component {}", "Next.js server component {}",
self.asset.ident().to_string().await? self.asset.ident().to_string().await?
))) )))
@ -36,7 +34,7 @@ impl ValueToString for NextServerComponentModuleReference {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl AssetReference for NextServerComponentModuleReference { impl AssetReference for NextServerComponentModuleReference {
#[turbo_tasks::function] #[turbo_tasks::function]
fn resolve_reference(&self) -> ResolveResultVc { fn resolve_reference(&self) -> Vc<ResolveResult> {
ResolveResult::asset(self.asset).cell() ResolveResult::asset(self.asset).cell()
} }
} }
@ -44,9 +42,9 @@ impl AssetReference for NextServerComponentModuleReference {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ChunkableModuleReference for NextServerComponentModuleReference { impl ChunkableModuleReference for NextServerComponentModuleReference {
#[turbo_tasks::function] #[turbo_tasks::function]
fn chunking_type(&self) -> ChunkingTypeOptionVc { fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
// TODO(alexkirsz) Instead of isolated parallel, have the server component // TODO(alexkirsz) Instead of isolated parallel, have the server component
// reference create a new chunk group entirely? // reference create a new chunk group entirely?
ChunkingTypeOptionVc::cell(Some(ChunkingType::IsolatedParallel)) Vc::cell(Some(ChunkingType::IsolatedParallel))
} }
} }

View file

@ -1,17 +1,15 @@
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use turbo_tasks::Vc;
use turbopack_binding::turbopack::{ use turbopack_binding::turbopack::{
core::module::ModuleVc, core::module::Module,
ecmascript::chunk::EcmascriptChunkPlaceableVc, ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{ turbopack::{transition::Transition, ModuleAssetContext},
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
},
}; };
use super::server_component_module::NextServerComponentModuleVc; use super::server_component_module::NextServerComponentModule;
/// This transition wraps a module into a marker /// This transition wraps a module into a marker
/// [`NextServerComponentModuleVc`]. /// [`Vc<NextServerComponentModule>`].
/// ///
/// When walking the module graph to build the client reference manifest, this /// When walking the module graph to build the client reference manifest, this
/// is used to determine under which server component CSS client references are /// is used to determine under which server component CSS client references are
@ -20,10 +18,10 @@ use super::server_component_module::NextServerComponentModuleVc;
pub struct NextServerComponentTransition {} pub struct NextServerComponentTransition {}
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl NextServerComponentTransitionVc { impl NextServerComponentTransition {
/// Creates a new [`NextServerComponentTransitionVc`]. /// Creates a new [`Vc<NextServerComponentTransition>`].
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new() -> Self { pub fn new() -> Vc<Self> {
NextServerComponentTransition {}.cell() NextServerComponentTransition {}.cell()
} }
} }
@ -32,14 +30,16 @@ impl NextServerComponentTransitionVc {
impl Transition for NextServerComponentTransition { impl Transition for NextServerComponentTransition {
#[turbo_tasks::function] #[turbo_tasks::function]
async fn process_module( async fn process_module(
_self_vc: NextServerComponentTransitionVc, self: Vc<Self>,
module: ModuleVc, module: Vc<Box<dyn Module>>,
_context: ModuleAssetContextVc, _context: Vc<ModuleAssetContext>,
) -> Result<ModuleVc> { ) -> Result<Vc<Box<dyn Module>>> {
let Some(module) = EcmascriptChunkPlaceableVc::resolve_from(module).await? else { let Some(module) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(module).await?
else {
bail!("not an ecmascript module"); bail!("not an ecmascript module");
}; };
Ok(NextServerComponentModuleVc::new(module).into()) Ok(Vc::upcast(NextServerComponentModule::new(module)))
} }
} }

View file

@ -2,16 +2,17 @@ use std::collections::HashSet;
use anyhow::Result; use anyhow::Result;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use turbo_tasks_fs::glob::GlobVc; use turbo_tasks::Vc;
use turbo_tasks_fs::glob::Glob;
use turbopack_binding::{ use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc, turbo::tasks_fs::FileSystemPath,
turbopack::core::{ turbopack::core::{
issue::unsupported_module::UnsupportedModuleIssue, issue::{unsupported_module::UnsupportedModuleIssue, IssueExt},
resolve::{ resolve::{
parse::{Request, RequestVc}, parse::Request,
pattern::Pattern, pattern::Pattern,
plugin::{ResolvePlugin, ResolvePluginConditionVc, ResolvePluginVc}, plugin::{ResolvePlugin, ResolvePluginCondition},
ResolveResultOptionVc, ResolveResultOption,
}, },
}, },
}; };
@ -23,13 +24,13 @@ lazy_static! {
#[turbo_tasks::value] #[turbo_tasks::value]
pub(crate) struct UnsupportedModulesResolvePlugin { pub(crate) struct UnsupportedModulesResolvePlugin {
root: FileSystemPathVc, root: Vc<FileSystemPath>,
} }
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl UnsupportedModulesResolvePluginVc { impl UnsupportedModulesResolvePlugin {
#[turbo_tasks::function] #[turbo_tasks::function]
pub fn new(root: FileSystemPathVc) -> Self { pub fn new(root: Vc<FileSystemPath>) -> Vc<Self> {
UnsupportedModulesResolvePlugin { root }.cell() UnsupportedModulesResolvePlugin { root }.cell()
} }
} }
@ -37,17 +38,17 @@ impl UnsupportedModulesResolvePluginVc {
#[turbo_tasks::value_impl] #[turbo_tasks::value_impl]
impl ResolvePlugin for UnsupportedModulesResolvePlugin { impl ResolvePlugin for UnsupportedModulesResolvePlugin {
#[turbo_tasks::function] #[turbo_tasks::function]
fn after_resolve_condition(&self) -> ResolvePluginConditionVc { fn after_resolve_condition(&self) -> Vc<ResolvePluginCondition> {
ResolvePluginConditionVc::new(self.root.root(), GlobVc::new("**")) ResolvePluginCondition::new(self.root.root(), Glob::new("**".to_string()))
} }
#[turbo_tasks::function] #[turbo_tasks::function]
async fn after_resolve( async fn after_resolve(
&self, &self,
_fs_path: FileSystemPathVc, _fs_path: Vc<FileSystemPath>,
context: FileSystemPathVc, context: Vc<FileSystemPath>,
request: RequestVc, request: Vc<Request>,
) -> Result<ResolveResultOptionVc> { ) -> Result<Vc<ResolveResultOption>> {
if let Request::Module { if let Request::Module {
module, module,
path, path,
@ -62,7 +63,6 @@ impl ResolvePlugin for UnsupportedModulesResolvePlugin {
package_path: None, package_path: None,
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
} }
@ -74,12 +74,11 @@ impl ResolvePlugin for UnsupportedModulesResolvePlugin {
package_path: Some(path.to_owned()), package_path: Some(path.to_owned()),
} }
.cell() .cell()
.as_issue()
.emit(); .emit();
} }
} }
} }
Ok(ResolveResultOptionVc::none()) Ok(ResolveResultOption::none())
} }
} }

Some files were not shown because too many files have changed in this diff Show more