diff --git a/crates/turbopack-build/src/chunking_context.rs b/crates/turbopack-build/src/chunking_context.rs index 5ada231b4a6c37..ca2d81bf352968 100644 --- a/crates/turbopack-build/src/chunking_context.rs +++ b/crates/turbopack-build/src/chunking_context.rs @@ -114,7 +114,7 @@ impl BuildChunkingContextVc { /// * exports the result of evaluating the given module as a CommonJS /// default export. #[turbo_tasks::function] - pub async fn generate_entry_chunk( + pub async fn entry_chunk( self_vc: BuildChunkingContextVc, path: FileSystemPathVc, module: EcmascriptChunkPlaceableVc, @@ -129,7 +129,6 @@ impl BuildChunkingContextVc { let asset = EcmascriptBuildNodeEntryChunkVc::new( path, self_vc, - entry_chunk, AssetsVc::cell(other_chunks), evaluatable_assets, module, diff --git a/crates/turbopack-build/src/ecmascript/node/entry/chunk.rs b/crates/turbopack-build/src/ecmascript/node/entry/chunk.rs index f1f747d952dda1..2b573d8a18c14b 100644 --- a/crates/turbopack-build/src/ecmascript/node/entry/chunk.rs +++ b/crates/turbopack-build/src/ecmascript/node/entry/chunk.rs @@ -6,7 +6,7 @@ use turbo_tasks::{primitives::StringVc, ValueToString, ValueToStringVc}; use turbo_tasks_fs::{File, FileSystemPathVc}; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc, AssetsVc}, - chunk::{ChunkVc, ChunkingContext, EvaluatableAssetsVc}, + chunk::{ChunkingContext, EvaluatableAssetsVc}, code_builder::{CodeBuilder, CodeVc}, ident::AssetIdentVc, reference::{AssetReferencesVc, SingleAssetReferenceVc}, @@ -28,7 +28,6 @@ use crate::BuildChunkingContextVc; pub(crate) struct EcmascriptBuildNodeEntryChunk { path: FileSystemPathVc, chunking_context: BuildChunkingContextVc, - entry_chunk: ChunkVc, other_chunks: AssetsVc, evaluatable_assets: EvaluatableAssetsVc, exported_module: EcmascriptChunkPlaceableVc, @@ -41,7 +40,6 @@ impl EcmascriptBuildNodeEntryChunkVc { pub fn new( path: FileSystemPathVc, chunking_context: BuildChunkingContextVc, - entry_chunk: ChunkVc, other_chunks: AssetsVc, evaluatable_assets: EvaluatableAssetsVc, exported_module: EcmascriptChunkPlaceableVc, @@ -49,7 +47,6 @@ impl EcmascriptBuildNodeEntryChunkVc { EcmascriptBuildNodeEntryChunk { path, chunking_context, - entry_chunk, other_chunks, evaluatable_assets, exported_module, diff --git a/crates/turbopack-css/src/chunk/mod.rs b/crates/turbopack-css/src/chunk/mod.rs index 8d4efc0dfcdc51..6c3730243f21ae 100644 --- a/crates/turbopack-css/src/chunk/mod.rs +++ b/crates/turbopack-css/src/chunk/mod.rs @@ -12,7 +12,7 @@ use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc, AssetsVc}, chunk::{ availability_info::AvailabilityInfo, chunk_content, chunk_content_split, Chunk, - ChunkContentResult, ChunkGroupReferenceVc, ChunkItem, ChunkItemVc, ChunkVc, + ChunkContentResult, ChunkGroupReferenceVc, ChunkItem, ChunkItemVc, ChunkVc, ChunkableAsset, ChunkableAssetVc, ChunkingContext, ChunkingContextVc, ChunksVc, FromChunkableAsset, ModuleId, ModuleIdVc, ModuleIdsVc, OutputChunk, OutputChunkRuntimeInfo, OutputChunkRuntimeInfoVc, OutputChunkVc, @@ -467,7 +467,7 @@ impl CssChunkContextVc { } #[turbo_tasks::value_trait] -pub trait CssChunkPlaceable: Asset { +pub trait CssChunkPlaceable: ChunkableAsset + Asset { fn as_chunk_item(&self, context: ChunkingContextVc) -> CssChunkItemVc; } diff --git a/crates/turbopack-dev/src/chunking_context.rs b/crates/turbopack-dev/src/chunking_context.rs index dcf68b406dbef1..0f259dea1cca75 100644 --- a/crates/turbopack-dev/src/chunking_context.rs +++ b/crates/turbopack-dev/src/chunking_context.rs @@ -41,6 +41,12 @@ impl DevChunkingContextBuilder { self } + pub fn chunk_base_path(mut self, chunk_base_path: &str) -> Self { + self.context.chunk_base_path = + (!chunk_base_path.is_empty()).then(|| chunk_base_path.to_string()); + self + } + pub fn layer(mut self, layer: &str) -> Self { self.context.layer = (!layer.is_empty()).then(|| layer.to_string()); self @@ -61,8 +67,8 @@ impl DevChunkingContextBuilder { self } - pub fn build(self) -> ChunkingContextVc { - DevChunkingContextVc::new(Value::new(self.context)).into() + pub fn build(self) -> DevChunkingContextVc { + DevChunkingContextVc::new(Value::new(self.context)) } } @@ -87,6 +93,9 @@ pub struct DevChunkingContext { reference_css_chunk_source_maps: bool, /// Static assets are placed at this path asset_root_path: FileSystemPathVc, + /// Base path that will be prepended to all chunk URLs when loading them. + /// This path will not appear in chunk paths or chunk data. + chunk_base_path: Option, /// Layer name within this context layer: Option, /// Enable HMR for this chunking @@ -113,6 +122,7 @@ impl DevChunkingContextVc { reference_chunk_source_maps: true, reference_css_chunk_source_maps: true, asset_root_path, + chunk_base_path: None, layer: None, enable_hot_module_replacement: false, environment, @@ -130,6 +140,11 @@ impl DevChunkingContext { pub fn runtime_type(&self) -> RuntimeType { self.runtime_type } + + /// Returns the chunk public path. + pub fn chunk_base_path(&self) -> Option<&String> { + self.chunk_base_path.as_ref() + } } #[turbo_tasks::value_impl] diff --git a/crates/turbopack-dev/src/ecmascript/evaluate/chunk.rs b/crates/turbopack-dev/src/ecmascript/evaluate/chunk.rs index 3dd90e16f9ddc6..3e2fad515ca755 100644 --- a/crates/turbopack-dev/src/ecmascript/evaluate/chunk.rs +++ b/crates/turbopack-dev/src/ecmascript/evaluate/chunk.rs @@ -3,7 +3,10 @@ use std::io::Write; use anyhow::{bail, Result}; use indoc::writedoc; use serde::Serialize; -use turbo_tasks::{primitives::StringVc, TryJoinIterExt, Value, ValueToString, ValueToStringVc}; +use turbo_tasks::{ + primitives::{OptionStringVc, StringVc}, + TryJoinIterExt, Value, ValueToString, ValueToStringVc, +}; use turbo_tasks_fs::File; use turbopack_core::{ asset::{Asset, AssetContentVc, AssetVc, AssetsVc}, @@ -67,6 +70,7 @@ impl EcmascriptDevEvaluateChunkVc { #[turbo_tasks::function] async fn code(self) -> Result { let this = self.await?; + let chunking_context = this.chunking_context.await?; let environment = this.chunking_context.environment(); let output_root = this.chunking_context.output_root().await?; @@ -137,9 +141,12 @@ impl EcmascriptDevEvaluateChunkVc { StringifyJs(¶ms), )?; - match this.chunking_context.await?.runtime_type() { + match chunking_context.runtime_type() { RuntimeType::Default => { - let runtime_code = turbopack_ecmascript_runtime::get_dev_runtime_code(environment); + let runtime_code = turbopack_ecmascript_runtime::get_dev_runtime_code( + environment, + OptionStringVc::cell(chunking_context.chunk_base_path().cloned()), + ); code.push_code(&*runtime_code.await?); } #[cfg(feature = "test")] diff --git a/crates/turbopack-ecmascript-plugins/src/transform/directives/client.rs b/crates/turbopack-ecmascript-plugins/src/transform/directives/client.rs index 17863f485f852b..a54e6916973767 100644 --- a/crates/turbopack-ecmascript-plugins/src/transform/directives/client.rs +++ b/crates/turbopack-ecmascript-plugins/src/transform/directives/client.rs @@ -12,10 +12,8 @@ pub struct ClientDirectiveTransformer { } impl ClientDirectiveTransformer { - pub fn new(transition_name: &StringVc) -> Self { - Self { - transition_name: *transition_name, - } + pub fn new(transition_name: StringVc) -> Self { + Self { transition_name } } } diff --git a/crates/turbopack-ecmascript-plugins/src/transform/directives/server_to_client_proxy.rs b/crates/turbopack-ecmascript-plugins/src/transform/directives/server_to_client_proxy.rs index b52c836e19b2a3..c3827f0d9ff2d3 100644 --- a/crates/turbopack-ecmascript-plugins/src/transform/directives/server_to_client_proxy.rs +++ b/crates/turbopack-ecmascript-plugins/src/transform/directives/server_to_client_proxy.rs @@ -2,7 +2,7 @@ use swc_core::{ common::DUMMY_SP, ecma::{ ast::{ - Expr, ExprStmt, Ident, ImportDecl, ImportDefaultSpecifier, ImportSpecifier, + Expr, ExprStmt, Ident, ImportDecl, ImportSpecifier, ImportStarAsSpecifier, KeyValueProp, Lit, Module, ModuleDecl, ModuleItem, ObjectLit, Program, Prop, PropName, PropOrSpread, Stmt, Str, }, @@ -25,7 +25,8 @@ pub fn create_proxy_module(transition_name: &str, target_import: &str) -> Progra span: DUMMY_SP, })), ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl { - specifiers: vec![ImportSpecifier::Default(ImportDefaultSpecifier { + // TODO(alexkirsz) Is this correct? + specifiers: vec![ImportSpecifier::Namespace(ImportStarAsSpecifier { local: ident.clone(), span: DUMMY_SP, })], diff --git a/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/base/globals.d.ts b/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/base/globals.d.ts index eae4e2323ee6c5..343d3ae0400082 100644 --- a/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/base/globals.d.ts +++ b/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/base/globals.d.ts @@ -19,6 +19,7 @@ type ChunkUpdateProvider = { push: (registration: [ChunkPath, UpdateCallback]) => void; }; +declare var CHUNK_BASE_PATH: string; declare var TURBOPACK: ChunkRegistry | ChunkRegistration[] | undefined; declare var TURBOPACK_CHUNK_LISTS: ChunkListProvider | ChunkList[] | undefined; declare var TURBOPACK_CHUNK_UPDATE_LISTENERS: diff --git a/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/dom/runtime-backend-dom.ts b/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/dom/runtime-backend-dom.ts index b3eb55f583fcee..8b12437c8bb5fb 100644 --- a/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/dom/runtime-backend-dom.ts +++ b/crates/turbopack-ecmascript-runtime/js/src/dev/runtime/dom/runtime-backend-dom.ts @@ -197,7 +197,7 @@ function commonJsRequireContext( if (chunkPath.endsWith(".css")) { const link = document.createElement("link"); link.rel = "stylesheet"; - link.href = `/${chunkPath}`; + link.href = `/${CHUNK_BASE_PATH}${chunkPath}`; link.onerror = () => { resolver.reject(); }; @@ -209,7 +209,7 @@ function commonJsRequireContext( document.body.appendChild(link); } else if (chunkPath.endsWith(".js")) { const script = document.createElement("script"); - script.src = `/${chunkPath}`; + script.src = `/${CHUNK_BASE_PATH}${chunkPath}`; // We'll only mark the chunk as loaded once the script has been executed, // which happens in `registerChunk`. Hence the absence of `resolve()` in // this branch. diff --git a/crates/turbopack-ecmascript-runtime/src/dev_runtime.rs b/crates/turbopack-ecmascript-runtime/src/dev_runtime.rs index a5aa64746c7963..376490c80e65de 100644 --- a/crates/turbopack-ecmascript-runtime/src/dev_runtime.rs +++ b/crates/turbopack-ecmascript-runtime/src/dev_runtime.rs @@ -2,18 +2,22 @@ use std::io::Write; use anyhow::Result; use indoc::writedoc; +use turbo_tasks::primitives::OptionStringVc; use turbopack_core::{ code_builder::{CodeBuilder, CodeVc}, context::AssetContext, environment::{ChunkLoading, EnvironmentVc}, }; -use turbopack_ecmascript::StaticEcmascriptCodeVc; +use turbopack_ecmascript::{utils::StringifyJs, StaticEcmascriptCodeVc}; use crate::{asset_context::get_runtime_asset_context, embed_file_path}; /// Returns the code for the development ECMAScript runtime. #[turbo_tasks::function] -pub async fn get_dev_runtime_code(environment: EnvironmentVc) -> Result { +pub async fn get_dev_runtime_code( + environment: EnvironmentVc, + chunk_base_path: OptionStringVc, +) -> Result { let asset_context = get_runtime_asset_context(environment); let shared_runtime_utils_code = @@ -50,7 +54,14 @@ pub async fn get_dev_runtime_code(environment: EnvironmentVc) -> Result if (!Array.isArray(globalThis.TURBOPACK)) {{ return; }} - "# + + const CHUNK_BASE_PATH = {}; + "#, + StringifyJs(if let Some(chunk_base_path) = &*chunk_base_path.await? { + chunk_base_path.as_str() + } else { + "" + }) )?; code.push_code(&*shared_runtime_utils_code.await?); diff --git a/crates/turbopack/src/transition/context_transition.rs b/crates/turbopack/src/transition/context_transition.rs new file mode 100644 index 00000000000000..6cf33857f10889 --- /dev/null +++ b/crates/turbopack/src/transition/context_transition.rs @@ -0,0 +1,60 @@ +use anyhow::Result; +use turbopack_core::compile_time_info::CompileTimeInfoVc; + +use crate::{ + module_options::ModuleOptionsContextVc, + resolve_options_context::ResolveOptionsContextVc, + transition::{Transition, TransitionVc}, +}; + +/// A transition that only affects the asset context. +#[turbo_tasks::value(shared)] +pub struct ContextTransition { + compile_time_info: CompileTimeInfoVc, + module_options_context: ModuleOptionsContextVc, + resolve_options_context: ResolveOptionsContextVc, +} + +#[turbo_tasks::value_impl] +impl ContextTransitionVc { + #[turbo_tasks::function] + pub async fn new( + compile_time_info: CompileTimeInfoVc, + module_options_context: ModuleOptionsContextVc, + resolve_options_context: ResolveOptionsContextVc, + ) -> Result { + Ok(ContextTransition { + module_options_context, + resolve_options_context, + compile_time_info, + } + .cell()) + } +} + +#[turbo_tasks::value_impl] +impl Transition for ContextTransition { + #[turbo_tasks::function] + fn process_compile_time_info( + &self, + _compile_time_info: CompileTimeInfoVc, + ) -> CompileTimeInfoVc { + self.compile_time_info + } + + #[turbo_tasks::function] + fn process_module_options_context( + &self, + _context: ModuleOptionsContextVc, + ) -> ModuleOptionsContextVc { + self.module_options_context + } + + #[turbo_tasks::function] + fn process_resolve_options_context( + &self, + _context: ResolveOptionsContextVc, + ) -> ResolveOptionsContextVc { + self.resolve_options_context + } +} diff --git a/crates/turbopack/src/transition/mod.rs b/crates/turbopack/src/transition/mod.rs index 2483cf556cef12..4470240d1bb8c1 100644 --- a/crates/turbopack/src/transition/mod.rs +++ b/crates/turbopack/src/transition/mod.rs @@ -1,6 +1,9 @@ +pub(crate) mod context_transition; + use std::collections::HashMap; use anyhow::Result; +pub use context_transition::ContextTransitionVc; use turbo_tasks::Value; use turbopack_core::{ asset::AssetVc, compile_time_info::CompileTimeInfoVc, reference_type::ReferenceType,