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

View file

@ -44,11 +44,11 @@ swc_core = { version = "0.79.13" }
testing = { version = "0.33.20" }
# 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..
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
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

View file

@ -5,7 +5,9 @@ use next_swc::{
next_dynamic::next_dynamic,
next_ssg::next_ssg,
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 turbopack_binding::swc::{

View file

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

View file

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

View file

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

View file

@ -1,5 +1,8 @@
use std::ops::Deref;
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 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]
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> {
let turbo_tasks = endpoint.turbo_tasks().clone();
let endpoint = **endpoint;
let endpoint = ***endpoint;
let written = turbo_tasks
.run_once(async move { endpoint.write_to_disk().strongly_consistent().await })
.await
@ -39,7 +58,9 @@ pub async fn endpoint_write_to_disk(
#[napi(ts_return_type = "{ __napiType: \"RootTask\" }")]
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,
) -> napi::Result<External<RootTask>> {
let turbo_tasks = endpoint.turbo_tasks().clone();

View file

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

View file

@ -7,7 +7,7 @@ use napi::{
JsFunction, JsObject, NapiRaw, NapiValue, Status,
};
use serde::Serialize;
use turbo_tasks::{NothingVc, TaskId, TurboTasks};
use turbo_tasks::{unit, TaskId, TurboTasks};
use turbopack_binding::{
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);
return Err(error);
}
Ok(NothingVc::new().into())
Ok(unit().node)
})
});
Ok(External::new(RootTask {

View file

@ -31,7 +31,13 @@ use std::{cell::RefCell, env, path::PathBuf};
use anyhow::anyhow;
use napi::bindgen_prelude::{External, Status};
#[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_subscriber::{filter, prelude::*, util::SubscriberInitExt, Layer};

View file

@ -1,26 +1,28 @@
use next_core::app_structure::Entrypoint;
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]
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 {
Entrypoint::AppPage { .. } => Route::AppPage {
html_endpoint: AppPageEndpoint {
ty: AppPageEndpointType::Html,
}
.cell()
.into(),
rsc_endpoint: AppPageEndpoint {
ty: AppPageEndpointType::Rsc,
}
.cell()
.into(),
html_endpoint: Vc::upcast(
AppPageEndpoint {
ty: AppPageEndpointType::Html,
}
.cell(),
),
rsc_endpoint: Vc::upcast(
AppPageEndpoint {
ty: AppPageEndpointType::Rsc,
}
.cell(),
),
},
Entrypoint::AppRoute { .. } => Route::AppRoute {
endpoint: AppRouteEndpoint.cell().into(),
endpoint: Vc::upcast(AppRouteEndpoint.cell()),
},
}
.cell()
@ -40,12 +42,12 @@ struct AppPageEndpoint {
#[turbo_tasks::value_impl]
impl Endpoint for AppPageEndpoint {
#[turbo_tasks::function]
fn write_to_disk(&self) -> WrittenEndpointVc {
fn write_to_disk(&self) -> Vc<WrittenEndpoint> {
todo!()
}
#[turbo_tasks::function]
fn changed(&self) -> CompletionVc {
fn changed(&self) -> Vc<Completion> {
todo!()
}
}
@ -56,12 +58,12 @@ struct AppRouteEndpoint;
#[turbo_tasks::value_impl]
impl Endpoint for AppRouteEndpoint {
#[turbo_tasks::function]
fn write_to_disk(&self) -> WrittenEndpointVc {
fn write_to_disk(&self) -> Vc<WrittenEndpoint> {
todo!()
}
#[turbo_tasks::function]
fn changed(&self) -> CompletionVc {
fn changed(&self) -> Vc<Completion> {
todo!()
}
}

View file

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

View file

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

View file

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

View file

@ -1,4 +1,6 @@
#![feature(type_alias_impl_trait)]
#![feature(arbitrary_self_types)]
#![feature(async_fn_in_trait)]
use turbopack_binding::turbo::{
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 anyhow::Result;

View file

@ -2,15 +2,18 @@ use std::collections::HashSet;
use anyhow::Result;
use indexmap::IndexMap;
use next_core::{self, next_client_reference::ClientReferenceType};
use turbo_tasks::TryJoinIterExt;
use next_core::{
next_client_reference::ClientReferenceType,
{self},
};
use turbo_tasks::{TryJoinIterExt, Vc};
use turbopack_binding::turbopack::{
build::BuildChunkingContextVc,
build::BuildChunkingContext,
core::{
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
@ -20,9 +23,9 @@ use turbopack_binding::turbopack::{
/// type needs to load.
pub async fn compute_app_client_references_chunks(
app_client_reference_types: &HashSet<ClientReferenceType>,
client_chunking_context: EcmascriptChunkingContextVc,
ssr_chunking_context: BuildChunkingContextVc,
all_chunks: &mut Vec<OutputAssetVc>,
client_chunking_context: Vc<Box<dyn EcmascriptChunkingContext>>,
ssr_chunking_context: Vc<BuildChunkingContext>,
all_chunks: &mut Vec<Vc<Box<dyn OutputAsset>>>,
) -> Result<IndexMap<ClientReferenceType, ClientReferenceChunks>> {
let app_client_references_chunks: IndexMap<_, _> = app_client_reference_types
.iter()
@ -34,10 +37,10 @@ pub async fn compute_app_client_references_chunks(
let ecmascript_client_reference_ref = ecmascript_client_reference.await?;
let client_entry_chunk = ecmascript_client_reference_ref
.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
.ssr_module
.as_root_chunk(ssr_chunking_context.into());
.as_root_chunk(Vc::upcast(ssr_chunking_context));
ClientReferenceChunks {
client_chunks: client_chunking_context.chunk_group(client_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 client_entry_chunk = css_client_reference_ref
.client_module
.as_root_chunk(client_chunking_context.into());
.as_root_chunk(Vc::upcast(client_chunking_context));
ClientReferenceChunks {
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.
pub struct ClientReferenceChunks {
/// 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.
pub ssr_chunks: OutputAssetsVc,
pub ssr_chunks: Vc<OutputAssets>,
}

View file

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

View file

@ -3,37 +3,36 @@ use std::io::Write;
use anyhow::{bail, Result};
use indoc::writedoc;
use next_core::{
app_structure::LoaderTreeVc,
app_structure::LoaderTree,
loader_tree::{LoaderTreeModule, ServerComponentTransition},
mode::NextMode,
next_server_component::NextServerComponentTransitionVc,
next_server_component::NextServerComponentTransition,
UnsupportedDynamicMetadataIssue,
};
use turbo_tasks::{TryJoinIterExt, Value, ValueToString};
use turbo_tasks::{TryJoinIterExt, Value, ValueToString, Vc};
use turbopack_binding::{
turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPathVc},
turbo::tasks_fs::{rope::RopeBuilder, File, FileSystemPath},
turbopack::{
core::{
context::AssetContext,
reference_type::{InnerAssetsVc, ReferenceType},
virtual_source::VirtualSourceVc,
asset::AssetContent, context::AssetContext, issue::IssueExt,
reference_type::ReferenceType, virtual_source::VirtualSource,
},
ecmascript::{chunk::EcmascriptChunkPlaceableVc, utils::StringifyJs},
turbopack::ModuleAssetContextVc,
ecmascript::{chunk::EcmascriptChunkPlaceable, utils::StringifyJs},
turbopack::ModuleAssetContext,
},
};
use super::app_entries::{AppEntry, AppEntryVc};
use super::app_entries::AppEntry;
/// Computes the entry for a Next.js app page.
pub(super) async fn get_app_page_entry(
context: ModuleAssetContextVc,
loader_tree: LoaderTreeVc,
app_dir: FileSystemPathVc,
context: Vc<ModuleAssetContext>,
loader_tree: Vc<LoaderTree>,
app_dir: Vc<FileSystemPath>,
pathname: &str,
project_root: FileSystemPathVc,
) -> Result<AppEntryVc> {
let server_component_transition = NextServerComponentTransitionVc::new().into();
project_root: Vc<FileSystemPath>,
) -> Result<Vc<AppEntry>> {
let server_component_transition = Vc::upcast(NextServerComponentTransition::new());
let loader_tree = LoaderTreeModule::build(
loader_tree,
@ -57,7 +56,6 @@ pub(super) async fn get_app_page_entry(
files: unsupported_metadata,
}
.cell()
.as_issue()
.emit();
}
@ -95,14 +93,16 @@ pub(super) async fn get_app_page_entry(
let file = File::from(result.build());
let source =
// 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(
source.into(),
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(inner_assets))),
Vc::upcast(source),
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");
};

View file

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

View file

@ -4,23 +4,24 @@ use anyhow::{bail, Result};
use base64::{display::Base64Display, engine::general_purpose::STANDARD};
use indoc::writedoc;
use next_core::app_structure::MetadataItem;
use turbo_tasks::ValueToString;
use turbo_tasks::{ValueToString, Vc};
use turbopack_binding::{
turbo::tasks_fs::{rope::RopeBuilder, File, FileContent, FileSystemPathVc},
turbo::tasks_fs::{rope::RopeBuilder, File, FileContent, FileSystemPath},
turbopack::{
core::virtual_source::VirtualSourceVc, ecmascript::utils::StringifyJs,
turbopack::ModuleAssetContextVc,
core::{asset::AssetContent, virtual_source::VirtualSource},
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.
pub(super) async fn get_app_route_favicon_entry(
rsc_context: ModuleAssetContextVc,
rsc_context: Vc<ModuleAssetContext>,
favicon: MetadataItem,
project_root: FileSystemPathVc,
) -> Result<AppEntryVc> {
project_root: Vc<FileSystemPath>,
) -> Result<Vc<AppEntry>> {
let path = match favicon {
// TODO(alexkirsz) Is there a difference here?
MetadataItem::Static { path } => path,
@ -74,11 +75,11 @@ pub(super) async fn get_app_route_favicon_entry(
let file = File::from(code.build());
let 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(
rsc_context,
source.into(),
Vc::upcast(source),
// TODO(alexkirsz) Get this from the metadata?
"/favicon.ico",
project_root,

View file

@ -7,42 +7,38 @@ use std::{
use anyhow::{anyhow, bail, Context, Result};
use dunce::canonicalize;
use next_core::{
self,
mode::NextMode,
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_dynamic::NextDynamicEntriesVc,
next_dynamic::NextDynamicEntries,
next_server::{get_server_chunking_context, get_server_compile_time_info},
url_node::get_sorted_routes,
{self},
};
use serde::Serialize;
use turbo_tasks::{
graph::{AdjacencyMap, GraphTraversal},
CollectiblesSource, CompletionVc, CompletionsVc, RawVc, TransientInstance, TransientValue,
TryJoinIterExt,
Completion, Completions, TransientInstance, TransientValue, TryJoinIterExt, Vc,
};
use turbopack_binding::{
turbo::tasks_fs::{
rebase, DiskFileSystemVc, FileContent, FileSystem, FileSystemPath, FileSystemPathVc,
FileSystemVc,
},
turbo::tasks_fs::{rebase, DiskFileSystem, FileContent, FileSystem, FileSystemPath},
turbopack::{
build::BuildChunkingContextVc,
cli_utils::issue::{ConsoleUiVc, LogOptions},
build::BuildChunkingContext,
cli_utils::issue::{ConsoleUi, LogOptions},
core::{
asset::{Asset, AssetVc, AssetsVc},
asset::{Asset, Assets},
chunk::ChunkingContext,
environment::ServerAddrVc,
issue::{IssueReporter, IssueReporterVc, IssueSeverity, IssueVc},
output::{OutputAssetVc, OutputAssetsVc},
environment::ServerAddr,
issue::{IssueContextExt, IssueReporter, IssueSeverity},
output::{OutputAsset, OutputAssets},
reference::AssetReference,
virtual_fs::VirtualFileSystemVc,
virtual_fs::VirtualFileSystem,
},
dev::DevChunkingContextVc,
dev::DevChunkingContext,
ecmascript::utils::StringifyJs,
env::dotenv::load_env,
node::execution_context::ExecutionContextVc,
node::execution_context::ExecutionContext,
turbopack::evaluate_context::node_build_environment,
},
};
@ -62,7 +58,7 @@ use crate::{
};
#[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
.dir
.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 \
versions, last 1 Edge versions";
versions, last 1 Edge versions"
.to_string();
let log_options = LogOptions {
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),
};
let issue_reporter: IssueReporterVc =
ConsoleUiVc::new(TransientInstance::new(log_options)).into();
let node_fs = node_fs(&project_root, issue_reporter);
let node_root = node_fs.root().join(".next");
let client_fs = client_fs(&project_root, issue_reporter);
let client_root = client_fs.root().join(".next");
let issue_reporter: Vc<Box<dyn IssueReporter>> =
Vc::upcast(ConsoleUi::new(TransientInstance::new(log_options)));
let node_fs = node_fs(project_root.clone(), issue_reporter);
let node_root = node_fs.root().join(".next".to_string());
let client_fs = client_fs(project_root.clone(), issue_reporter);
let client_root = client_fs.root().join(".next".to_string());
// 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 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_relative
.strip_prefix(MAIN_SEPARATOR)
.unwrap_or(project_relative)
.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_execution_chunking_context = DevChunkingContextVc::builder(
project_root,
node_root,
node_root.join("chunks"),
node_root.join("assets"),
node_build_environment(),
)
.build()
.into();
let node_execution_chunking_context = Vc::upcast(
DevChunkingContext::builder(
project_root,
node_root,
node_root.join("chunks".to_string()),
node_root.join("assets".to_string()),
node_build_environment(),
)
.build(),
);
let env = load_env(project_root);
let execution_context =
ExecutionContextVc::new(project_root, node_execution_chunking_context, env);
let next_config = load_next_config(execution_context.with_layer("next_config"));
ExecutionContext::new(project_root, node_execution_chunking_context, env);
let next_config = load_next_config(execution_context.with_layer("next_config".to_string()));
let mode = NextMode::Build;
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.
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 page_entries = get_page_entries(
next_router_root,
@ -169,12 +167,8 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
.try_join()
.await?;
let app_client_references_by_entry = ClientReferencesByEntryVc::new(AssetsVc::cell(
app_rsc_entries
.iter()
.copied()
.map(|entry| entry.into())
.collect(),
let app_client_references_by_entry = ClientReferencesByEntry::new(Vc::cell(
app_rsc_entries.iter().copied().map(Vc::upcast).collect(),
))
.await?;
@ -228,12 +222,8 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
.collect();
// TODO(alexkirsz) Handle dynamic entries and dynamic chunks.
let _dynamic_entries = NextDynamicEntriesVc::from_entries(AssetsVc::cell(
all_node_entries
.iter()
.copied()
.map(|entry| entry.into())
.collect(),
let _dynamic_entries = NextDynamicEntries::from_entries(Vc::cell(
all_node_entries.iter().copied().map(Vc::upcast).collect(),
))
.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
// be applied on the AssetContext level instead.
let rsc_chunking_context = server_chunking_context.with_layer("rsc");
let ssr_chunking_context = server_chunking_context.with_layer("ssr");
let rsc_chunking_context = server_chunking_context.with_layer("rsc".to_string());
let ssr_chunking_context = server_chunking_context.with_layer("ssr".to_string());
let (Some(rsc_chunking_context), Some(ssr_chunking_context)) = (
BuildChunkingContextVc::resolve_from(rsc_chunking_context).await?,
BuildChunkingContextVc::resolve_from(ssr_chunking_context).await?,
Vc::try_resolve_downcast_type::<BuildChunkingContext>(rsc_chunking_context).await?,
Vc::try_resolve_downcast_type::<BuildChunkingContext>(ssr_chunking_context).await?,
) else {
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 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
// in manifests. It will be added back on the client through the chunk_base_path
// 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?;
// PAGE CHUNKING
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?;
compute_page_entries_chunks(
@ -300,10 +290,10 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
// APP CHUNKING
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 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?;
// APP CLIENT REFERENCES CHUNKING
@ -325,7 +315,7 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
&app_client_references_chunks,
rsc_chunking_context,
client_chunking_context,
ssr_chunking_context.into(),
Vc::upcast(ssr_chunking_context),
node_root,
&client_relative_path_ref,
&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_fs_path = node_root.join(&ssg_manifest_path);
let ssg_manifest_fs_path = node_root.join(ssg_manifest_path.clone());
completions.push(
ssg_manifest_fs_path.write(
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_fs_path = node_root.join(&client_manifest_path);
let client_manifest_fs_path = node_root.join(client_manifest_path.clone());
completions.push(
client_manifest_fs_path.write(
FileContent::Content(
@ -422,23 +412,23 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
// experimental-edge pages?
completions.push(write_manifest(
MiddlewaresManifest::default(),
node_root.join("server/middleware-manifest.json"),
node_root.join("server/middleware-manifest.json".to_string()),
)?);
completions.push(write_manifest(
NextFontManifest::default(),
node_root.join("server/next-font-manifest.json"),
node_root.join("server/next-font-manifest.json".to_string()),
)?);
completions.push(write_manifest(
FontManifest::default(),
node_root.join("server/font-manifest.json"),
node_root.join("server/font-manifest.json".to_string()),
)?);
completions.push(write_manifest(
ServerReferenceManifest::default(),
node_root.join("server/server-reference-manifest.json"),
node_root.join("server/server-reference-manifest.json".to_string()),
)?);
completions.push(write_manifest(
ReactLoadableManifest::default(),
node_root.join("react-loadable-manifest.json"),
node_root.join("react-loadable-manifest.json".to_string()),
)?);
completions.push(
@ -451,45 +441,49 @@ pub(crate) async fn next_build(options: TransientInstance<BuildOptions>) -> Resu
.await?,
);
Ok(CompletionsVc::all(completions))
Ok(Completions::all(completions))
}
#[turbo_tasks::function]
async fn workspace_fs(
workspace_root: &str,
issue_reporter: IssueReporterVc,
) -> Result<FileSystemVc> {
let disk_fs = DiskFileSystemVc::new("workspace".to_string(), workspace_root.to_string());
workspace_root: String,
issue_reporter: Vc<Box<dyn IssueReporter>>,
) -> Result<Vc<Box<dyn FileSystem>>> {
let disk_fs = DiskFileSystem::new("workspace".to_string(), workspace_root.to_string());
handle_issues(disk_fs, issue_reporter).await?;
Ok(disk_fs.into())
Ok(Vc::upcast(disk_fs))
}
#[turbo_tasks::function]
async fn node_fs(node_root: &str, issue_reporter: IssueReporterVc) -> Result<FileSystemVc> {
let disk_fs = DiskFileSystemVc::new("node".to_string(), node_root.to_string());
async fn node_fs(
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?;
Ok(disk_fs.into())
Ok(Vc::upcast(disk_fs))
}
#[turbo_tasks::function]
async fn client_fs(client_root: &str, issue_reporter: IssueReporterVc) -> Result<FileSystemVc> {
let disk_fs = DiskFileSystemVc::new("client".to_string(), client_root.to_string());
async fn client_fs(
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?;
Ok(disk_fs.into())
Ok(Vc::upcast(disk_fs))
}
async fn handle_issues<T: Into<RawVc> + CollectiblesSource + Copy>(
source: T,
issue_reporter: IssueReporterVc,
) -> Result<()> {
let issues = IssueVc::peek_issues_with_path(source)
async fn handle_issues<T>(source: Vc<T>, issue_reporter: Vc<Box<dyn IssueReporter>>) -> Result<()> {
let issues = source
.peek_issues_with_path()
.await?
.strongly_consistent()
.await?;
let has_fatal = issue_reporter.report_issues(
TransientInstance::new(issues.clone()),
TransientValue::new(source.into()),
TransientValue::new(source.node),
);
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
/// inside the node root or the client root.
async fn emit_all_assets(
chunks: Vec<OutputAssetVc>,
chunks: Vec<Vc<Box<dyn OutputAsset>>>,
node_root: &FileSystemPath,
client_relative_path: FileSystemPathVc,
client_output_path: FileSystemPathVc,
) -> Result<CompletionVc> {
let all_assets = all_assets_from_entries(OutputAssetsVc::cell(chunks)).await?;
Ok(CompletionsVc::all(
client_relative_path: Vc<FileSystemPath>,
client_output_path: Vc<FileSystemPath>,
) -> Result<Vc<Completion>> {
let all_assets = all_assets_from_entries(Vc::cell(chunks)).await?;
Ok(Completions::all(
all_assets
.iter()
.copied()
.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));
} else if asset
.ident()
.path()
.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
// _next. We need to rebase them to remove that prefix.
return Ok(emit_rebase(asset, client_relative_path, client_output_path));
}
Ok(CompletionVc::immutable())
Ok(Completion::immutable())
})
.try_join()
.await?,
@ -534,12 +528,16 @@ async fn emit_all_assets(
}
#[turbo_tasks::function]
fn emit(asset: AssetVc) -> CompletionVc {
fn emit(asset: Vc<Box<dyn Asset>>) -> Vc<Completion> {
asset.content().write(asset.ident().path())
}
#[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
.content()
.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
/// assets.
#[turbo_tasks::function]
async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<AssetsVc> {
Ok(AssetsVc::cell(
async fn all_assets_from_entries(entries: Vc<OutputAssets>) -> Result<Vc<Assets>> {
Ok(Vc::cell(
AdjacencyMap::new()
.skip_duplicates()
.visit(
entries.await?.iter().copied().map(Into::into),
entries.await?.iter().copied().map(Vc::upcast),
get_referenced_assets,
)
.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.
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
.references()
.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
/// 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
T: Serialize,
{

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

@ -1,27 +1,28 @@
use turbo_tasks::Vc;
use turbopack_binding::{
turbo::tasks_fs::{FileContentVc, FileSystem, FileSystemPathVc, FileSystemVc},
turbopack::core::{file_source::FileSourceVc, source::SourceVc},
turbo::tasks_fs::{FileContent, FileSystem, FileSystemPath},
turbopack::core::{file_source::FileSource, source::Source},
};
pub const VIRTUAL_PACKAGE_NAME: &str = "@vercel/turbopack-next";
#[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
turbo_tasks_fs::embed_directory!("next", "$CARGO_MANIFEST_DIR/js/src")
}
#[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()
}
#[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)
}
#[turbo_tasks::function]
pub(crate) fn next_asset(path: &str) -> SourceVc {
FileSourceVc::new(next_js_file_path(path)).into()
pub(crate) fn next_asset(path: String) -> Vc<Box<dyn Source>> {
Vc::upcast(FileSource::new(next_js_file_path(path)))
}

View file

@ -1,12 +1,12 @@
use anyhow::Result;
use turbo_tasks::{
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::{
asset::Asset,
output::{OutputAssetVc, OutputAssetsVc},
output::{OutputAsset, OutputAssets},
reference::AssetReference,
};
@ -14,31 +14,36 @@ use turbopack_binding::turbopack::core::{
/// inside the node root or the client root.
#[turbo_tasks::function]
pub async fn emit_all_assets(
assets: OutputAssetsVc,
node_root: FileSystemPathVc,
client_relative_path: FileSystemPathVc,
client_output_path: FileSystemPathVc,
) -> Result<CompletionVc> {
assets: Vc<OutputAssets>,
node_root: Vc<FileSystemPath>,
client_relative_path: Vc<FileSystemPath>,
client_output_path: Vc<FileSystemPath>,
) -> Result<Vc<Completion>> {
let all_assets = all_assets_from_entries(assets).await?;
Ok(CompletionsVc::all(
Ok(Completions::all(
all_assets
.iter()
.copied()
.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));
} else if asset
.ident()
.path()
.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
// _next. We need to rebase them to remove that prefix.
return Ok(emit_rebase(asset, client_relative_path, client_output_path));
}
Ok(CompletionVc::immutable())
Ok(Completion::immutable())
})
.try_join()
.await?,
@ -46,12 +51,16 @@ pub async fn emit_all_assets(
}
#[turbo_tasks::function]
fn emit(asset: OutputAssetVc) -> CompletionVc {
fn emit(asset: Vc<Box<dyn OutputAsset>>) -> Vc<Completion> {
asset.content().write(asset.ident().path())
}
#[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
.content()
.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
/// assets.
#[turbo_tasks::function]
async fn all_assets_from_entries(entries: OutputAssetsVc) -> Result<OutputAssetsVc> {
Ok(OutputAssetsVc::cell(
async fn all_assets_from_entries(entries: Vc<OutputAssets>) -> Result<Vc<OutputAssets>> {
Ok(Vc::cell(
AdjacencyMap::new()
.skip_duplicates()
.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.
async fn get_referenced_assets(
asset: OutputAssetVc,
) -> Result<impl Iterator<Item = OutputAssetVc> + Send> {
Ok(asset
.references()
.await?
.iter()
.map(|reference| async move {
let primary_assets = reference.resolve_reference().primary_assets().await?;
Ok(primary_assets.clone_value())
})
.try_join()
.await?
.into_iter()
.flatten()
.map(|asset| async move { Ok(OutputAssetVc::resolve_from(asset).await?) })
.try_join()
.await?
.into_iter()
.flatten())
asset: Vc<Box<dyn OutputAsset>>,
) -> Result<impl Iterator<Item = Vc<Box<dyn OutputAsset>>> + Send> {
Ok(
asset
.references()
.await?
.iter()
.map(|reference| async move {
let primary_assets = reference.resolve_reference().primary_assets().await?;
Ok(primary_assets.clone_value())
})
.try_join()
.await?
.into_iter()
.flatten()
.map(|asset| async move {
Ok(Vc::try_resolve_sidecast::<Box<dyn OutputAsset>>(asset).await?)
})
.try_join()
.await?
.into_iter()
.flatten(),
)
}

View file

@ -1,47 +1,47 @@
use anyhow::Result;
use indexmap::indexmap;
use turbo_tasks::Vc;
use turbopack_binding::{
turbo::tasks_env::{
CustomProcessEnvVc, EnvMapVc, FilterProcessEnvVc, ProcessEnv, ProcessEnvVc,
},
turbopack::env::EmbeddableProcessEnvVc,
turbo::tasks_env::{CustomProcessEnv, EnvMap, FilterProcessEnv, ProcessEnv},
turbopack::env::EmbeddableProcessEnv,
};
use crate::next_config::NextConfigVc;
use crate::next_config::NextConfig;
/// Creates a ProcessEnvVc safe to use in JS, by stringifying and encoding as
/// regular JS strings. Setting `client` to true will additionally filter the
/// env to just the keys that are acceptable for the client to access.
/// Creates a Vc<Box<dyn ProcessEnv>> safe to use in JS, by stringifying and
/// encoding as regular JS strings. Setting `client` to true will additionally
/// 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
/// an Object and not a String.
#[turbo_tasks::function]
pub async fn env_for_js(
env: ProcessEnvVc,
env: Vc<Box<dyn ProcessEnv>>,
client: bool,
next_config: NextConfigVc,
) -> Result<ProcessEnvVc> {
let test_mode = env.read("__NEXT_TEST_MODE").await?;
next_config: Vc<NextConfig>,
) -> Result<Vc<Box<dyn ProcessEnv>>> {
let test_mode = env.read("__NEXT_TEST_MODE".to_string()).await?;
let test_mode = test_mode.as_deref().unwrap_or("");
let env = if client {
FilterProcessEnvVc::new(
Vc::upcast(FilterProcessEnv::new(
env,
vec![
"NEXT_PUBLIC_".to_string(),
"NODE_ENV".to_string(),
"PORT".to_string(),
],
)
.into()
))
} else {
// Server doesn't need to have env vars injected since it will have them in the
// real process.env.
EnvMapVc::cell(Default::default()).into()
Vc::upcast(EnvMap::empty())
};
let env =
EmbeddableProcessEnvVc::new(CustomProcessEnvVc::new(env, next_config.env()).into()).into();
let env = Vc::upcast(EmbeddableProcessEnv::new(Vc::upcast(
CustomProcessEnv::new(env, next_config.env()),
)));
let image_config = next_config.image_config().await?;
let mut map = indexmap! {
@ -65,5 +65,5 @@ pub async fn env_for_js(
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 anyhow::{bail, Result};
use turbo_tasks::Value;
use turbo_tasks::{Value, Vc};
use turbopack_binding::{
turbo::{tasks_env::ProcessEnvVc, tasks_fs::FileSystemPathVc},
turbo::{tasks_env::ProcessEnv, tasks_fs::FileSystemPath},
turbopack::{
core::{
compile_time_info::CompileTimeInfoVc,
context::AssetContextVc,
resolve::{options::ImportMap, origin::PlainResolveOriginVc},
},
dev_server::html::DevHtmlAssetVc,
node::execution_context::ExecutionContextVc,
turbopack::{
ecmascript::EcmascriptModuleAssetVc, transition::TransitionsByNameVc,
ModuleAssetContextVc,
compile_time_info::CompileTimeInfo,
context::AssetContext,
resolve::{options::ImportMap, origin::PlainResolveOrigin},
},
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_resolve_options_context, get_client_runtime_entries, ClientContextType,
},
next_config::NextConfigVc,
next_config::NextConfig,
next_import_map::insert_next_shared_aliases,
runtime::resolve_runtime_request,
};
#[turbo_tasks::function]
pub async fn get_fallback_page(
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
dev_server_root: FileSystemPathVc,
env: ProcessEnvVc,
client_compile_time_info: CompileTimeInfoVc,
next_config: NextConfigVc,
) -> Result<DevHtmlAssetVc> {
project_path: Vc<FileSystemPath>,
execution_context: Vc<ExecutionContext>,
dev_server_root: Vc<FileSystemPath>,
env: Vc<Box<dyn ProcessEnv>>,
client_compile_time_info: Vc<CompileTimeInfo>,
next_config: Vc<NextConfig>,
) -> Result<Vc<DevHtmlAsset>> {
let ty = Value::new(ClientContextType::Fallback);
let mode = NextMode::Development;
let resolve_options_context =
@ -69,35 +66,34 @@ pub async fn get_fallback_page(
)
.await?;
let context: AssetContextVc = ModuleAssetContextVc::new(
TransitionsByNameVc::cell(HashMap::new()),
let context: Vc<Box<dyn AssetContext>> = Vc::upcast(ModuleAssetContext::new(
Vc::cell(HashMap::new()),
client_compile_time_info,
module_options_context,
resolve_options_context.with_extended_import_map(import_map.cell()),
)
.into();
));
let runtime_entries = entries.resolve_entries(context);
let fallback_chunk = resolve_runtime_request(
PlainResolveOriginVc::new(context, project_path).into(),
"entry/fallback",
Vc::upcast(PlainResolveOrigin::new(context, project_path)),
"entry/fallback".to_string(),
);
let module = if let Some(module) =
EcmascriptModuleAssetVc::resolve_from(fallback_chunk.as_asset()).await?
Vc::try_resolve_downcast_type::<EcmascriptModuleAsset>(fallback_chunk).await?
{
module
} else {
bail!("fallback runtime entry is not an ecmascript module");
};
Ok(DevHtmlAssetVc::new(
dev_server_root.join("fallback.html"),
Ok(DevHtmlAsset::new(
dev_server_root.join("fallback.html".to_string()),
vec![(
module.into(),
chunking_context.into(),
Some(runtime_entries.with_entry(module.into())),
Vc::upcast(module),
Vc::upcast(chunking_context),
Some(runtime_entries.with_entry(Vc::upcast(module))),
)],
))
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,14 +1,15 @@
use anyhow::{bail, Result};
use turbo_tasks::Vc;
use turbopack_binding::{
turbo::{tasks::ValueToString, tasks_fs::FileSystemPathVc},
turbo::{tasks::ValueToString, tasks_fs::FileSystemPath},
turbopack::{
core::{
asset::Asset,
chunk::{EvaluatableAssetVc, EvaluatableAssetsVc},
context::AssetContextVc,
issue::{IssueSeverity, OptionIssueSourceVc},
resolve::{origin::PlainResolveOriginVc, parse::RequestVc},
source::SourceVc,
chunk::{EvaluatableAsset, EvaluatableAssetExt, EvaluatableAssets},
context::AssetContext,
issue::{IssueSeverity, OptionIssueSource},
resolve::{origin::PlainResolveOrigin, parse::Request},
source::Source,
},
ecmascript::resolve::cjs_resolve,
},
@ -16,29 +17,30 @@ use turbopack_binding::{
#[turbo_tasks::value(shared)]
pub enum RuntimeEntry {
Request(RequestVc, FileSystemPathVc),
Evaluatable(EvaluatableAssetVc),
Source(SourceVc),
Request(Vc<Request>, Vc<FileSystemPath>),
Evaluatable(Vc<Box<dyn EvaluatableAsset>>),
Source(Vc<Box<dyn Source>>),
}
#[turbo_tasks::value_impl]
impl RuntimeEntryVc {
impl RuntimeEntry {
#[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? {
RuntimeEntry::Evaluatable(e) => return Ok(EvaluatableAssetsVc::one(e)),
RuntimeEntry::Evaluatable(e) => return Ok(EvaluatableAssets::one(e)),
RuntimeEntry::Source(source) => {
return Ok(EvaluatableAssetsVc::one(EvaluatableAssetVc::from_source(
source, context,
)));
return Ok(EvaluatableAssets::one(source.to_evaluatable(context)));
}
RuntimeEntry::Request(r, path) => (r, path),
};
let assets = cjs_resolve(
PlainResolveOriginVc::new(context, path).into(),
Vc::upcast(PlainResolveOrigin::new(context, path)),
request,
OptionIssueSourceVc::none(),
OptionIssueSource::none(),
IssueSeverity::Error.cell(),
)
.primary_assets()
@ -46,7 +48,9 @@ impl RuntimeEntryVc {
let mut runtime_entries = Vec::with_capacity(assets.len());
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);
} else {
bail!(
@ -56,17 +60,20 @@ impl RuntimeEntryVc {
}
}
Ok(EvaluatableAssetsVc::cell(runtime_entries))
Ok(Vc::cell(runtime_entries))
}
}
#[turbo_tasks::value(transparent)]
pub struct RuntimeEntries(Vec<RuntimeEntryVc>);
pub struct RuntimeEntries(Vec<Vc<RuntimeEntry>>);
#[turbo_tasks::value_impl]
impl RuntimeEntriesVc {
impl RuntimeEntries {
#[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();
for reference in &self.await? {
@ -74,6 +81,6 @@ impl RuntimeEntriesVc {
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 next_transform_strip_page_exports::ExportFilter;
use turbo_tasks::Vc;
use turbopack_binding::turbopack::turbopack::module_options::ModuleRule;
use crate::{
mode::NextMode,
next_client::context::ClientContextType,
next_config::NextConfigVc,
next_config::NextConfig,
next_shared::transforms::{
get_next_dynamic_transform_rule, get_next_font_transform_rule, get_next_image_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
/// transforms.
pub async fn get_next_client_transforms_rules(
next_config: NextConfigVc,
next_config: Vc<NextConfig>,
context_ty: ClientContextType,
mode: NextMode,
) -> Result<Vec<ModuleRule>> {

View file

@ -1,25 +1,20 @@
use anyhow::{bail, Result};
use indexmap::indexmap;
use turbo_tasks::Value;
use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{
core::{
chunk::{ChunkingContext, ChunkingContextVc},
compile_time_info::CompileTimeInfoVc,
context::AssetContext,
module::ModuleVc,
reference_type::{InnerAssetsVc, ReferenceType},
chunk::ChunkingContext, compile_time_info::CompileTimeInfo, context::AssetContext,
module::Module, reference_type::ReferenceType,
},
ecmascript::chunk::EcmascriptChunkPlaceableVc,
ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{
ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset,
module_options::ModuleOptionsContextVc,
resolve_options_context::ResolveOptionsContextVc,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext,
transition::Transition, ModuleAssetContext,
},
};
use super::runtime_entry::RuntimeEntriesVc;
use super::runtime_entry::RuntimeEntries;
use crate::embed_js::next_asset;
/// Makes a transition into a next.js client context.
@ -30,11 +25,11 @@ use crate::embed_js::next_asset;
#[turbo_tasks::value(shared)]
pub struct NextClientTransition {
pub is_app: bool,
pub client_compile_time_info: CompileTimeInfoVc,
pub client_module_options_context: ModuleOptionsContextVc,
pub client_resolve_options_context: ResolveOptionsContextVc,
pub client_chunking_context: ChunkingContextVc,
pub runtime_entries: RuntimeEntriesVc,
pub client_compile_time_info: Vc<CompileTimeInfo>,
pub client_module_options_context: Vc<ModuleOptionsContext>,
pub client_resolve_options_context: Vc<ResolveOptionsContext>,
pub client_chunking_context: Vc<Box<dyn ChunkingContext>>,
pub runtime_entries: Vc<RuntimeEntries>,
}
#[turbo_tasks::value_impl]
@ -42,60 +37,65 @@ impl Transition for NextClientTransition {
#[turbo_tasks::function]
fn process_compile_time_info(
&self,
_compile_time_info: CompileTimeInfoVc,
) -> CompileTimeInfoVc {
_compile_time_info: Vc<CompileTimeInfo>,
) -> Vc<CompileTimeInfo> {
self.client_compile_time_info
}
#[turbo_tasks::function]
fn process_module_options_context(
&self,
_context: ModuleOptionsContextVc,
) -> ModuleOptionsContextVc {
_context: Vc<ModuleOptionsContext>,
) -> Vc<ModuleOptionsContext> {
self.client_module_options_context
}
#[turbo_tasks::function]
fn process_resolve_options_context(
&self,
_context: ResolveOptionsContextVc,
) -> ResolveOptionsContextVc {
_context: Vc<ResolveOptionsContext>,
) -> Vc<ResolveOptionsContext> {
self.client_resolve_options_context
}
#[turbo_tasks::function]
async fn process_module(
&self,
asset: ModuleVc,
context: ModuleAssetContextVc,
) -> Result<ModuleVc> {
asset: Vc<Box<dyn Module>>,
context: Vc<ModuleAssetContext>,
) -> Result<Vc<Box<dyn Module>>> {
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(
internal_asset,
Value::new(ReferenceType::Internal(InnerAssetsVc::cell(indexmap! {
"PAGE".to_string() => asset.into()
Value::new(ReferenceType::Internal(Vc::cell(indexmap! {
"PAGE".to_string() => Vc::upcast(asset)
}))),
)
} else {
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");
};
let runtime_entries = self.runtime_entries.resolve_entries(context.into());
let runtime_entries = self.runtime_entries.resolve_entries(Vc::upcast(context));
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
// 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,
runtime_entries: Some(runtime_entries),
};
Ok(asset.cell().into())
Ok(Vc::upcast(asset.cell()))
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,33 +1,31 @@
use anyhow::{bail, Result};
use turbo_tasks::Value;
use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{
core::{
module::ModuleVc,
module::Module,
reference_type::{CssReferenceSubType, ReferenceType},
resolve::ModulePartVc,
source::SourceVc,
resolve::ModulePart,
source::Source,
},
turbopack::{
css::chunk::CssChunkPlaceableVc,
module_options::{CustomModuleType, CustomModuleTypeVc},
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
css::chunk::CssChunkPlaceable, module_options::CustomModuleType, transition::Transition,
ModuleAssetContext,
},
};
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
/// asset processing and inject a client reference on the server side.
#[turbo_tasks::value]
pub struct CssClientReferenceModuleType {
client_transition: TransitionVc,
client_transition: Vc<Box<dyn Transition>>,
}
#[turbo_tasks::value_impl]
impl CssClientReferenceModuleTypeVc {
impl CssClientReferenceModuleType {
#[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()
}
}
@ -37,20 +35,22 @@ impl CustomModuleType for CssClientReferenceModuleType {
#[turbo_tasks::function]
async fn create_module(
&self,
source: SourceVc,
context: ModuleAssetContextVc,
_part: Option<ModulePartVc>,
) -> Result<ModuleVc> {
source: Vc<Box<dyn Source>>,
context: Vc<ModuleAssetContext>,
_part: Option<Vc<ModulePart>>,
) -> Result<Vc<Box<dyn Module>>> {
let client_module = self.client_transition.process(
source,
context,
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");
};
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::{
core::reference_type::{CssReferenceSubType, ReferenceType},
turbopack::{
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(
client_transition: TransitionVc,
client_transition: Vc<Box<dyn Transition>>,
) -> ModuleRule {
let module_type = CssClientReferenceModuleTypeVc::new(client_transition);
let module_type = CssClientReferenceModuleType::new(client_transition);
ModuleRule::new_internal(
// 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),
)]),
vec![ModuleRuleEffect::ModuleType(ModuleType::Custom(
module_type.into(),
Vc::upcast(module_type),
))],
)
}

View file

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

View file

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

View file

@ -1,34 +1,34 @@
use anyhow::{bail, Result};
use turbo_tasks::Value;
use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{
core::{
asset::Asset,
module::ModuleVc,
module::Module,
reference_type::{EntryReferenceSubType, ReferenceType},
source::SourceVc,
source::Source,
},
ecmascript::chunk::EcmascriptChunkPlaceableVc,
ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{
transition::{ContextTransitionVc, Transition, TransitionVc},
ModuleAssetContextVc,
transition::{ContextTransition, Transition},
ModuleAssetContext,
},
};
use super::ecmascript_client_reference_proxy_module::EcmascriptClientReferenceProxyModuleVc;
use super::ecmascript_client_reference_proxy_module::EcmascriptClientReferenceProxyModule;
#[turbo_tasks::value(shared)]
pub struct NextEcmascriptClientReferenceTransition {
client_transition: ContextTransitionVc,
ssr_transition: ContextTransitionVc,
client_transition: Vc<ContextTransition>,
ssr_transition: Vc<ContextTransition>,
}
#[turbo_tasks::value_impl]
impl NextEcmascriptClientReferenceTransitionVc {
impl NextEcmascriptClientReferenceTransition {
#[turbo_tasks::function]
pub fn new(
client_transition: ContextTransitionVc,
ssr_transition: ContextTransitionVc,
) -> Self {
client_transition: Vc<ContextTransition>,
ssr_transition: Vc<ContextTransition>,
) -> Vc<Self> {
NextEcmascriptClientReferenceTransition {
client_transition,
ssr_transition,
@ -42,10 +42,10 @@ impl Transition for NextEcmascriptClientReferenceTransition {
#[turbo_tasks::function]
async fn process(
&self,
source: SourceVc,
context: ModuleAssetContextVc,
source: Vc<Box<dyn Source>>,
context: Vc<ModuleAssetContext>,
_reference_type: Value<ReferenceType>,
) -> Result<ModuleVc> {
) -> Result<Vc<Box<dyn Module>>> {
let client_module = self.client_transition.process(
source,
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 {
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");
};
// TODO(alexkirsz) This is necessary to remove the transition currently set on
// the context.
let context = context.await?;
let server_context = ModuleAssetContextVc::new(
let server_context = ModuleAssetContext::new(
context.transitions,
context.compile_time_info,
context.module_options_context,
context.resolve_options_context,
);
Ok(EcmascriptClientReferenceProxyModuleVc::new(
Ok(Vc::upcast(EcmascriptClientReferenceProxyModule::new(
source.ident(),
server_context.into(),
Vc::upcast(server_context),
client_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 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::{
ecmascript_client_reference_module::EcmascriptClientReferenceModuleVc,
ecmascript_client_reference_transition::NextEcmascriptClientReferenceTransitionVc,
};
pub use visit_client_reference::{
ClientReference, ClientReferenceType, ClientReferencesByEntry, ClientReferencesByEntryVc,
ecmascript_client_reference_module::EcmascriptClientReferenceModule,
ecmascript_client_reference_transition::NextEcmascriptClientReferenceTransition,
};
pub use visit_client_reference::{ClientReference, ClientReferenceType, ClientReferencesByEntry};

View file

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

View file

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

View file

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

View file

@ -1,27 +1,27 @@
use anyhow::Result;
use turbo_tasks::Value;
use turbo_tasks::{Value, Vc};
use turbopack_binding::turbopack::{
core::{module::ModuleVc, reference_type::ReferenceType, source::SourceVc},
core::{module::Module, reference_type::ReferenceType, source::Source},
turbopack::{
transition::{ContextTransitionVc, Transition, TransitionVc},
ModuleAssetContextVc,
transition::{ContextTransition, Transition},
ModuleAssetContext,
},
};
use super::NextDynamicEntryModuleVc;
use super::NextDynamicEntryModule;
/// 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
/// create the dynamic entry, and the dynamic manifest entry.
#[turbo_tasks::value]
pub struct NextDynamicTransition {
client_transition: ContextTransitionVc,
client_transition: Vc<ContextTransition>,
}
#[turbo_tasks::value_impl]
impl NextDynamicTransitionVc {
impl NextDynamicTransition {
#[turbo_tasks::function]
pub fn new(client_transition: ContextTransitionVc) -> Self {
pub fn new(client_transition: Vc<ContextTransition>) -> Vc<Self> {
NextDynamicTransition { client_transition }.cell()
}
}
@ -31,14 +31,14 @@ impl Transition for NextDynamicTransition {
#[turbo_tasks::function]
async fn process(
&self,
source: SourceVc,
context: ModuleAssetContextVc,
source: Vc<Box<dyn Source>>,
context: Vc<ModuleAssetContext>,
_reference_type: Value<ReferenceType>,
) -> Result<ModuleVc> {
) -> Result<Vc<Box<dyn Module>>> {
let client_module =
self.client_transition
.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 visit_dynamic;
pub use dynamic_module::NextDynamicEntryModuleVc;
pub use dynamic_transition::NextDynamicTransitionVc;
pub use visit_dynamic::NextDynamicEntriesVc;
pub use dynamic_module::NextDynamicEntryModule;
pub use dynamic_transition::NextDynamicTransition;
pub use visit_dynamic::NextDynamicEntries;

View file

@ -3,22 +3,22 @@ use std::future::Future;
use anyhow::Result;
use turbo_tasks::{
graph::{AdjacencyMap, GraphTraversal, Visit, VisitControlFlow},
TryJoinIterExt,
TryJoinIterExt, Vc,
};
use turbopack_binding::turbopack::core::{
asset::{Asset, AssetVc, AssetsVc},
asset::{Asset, Assets},
reference::AssetReference,
};
use super::NextDynamicEntryModuleVc;
use super::NextDynamicEntryModule;
#[turbo_tasks::value(transparent)]
pub struct NextDynamicEntries(Vec<NextDynamicEntryModuleVc>);
pub struct NextDynamicEntries(Vec<Vc<NextDynamicEntryModule>>);
#[turbo_tasks::value_impl]
impl NextDynamicEntriesVc {
impl NextDynamicEntries {
#[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()
.skip_duplicates()
.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)]
enum VisitDynamicNode {
Dynamic(NextDynamicEntryModuleVc),
Internal(AssetVc),
Dynamic(Vc<NextDynamicEntryModule>),
Internal(Vc<Box<dyn Asset>>),
}
impl Visit<VisitDynamicNode> for VisitDynamic {
@ -77,7 +77,7 @@ impl Visit<VisitDynamicNode> for VisitDynamic {
let node = node.clone();
async move {
let asset = match node {
VisitDynamicNode::Dynamic(dynamic_asset) => dynamic_asset.into(),
VisitDynamicNode::Dynamic(dynamic_asset) => Vc::upcast(dynamic_asset),
VisitDynamicNode::Internal(asset) => asset,
};
@ -97,7 +97,7 @@ impl Visit<VisitDynamicNode> for VisitDynamic {
let referenced_assets = referenced_assets.map(|asset| async move {
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));
}

View file

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

View file

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

View file

@ -1,33 +1,32 @@
use anyhow::Result;
use indexmap::indexmap;
use turbo_tasks::Vc;
use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc,
turbo::tasks_fs::FileSystemPath,
turbopack::{
core::{
chunk::ChunkingContextVc, compile_time_info::CompileTimeInfoVc, module::ModuleVc,
source::SourceVc,
chunk::ChunkingContext, compile_time_info::CompileTimeInfo, module::Module,
source::Source,
},
ecmascript::chunk_group_files_asset::ChunkGroupFilesAsset,
turbopack::{
module_options::ModuleOptionsContextVc,
resolve_options_context::ResolveOptionsContextVc,
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
module_options::ModuleOptionsContext, resolve_options_context::ResolveOptionsContext,
transition::Transition, ModuleAssetContext,
},
},
};
use crate::bootstrap::{route_bootstrap, BootstrapConfigVc};
use crate::bootstrap::route_bootstrap;
#[turbo_tasks::value(shared)]
pub struct NextEdgeRouteTransition {
pub edge_compile_time_info: CompileTimeInfoVc,
pub edge_chunking_context: ChunkingContextVc,
pub edge_module_options_context: Option<ModuleOptionsContextVc>,
pub edge_resolve_options_context: ResolveOptionsContextVc,
pub output_path: FileSystemPathVc,
pub base_path: FileSystemPathVc,
pub bootstrap_asset: SourceVc,
pub edge_compile_time_info: Vc<CompileTimeInfo>,
pub edge_chunking_context: Vc<Box<dyn ChunkingContext>>,
pub edge_module_options_context: Option<Vc<ModuleOptionsContext>>,
pub edge_resolve_options_context: Vc<ResolveOptionsContext>,
pub output_path: Vc<FileSystemPath>,
pub base_path: Vc<FileSystemPath>,
pub bootstrap_asset: Vc<Box<dyn Source>>,
pub entry_name: String,
}
@ -36,50 +35,50 @@ impl Transition for NextEdgeRouteTransition {
#[turbo_tasks::function]
fn process_compile_time_info(
&self,
_compile_time_info: CompileTimeInfoVc,
) -> CompileTimeInfoVc {
_compile_time_info: Vc<CompileTimeInfo>,
) -> Vc<CompileTimeInfo> {
self.edge_compile_time_info
}
#[turbo_tasks::function]
fn process_module_options_context(
&self,
context: ModuleOptionsContextVc,
) -> ModuleOptionsContextVc {
context: Vc<ModuleOptionsContext>,
) -> Vc<ModuleOptionsContext> {
self.edge_module_options_context.unwrap_or(context)
}
#[turbo_tasks::function]
fn process_resolve_options_context(
&self,
_context: ResolveOptionsContextVc,
) -> ResolveOptionsContextVc {
_context: Vc<ResolveOptionsContext>,
) -> Vc<ResolveOptionsContext> {
self.edge_resolve_options_context
}
#[turbo_tasks::function]
async fn process_module(
&self,
asset: ModuleVc,
context: ModuleAssetContextVc,
) -> Result<ModuleVc> {
asset: Vc<Box<dyn Module>>,
context: Vc<ModuleAssetContext>,
) -> Result<Vc<Box<dyn Module>>> {
let new_asset = route_bootstrap(
asset.into(),
context.into(),
Vc::upcast(asset),
Vc::upcast(context),
self.base_path,
self.bootstrap_asset,
BootstrapConfigVc::cell(indexmap! {
Vc::cell(indexmap! {
"NAME".to_string() => self.entry_name.clone(),
}),
);
let asset = ChunkGroupFilesAsset {
module: new_asset.into(),
module: Vc::upcast(new_asset),
client_root: self.output_path,
chunking_context: self.edge_chunking_context,
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 serde::{Deserialize, Serialize};
use turbopack_binding::turbo::tasks::{
primitives::{StringVc, StringsVc},
trace::TraceRawVcs,
};
use turbo_tasks::Vc;
use turbopack_binding::turbo::tasks::trace::TraceRawVcs;
pub(crate) struct DefaultFallbackFont {
pub name: String,
@ -34,9 +31,9 @@ pub(crate) static DEFAULT_SERIF_FONT: Lazy<DefaultFallbackFont> =
#[turbo_tasks::value(shared)]
pub(crate) struct AutomaticFontFallback {
/// 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("{}")`
pub local_font_family: StringVc,
pub local_font_family: Vc<String>,
pub adjustment: Option<FontAdjustment>,
}
@ -45,17 +42,17 @@ pub(crate) struct AutomaticFontFallback {
pub(crate) enum FontFallback {
/// An automatically generated fallback font generated by next/font. May
/// include an optional [[FontAdjustment]].
Automatic(AutomaticFontFallbackVc),
Automatic(Vc<AutomaticFontFallback>),
/// There was an issue preparing the font fallback. Since resolving the
/// font css cannot fail, proper Errors cannot be returned. Emit an issue,
/// return this and omit fallback information instead.
Error,
/// A list of manually provided font names to use a fallback, as-is.
Manual(StringsVc),
Manual(Vc<Vec<String>>),
}
#[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
/// 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 regex::Regex;
use serde::{Deserialize, Serialize};
use turbo_tasks::{
primitives::{StringVc, StringsVc, U32Vc},
trace::TraceRawVcs,
use turbo_tasks::{trace::TraceRawVcs, Vc};
use turbopack_binding::{
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::{
next_font::{
font_fallback::{
AutomaticFontFallback, FontAdjustment, FontFallback, FontFallbackVc,
DEFAULT_SANS_SERIF_FONT, DEFAULT_SERIF_FONT,
AutomaticFontFallback, FontAdjustment, FontFallback, DEFAULT_SANS_SERIF_FONT,
DEFAULT_SERIF_FONT,
},
issue::NextFontIssue,
util::{get_scoped_font_family, FontFamilyType},
@ -46,13 +46,13 @@ struct Fallback {
#[turbo_tasks::function]
pub(super) async fn get_font_fallback(
context: FileSystemPathVc,
options_vc: NextFontGoogleOptionsVc,
request_hash: U32Vc,
) -> Result<FontFallbackVc> {
context: Vc<FileSystemPath>,
options_vc: Vc<NextFontGoogleOptions>,
request_hash: Vc<u32>,
) -> Result<Vc<FontFallback>> {
let options = options_vc.await?;
Ok(match &options.fallback {
Some(fallback) => FontFallback::Manual(StringsVc::cell(fallback.clone())).cell(),
Some(fallback) => FontFallback::Manual(Vc::cell(fallback.clone())).cell(),
None => {
let metrics_json =
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(),
request_hash,
),
local_font_family: StringVc::cell(fallback.font_family),
local_font_family: Vc::cell(fallback.font_family),
adjustment: fallback.adjustment,
}
.cell(),
@ -79,17 +79,14 @@ pub(super) async fn get_font_fallback(
Err(_) => {
NextFontIssue {
path: context,
title: StringVc::cell(format!(
title: Vc::cell(format!(
"Failed to find font override values for font `{}`",
&options.font_family,
)),
description: StringVc::cell(
"Skipping generating a fallback font.".to_owned(),
),
description: Vc::cell("Skipping generating a fallback font.".to_owned()),
severity: IssueSeverity::Warning.cell(),
}
.cell()
.as_issue()
.emit();
FontFallback::Error.cell()
}

View file

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

View file

@ -1,7 +1,8 @@
use anyhow::{anyhow, Context, Result};
use indexmap::{indexset, IndexMap, IndexSet};
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};
@ -28,15 +29,15 @@ pub(super) struct NextFontGoogleOptions {
}
#[turbo_tasks::value_impl]
impl NextFontGoogleOptionsVc {
impl NextFontGoogleOptions {
#[turbo_tasks::function]
pub fn new(options: Value<NextFontGoogleOptions>) -> NextFontGoogleOptionsVc {
pub fn new(options: Value<NextFontGoogleOptions>) -> Vc<NextFontGoogleOptions> {
Self::cell(options.into_value())
}
#[turbo_tasks::function]
pub async fn font_family(self) -> Result<StringVc> {
Ok(StringVc::cell((*self.await?.font_family).to_owned()))
pub async fn font_family(self: Vc<Self>) -> Result<Vc<String>> {
Ok(Vc::cell((*self.await?.font_family).to_owned()))
}
}

View file

@ -1,25 +1,24 @@
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::{
font_fallback::{FontFallbackVc, FontFallbacksVc},
font_fallback::FontFallback,
stylesheet::{build_fallback_definition, build_font_class_rules},
};
#[turbo_tasks::function]
pub(super) async fn build_stylesheet(
base_stylesheet: OptionStringVc,
font_css_properties: FontCssPropertiesVc,
font_fallback: FontFallbackVc,
) -> Result<StringVc> {
base_stylesheet: Vc<Option<String>>,
font_css_properties: Vc<FontCssProperties>,
font_fallback: Vc<FontFallback>,
) -> Result<Vc<String>> {
let base_stylesheet = &*base_stylesheet.await?;
let mut stylesheet = base_stylesheet
.as_ref()
.map_or_else(|| "".to_owned(), |s| s.to_owned());
stylesheet
.push_str(&build_fallback_definition(FontFallbacksVc::cell(vec![font_fallback])).await?);
stylesheet.push_str(&build_fallback_definition(Vc::cell(vec![font_fallback])).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::{
turbo::tasks_fs::FileSystemPathVc,
turbopack::core::issue::{Issue, IssueSeverityVc, IssueVc},
turbo::tasks_fs::FileSystemPath,
turbopack::core::issue::{Issue, IssueSeverity},
};
#[turbo_tasks::value(shared)]
pub(crate) struct NextFontIssue {
pub(crate) path: FileSystemPathVc,
pub(crate) title: StringVc,
pub(crate) description: StringVc,
pub(crate) severity: IssueSeverityVc,
pub(crate) path: Vc<FileSystemPath>,
pub(crate) title: Vc<String>,
pub(crate) description: Vc<String>,
pub(crate) severity: Vc<IssueSeverity>,
}
#[turbo_tasks::value_impl]
impl Issue for NextFontIssue {
#[turbo_tasks::function]
fn category(&self) -> StringVc {
StringVc::cell("other".to_string())
fn category(&self) -> Vc<String> {
Vc::cell("other".to_string())
}
#[turbo_tasks::function]
fn severity(&self) -> IssueSeverityVc {
fn severity(&self) -> Vc<IssueSeverity> {
self.severity
}
#[turbo_tasks::function]
fn context(&self) -> FileSystemPathVc {
fn context(&self) -> Vc<FileSystemPath> {
self.path
}
#[turbo_tasks::function]
fn title(&self) -> StringVc {
fn title(&self) -> Vc<String> {
self.title
}
#[turbo_tasks::function]
fn description(&self) -> StringVc {
fn description(&self) -> Vc<String> {
self.description
}
}

View file

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

View file

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

View file

@ -1,28 +1,28 @@
use anyhow::{bail, Result};
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::{
font_fallback::FontFallbacksVc,
font_fallback::FontFallbacks,
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]
pub(super) async fn build_stylesheet(
options: NextFontLocalOptionsVc,
fallbacks: FontFallbacksVc,
css_properties: FontCssPropertiesVc,
request_hash: U32Vc,
) -> Result<StringVc> {
options: Vc<NextFontLocalOptions>,
fallbacks: Vc<FontFallbacks>,
css_properties: Vc<FontCssProperties>,
request_hash: Vc<u32>,
) -> Result<Vc<String>> {
let scoped_font_family = get_scoped_font_family(
FontFamilyType::WebFont.cell(),
options.font_family(),
request_hash,
);
Ok(StringVc::cell(formatdoc!(
Ok(Vc::cell(formatdoc!(
r#"
{}
{}
@ -37,9 +37,9 @@ pub(super) async fn build_stylesheet(
/// Builds a string of `@font-face` definitions for each local font file
#[turbo_tasks::function]
pub(super) async fn build_font_face_definitions(
scoped_font_family: StringVc,
options: NextFontLocalOptionsVc,
) -> Result<StringVc> {
scoped_font_family: Vc<String>,
options: Vc<NextFontLocalOptions>,
) -> Result<Vc<String>> {
let options = &*options.await?;
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`

View file

@ -1,19 +1,19 @@
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::{
font_fallback::{FontFallback, FontFallbacksVc},
font_fallback::{FontFallback, FontFallbacks},
util::{get_scoped_font_family, FontFamilyType},
};
/// Returns a string to be used as the `font-family` property in css.
#[turbo_tasks::function]
pub(super) async fn build_font_family_string(
options: NextFontLocalOptionsVc,
font_fallbacks: FontFallbacksVc,
request_hash: U32Vc,
) -> Result<StringVc> {
options: Vc<NextFontLocalOptions>,
font_fallbacks: Vc<FontFallbacks>,
request_hash: Vc<u32>,
) -> Result<Vc<String>> {
let mut font_families = vec![format!(
"'{}'",
*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 indoc::formatdoc;
use turbopack_binding::turbo::tasks::primitives::StringVc;
use turbo_tasks::Vc;
use super::{
font_fallback::{FontFallback, FontFallbacksVc},
util::FontCssPropertiesVc,
font_fallback::{FontFallback, FontFallbacks},
util::FontCssProperties,
};
/// Builds `@font-face` stylesheet definition for a given FontFallback
#[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();
for fallback_vc in &*fallbacks.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]
pub(super) async fn build_font_class_rules(
css_properties: FontCssPropertiesVc,
) -> Result<StringVc> {
css_properties: Vc<FontCssProperties>,
) -> Result<Vc<String>> {
let css_properties = &*css_properties.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 {

View file

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

View file

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

View file

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

View file

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

View file

@ -1,30 +1,28 @@
use std::io::Write;
use anyhow::{bail, Result};
use turbo_tasks::Vc;
use turbopack_binding::{
turbo::{
tasks::primitives::StringVc,
tasks_fs::{rope::RopeBuilder, FileContent},
},
turbo::tasks_fs::{rope::RopeBuilder, FileContent},
turbopack::{
core::{
asset::{Asset, AssetContent, AssetContentVc, AssetVc},
ident::AssetIdentVc,
source::{Source, SourceVc},
asset::{Asset, AssetContent},
ident::AssetIdent,
source::Source,
},
ecmascript::utils::StringifyJs,
image::process::{get_meta_data, BlurPlaceholderOptions, BlurPlaceholderOptionsVc},
image::process::{get_meta_data, BlurPlaceholderOptions},
},
};
use super::module::BlurPlaceholderMode;
fn modifier() -> StringVc {
StringVc::cell("structured image object".to_string())
fn modifier() -> Vc<String> {
Vc::cell("structured image object".to_string())
}
#[turbo_tasks::function]
fn blur_options() -> BlurPlaceholderOptionsVc {
fn blur_options() -> Vc<BlurPlaceholderOptions> {
BlurPlaceholderOptions {
quality: 70,
size: 8,
@ -36,7 +34,7 @@ fn blur_options() -> BlurPlaceholderOptionsVc {
/// an object with meta information like width, height and a blur placeholder.
#[turbo_tasks::value(shared)]
pub struct StructuredImageFileSource {
pub image: SourceVc,
pub image: Vc<Box<dyn Source>>,
pub blur_placeholder_mode: BlurPlaceholderMode,
}
@ -46,15 +44,15 @@ impl Source for StructuredImageFileSource {}
#[turbo_tasks::value_impl]
impl Asset for StructuredImageFileSource {
#[turbo_tasks::function]
fn ident(&self) -> AssetIdentVc {
fn ident(&self) -> Vc<AssetIdent> {
self.image
.ident()
.with_modifier(modifier())
.rename_as("*.mjs")
.rename_as("*.mjs".to_string())
}
#[turbo_tasks::function]
async fn content(&self) -> Result<AssetContentVc> {
async fn content(&self) -> Result<Vc<AssetContent>> {
let content = self.image.content().await?;
let AssetContent::File(content) = *content else {
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 anyhow::{Context, Result};
use turbo_tasks::Value;
use turbo_tasks::{Value, Vc};
use turbopack_binding::{
turbo::tasks_fs::{glob::GlobVc, FileSystem, FileSystemPathVc},
turbo::tasks_fs::{glob::Glob, FileSystem, FileSystemPath},
turbopack::{
core::{
asset::Asset,
resolve::{
options::{
ConditionValue, ImportMap, ImportMapVc, ImportMapping, ImportMappingVc,
ResolveOptionsVc, ResolvedMap, ResolvedMapVc,
},
parse::RequestVc,
options::{ConditionValue, ImportMap, ImportMapping, ResolveOptions, ResolvedMap},
parse::Request,
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},
},
};
@ -26,10 +23,10 @@ use crate::{
embed_js::{next_js_fs, VIRTUAL_PACKAGE_NAME},
mode::NextMode,
next_client::context::ClientContextType,
next_config::NextConfigVc,
next_config::NextConfig,
next_font::{
google::{NextFontGoogleCssModuleReplacerVc, NextFontGoogleReplacerVc},
local::{NextFontLocalCssModuleReplacerVc, NextFontLocalReplacerVc},
google::{NextFontGoogleCssModuleReplacer, NextFontGoogleReplacer},
local::{NextFontLocalCssModuleReplacer, NextFontLocalReplacer},
},
next_server::context::ServerContextType,
};
@ -38,11 +35,11 @@ use crate::{
/// Computes the Next-specific client import map.
#[turbo_tasks::function]
pub async fn get_next_client_import_map(
project_path: FileSystemPathVc,
project_path: Vc<FileSystemPath>,
ty: Value<ClientContextType>,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ImportMapVc> {
next_config: Vc<NextConfig>,
execution_context: Vc<ExecutionContext>,
) -> Result<Vc<ImportMap>> {
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(
@ -139,7 +136,7 @@ pub async fn get_next_client_import_map(
/// Computes the Next-specific client import map.
#[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();
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
/// polyfills to Node.js externals.
#[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();
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.
#[turbo_tasks::function]
pub async fn get_next_server_import_map(
project_path: FileSystemPathVc,
project_path: Vc<FileSystemPath>,
ty: Value<ServerContextType>,
mode: NextMode,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ImportMapVc> {
next_config: Vc<NextConfig>,
execution_context: Vc<ExecutionContext>,
) -> Result<Vc<ImportMap>> {
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(
@ -253,12 +250,12 @@ pub async fn get_next_server_import_map(
/// Computes the Next-specific edge-side import map.
#[turbo_tasks::function]
pub async fn get_next_edge_import_map(
project_path: FileSystemPathVc,
project_path: Vc<FileSystemPath>,
ty: Value<ServerContextType>,
mode: NextMode,
next_config: NextConfigVc,
execution_context: ExecutionContextVc,
) -> Result<ImportMapVc> {
next_config: Vc<NextConfig>,
execution_context: Vc<ExecutionContext>,
) -> Result<Vc<ImportMap>> {
let mut import_map = ImportMap::empty();
insert_next_shared_aliases(
@ -302,14 +299,17 @@ pub async fn get_next_edge_import_map(
}
pub fn get_next_client_resolved_map(
context: FileSystemPathVc,
root: FileSystemPathVc,
) -> ResolvedMapVc {
context: Vc<FileSystemPath>,
root: Vc<FileSystemPath>,
) -> Vc<ResolvedMap> {
let glob_mappings = vec![
// Temporary hack to replace the hot reloader until this is passable by props in next.js
(
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(
"@vercel/turbopack-next/dev/hot-reloader.tsx".to_string(),
Some(root),
@ -515,9 +515,9 @@ pub fn mdx_import_source_file() -> String {
// Make sure to not add any external requests here.
pub async fn insert_next_shared_aliases(
import_map: &mut ImportMap,
project_path: FileSystemPathVc,
execution_context: ExecutionContextVc,
next_config: NextConfigVc,
project_path: Vc<FileSystemPath>,
execution_context: Vc<ExecutionContext>,
next_config: Vc<NextConfig>,
) -> Result<()> {
let package_root = next_js_fs().root();
@ -549,38 +549,42 @@ pub async fn insert_next_shared_aliases(
import_map.insert_alias(
// Request path from js via next-font swc transform
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(
// Request path from js via next-font swc transform
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(
AliasPattern::exact("@vercel/turbopack-next/internal/font/google/cssmodule.module.css"),
ImportMapping::Dynamic(
NextFontGoogleCssModuleReplacerVc::new(project_path, execution_context).into(),
)
ImportMapping::Dynamic(Vc::upcast(NextFontGoogleCssModuleReplacer::new(
project_path,
execution_context,
)))
.into(),
);
import_map.insert_alias(
// Request path from js via next-font swc transform
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(
// Request path from js via next-font swc transform
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(
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));
@ -601,8 +605,8 @@ pub async fn insert_next_shared_aliases(
#[turbo_tasks::function]
async fn package_lookup_resolve_options(
project_path: FileSystemPathVc,
) -> Result<ResolveOptionsVc> {
project_path: Vc<FileSystemPath>,
) -> Result<Vc<ResolveOptions>> {
Ok(resolve_options(
project_path,
ResolveOptionsContext {
@ -616,10 +620,10 @@ async fn package_lookup_resolve_options(
}
#[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(
project_path,
RequestVc::parse(Value::new(Pattern::Constant(
Request::parse(Value::new(Pattern::Constant(
"next/package.json".to_string(),
))),
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>(
import_map: &mut ImportMap,
project_path: FileSystemPathVc,
alias_options: ResolveAliasMapVc,
project_path: Vc<FileSystemPath>,
alias_options: Vc<ResolveAliasMap>,
conditions: [&'static str; N],
) -> Result<()> {
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(
value: &SubpathValue,
conditions: &BTreeMap<String, ConditionValue>,
project_path: FileSystemPathVc,
) -> Option<ImportMappingVc> {
project_path: Vc<FileSystemPath>,
) -> Option<Vc<ImportMapping>> {
let mut result = Vec::new();
value.add_results(
conditions,
@ -679,13 +683,17 @@ fn export_value_to_import_mapping(
fn insert_alias_to_alternatives<'a>(
import_map: &mut ImportMap,
alias: impl Into<String> + 'a,
alternatives: Vec<ImportMappingVc>,
alternatives: Vec<Vc<ImportMapping>>,
) {
import_map.insert_exact_alias(alias, ImportMapping::Alternatives(alternatives).into());
}
/// 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(
prefix,
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
/// 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()
}
/// Creates a direct import mapping to the result of resolving an external
/// 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()
}

View file

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

View file

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

View file

@ -1,8 +1,8 @@
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use turbopack_binding::{
turbo::tasks::primitives::{BoolVc, Regex},
turbopack::node::route_matcher::{Param, ParamsVc, RouteMatcher},
turbo::tasks::primitives::Regex,
turbopack::node::route_matcher::{Param, Params, RouteMatcherRef},
};
/// 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 {
fn matches(&self, path: &str) -> BoolVc {
BoolVc::cell(self.regex.is_match(path))
impl RouteMatcherRef for PathRegex {
fn matches(&self, path: &str) -> bool {
self.regex.is_match(path)
}
fn params(&self, path: &str) -> ParamsVc {
ParamsVc::cell(self.regex.captures(path).map(|capture| {
fn params(&self, path: &str) -> Params {
Params(self.regex.captures(path).map(|capture| {
self.named_params
.iter()
.enumerate()

View file

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

View file

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

View file

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

View file

@ -1,11 +1,12 @@
use anyhow::Result;
use next_transform_strip_page_exports::ExportFilter;
use turbo_tasks::Vc;
use turbopack_binding::turbopack::turbopack::module_options::ModuleRule;
use crate::{
mode::NextMode,
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_shared::transforms::{
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
/// transforms.
pub async fn get_next_server_transforms_rules(
next_config: NextConfigVc,
next_config: Vc<NextConfig>,
context_ty: ServerContextType,
mode: NextMode,
) -> 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_transition;
pub use server_component_transition::NextServerComponentTransitionVc;
pub use server_component_transition::NextServerComponentTransition;

View file

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

View file

@ -1,23 +1,21 @@
use anyhow::Result;
use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc};
use turbo_tasks::{ValueToString, Vc};
use turbopack_binding::turbopack::core::{
asset::{Asset, AssetVc},
chunk::{
ChunkableModuleReference, ChunkableModuleReferenceVc, ChunkingType, ChunkingTypeOptionVc,
},
reference::{AssetReference, AssetReferenceVc},
resolve::{ResolveResult, ResolveResultVc},
asset::Asset,
chunk::{ChunkableModuleReference, ChunkingType, ChunkingTypeOption},
reference::AssetReference,
resolve::ResolveResult,
};
#[turbo_tasks::value]
pub struct NextServerComponentModuleReference {
asset: AssetVc,
asset: Vc<Box<dyn Asset>>,
}
#[turbo_tasks::value_impl]
impl NextServerComponentModuleReferenceVc {
impl NextServerComponentModuleReference {
#[turbo_tasks::function]
pub fn new(asset: AssetVc) -> Self {
pub fn new(asset: Vc<Box<dyn Asset>>) -> Vc<Self> {
NextServerComponentModuleReference { asset }.cell()
}
}
@ -25,8 +23,8 @@ impl NextServerComponentModuleReferenceVc {
#[turbo_tasks::value_impl]
impl ValueToString for NextServerComponentModuleReference {
#[turbo_tasks::function]
async fn to_string(&self) -> Result<StringVc> {
Ok(StringVc::cell(format!(
async fn to_string(&self) -> Result<Vc<String>> {
Ok(Vc::cell(format!(
"Next.js server component {}",
self.asset.ident().to_string().await?
)))
@ -36,7 +34,7 @@ impl ValueToString for NextServerComponentModuleReference {
#[turbo_tasks::value_impl]
impl AssetReference for NextServerComponentModuleReference {
#[turbo_tasks::function]
fn resolve_reference(&self) -> ResolveResultVc {
fn resolve_reference(&self) -> Vc<ResolveResult> {
ResolveResult::asset(self.asset).cell()
}
}
@ -44,9 +42,9 @@ impl AssetReference for NextServerComponentModuleReference {
#[turbo_tasks::value_impl]
impl ChunkableModuleReference for NextServerComponentModuleReference {
#[turbo_tasks::function]
fn chunking_type(&self) -> ChunkingTypeOptionVc {
fn chunking_type(&self) -> Vc<ChunkingTypeOption> {
// TODO(alexkirsz) Instead of isolated parallel, have the server component
// 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 turbo_tasks::Vc;
use turbopack_binding::turbopack::{
core::module::ModuleVc,
ecmascript::chunk::EcmascriptChunkPlaceableVc,
turbopack::{
transition::{Transition, TransitionVc},
ModuleAssetContextVc,
},
core::module::Module,
ecmascript::chunk::EcmascriptChunkPlaceable,
turbopack::{transition::Transition, ModuleAssetContext},
};
use super::server_component_module::NextServerComponentModuleVc;
use super::server_component_module::NextServerComponentModule;
/// This transition wraps a module into a marker
/// [`NextServerComponentModuleVc`].
/// [`Vc<NextServerComponentModule>`].
///
/// When walking the module graph to build the client reference manifest, this
/// 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 {}
#[turbo_tasks::value_impl]
impl NextServerComponentTransitionVc {
/// Creates a new [`NextServerComponentTransitionVc`].
impl NextServerComponentTransition {
/// Creates a new [`Vc<NextServerComponentTransition>`].
#[turbo_tasks::function]
pub fn new() -> Self {
pub fn new() -> Vc<Self> {
NextServerComponentTransition {}.cell()
}
}
@ -32,14 +30,16 @@ impl NextServerComponentTransitionVc {
impl Transition for NextServerComponentTransition {
#[turbo_tasks::function]
async fn process_module(
_self_vc: NextServerComponentTransitionVc,
module: ModuleVc,
_context: ModuleAssetContextVc,
) -> Result<ModuleVc> {
let Some(module) = EcmascriptChunkPlaceableVc::resolve_from(module).await? else {
self: Vc<Self>,
module: Vc<Box<dyn Module>>,
_context: Vc<ModuleAssetContext>,
) -> Result<Vc<Box<dyn Module>>> {
let Some(module) =
Vc::try_resolve_sidecast::<Box<dyn EcmascriptChunkPlaceable>>(module).await?
else {
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 lazy_static::lazy_static;
use turbo_tasks_fs::glob::GlobVc;
use turbo_tasks::Vc;
use turbo_tasks_fs::glob::Glob;
use turbopack_binding::{
turbo::tasks_fs::FileSystemPathVc,
turbo::tasks_fs::FileSystemPath,
turbopack::core::{
issue::unsupported_module::UnsupportedModuleIssue,
issue::{unsupported_module::UnsupportedModuleIssue, IssueExt},
resolve::{
parse::{Request, RequestVc},
parse::Request,
pattern::Pattern,
plugin::{ResolvePlugin, ResolvePluginConditionVc, ResolvePluginVc},
ResolveResultOptionVc,
plugin::{ResolvePlugin, ResolvePluginCondition},
ResolveResultOption,
},
},
};
@ -23,13 +24,13 @@ lazy_static! {
#[turbo_tasks::value]
pub(crate) struct UnsupportedModulesResolvePlugin {
root: FileSystemPathVc,
root: Vc<FileSystemPath>,
}
#[turbo_tasks::value_impl]
impl UnsupportedModulesResolvePluginVc {
impl UnsupportedModulesResolvePlugin {
#[turbo_tasks::function]
pub fn new(root: FileSystemPathVc) -> Self {
pub fn new(root: Vc<FileSystemPath>) -> Vc<Self> {
UnsupportedModulesResolvePlugin { root }.cell()
}
}
@ -37,17 +38,17 @@ impl UnsupportedModulesResolvePluginVc {
#[turbo_tasks::value_impl]
impl ResolvePlugin for UnsupportedModulesResolvePlugin {
#[turbo_tasks::function]
fn after_resolve_condition(&self) -> ResolvePluginConditionVc {
ResolvePluginConditionVc::new(self.root.root(), GlobVc::new("**"))
fn after_resolve_condition(&self) -> Vc<ResolvePluginCondition> {
ResolvePluginCondition::new(self.root.root(), Glob::new("**".to_string()))
}
#[turbo_tasks::function]
async fn after_resolve(
&self,
_fs_path: FileSystemPathVc,
context: FileSystemPathVc,
request: RequestVc,
) -> Result<ResolveResultOptionVc> {
_fs_path: Vc<FileSystemPath>,
context: Vc<FileSystemPath>,
request: Vc<Request>,
) -> Result<Vc<ResolveResultOption>> {
if let Request::Module {
module,
path,
@ -62,7 +63,6 @@ impl ResolvePlugin for UnsupportedModulesResolvePlugin {
package_path: None,
}
.cell()
.as_issue()
.emit();
}
@ -74,12 +74,11 @@ impl ResolvePlugin for UnsupportedModulesResolvePlugin {
package_path: Some(path.to_owned()),
}
.cell()
.as_issue()
.emit();
}
}
}
Ok(ResolveResultOptionVc::none())
Ok(ResolveResultOption::none())
}
}

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