diff --git a/crates/next-core/src/mode.rs b/crates/next-core/src/mode.rs index 31db7ce19f762e..f6a0496f86600b 100644 --- a/crates/next-core/src/mode.rs +++ b/crates/next-core/src/mode.rs @@ -58,10 +58,7 @@ impl NextMode { } pub fn is_production(&self) -> bool { - match self { - NextMode::Development => false, - NextMode::Build => true, - } + !self.is_development() } pub fn runtime_type(&self) -> RuntimeType { diff --git a/crates/next-core/src/next_client/context.rs b/crates/next-core/src/next_client/context.rs index b283f3e0110aab..42d135ee5d9764 100644 --- a/crates/next-core/src/next_client/context.rs +++ b/crates/next-core/src/next_client/context.rs @@ -19,8 +19,8 @@ use turbopack_browser::{ }; use turbopack_core::{ chunk::{ - ChunkingConfig, ChunkingContext, MangleType, MinifyType, SourceMapsType, - module_id_strategies::ModuleIdStrategy, + ChunkingConfig, ChunkingContext, MangleType, MinifyType, SourceMapSourceType, + SourceMapsType, module_id_strategies::ModuleIdStrategy, }, compile_time_info::{CompileTimeDefines, CompileTimeInfo, FreeVarReference, FreeVarReferences}, environment::{BrowserEnvironment, Environment, ExecutionEnvironment}, @@ -489,7 +489,7 @@ pub async fn get_client_chunking_context( if next_mode.is_development() { builder = builder .hot_module_replacement() - .use_file_source_map_uris() + .source_map_source_type(SourceMapSourceType::AbsoluteFileUri) .dynamic_chunk_content_loading(true); } else { builder = builder diff --git a/crates/next-core/src/next_server/context.rs b/crates/next-core/src/next_server/context.rs index 02c455dfef2ceb..bb308e6cb31537 100644 --- a/crates/next-core/src/next_server/context.rs +++ b/crates/next-core/src/next_server/context.rs @@ -16,7 +16,7 @@ use turbopack::{ }; use turbopack_core::{ chunk::{ - ChunkingConfig, MangleType, MinifyType, SourceMapsType, + ChunkingConfig, MangleType, MinifyType, SourceMapSourceType, SourceMapsType, module_id_strategies::ModuleIdStrategy, }, compile_time_defines, @@ -1060,9 +1060,13 @@ pub async fn get_server_chunking_context_with_client_assets( .file_tracing(next_mode.is_production()) .debug_ids(*debug_ids.await?); - if next_mode.is_development() { - builder = builder.use_file_source_map_uris(); + builder = builder.source_map_source_type(if next_mode.is_development() { + SourceMapSourceType::AbsoluteFileUri } else { + // TODO(lukesandberg): switch to relative once next is compatible. + SourceMapSourceType::TurbopackUri + }); + if next_mode.is_production() { builder = builder .chunking_config( Vc::::default().to_resolved().await?, @@ -1142,9 +1146,11 @@ pub async fn get_server_chunking_context( .debug_ids(*debug_ids.await?); if next_mode.is_development() { - builder = builder.use_file_source_map_uris() + builder = builder.source_map_source_type(SourceMapSourceType::AbsoluteFileUri); } else { builder = builder + // TODO(lukesandberg): switch to relative once next is compatible. + .source_map_source_type(SourceMapSourceType::TurbopackUri) .chunking_config( Vc::::default().to_resolved().await?, ChunkingConfig { diff --git a/turbopack/crates/turbo-tasks-fs/src/util.rs b/turbopack/crates/turbo-tasks-fs/src/util.rs index 8bd568f77a8a75..3feaa2f101c226 100644 --- a/turbopack/crates/turbo-tasks-fs/src/util.rs +++ b/turbopack/crates/turbo-tasks-fs/src/util.rs @@ -1,6 +1,6 @@ use std::{ io::{self, ErrorKind}, - path::Path, + path::{Path, PathBuf}, }; use anyhow::{Context, Result, anyhow}; @@ -19,10 +19,7 @@ pub fn extract_disk_access(value: io::Result, path: &Path) -> Result) -> Result { - use turbo_unix_path::sys_to_unix; - let root_fs = root.fs; let root_fs = &*ResolvedVc::try_downcast_type::(root_fs) .context("Expected root to have a DiskFileSystem")? @@ -33,32 +30,26 @@ pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result root, }; - let sys_path = root_fs.to_sys_path(&path); + Ok(uri_from_path_buf(root_fs.to_sys_path(&path))) +} + +#[cfg(not(target_os = "windows"))] +pub fn uri_from_path_buf(sys_path: PathBuf) -> String { + use turbo_unix_path::sys_to_unix; let sys_path = sys_path.to_string_lossy(); - Ok(format!( + format!( "file://{}", sys_to_unix(&sys_path) .split('/') .map(|s| urlencoding::encode(s)) .collect::>() .join("/") - )) + ) } #[cfg(target_os = "windows")] -pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result { - let root_fs = root.fs; - let root_fs = &*ResolvedVc::try_downcast_type::(root_fs) - .context("Expected root to have a DiskFileSystem")? - .await?; - - let sys_path = match path { - Some(path) => root.join(path.into())?, - None => root, - }; - let sys_path = root_fs.to_sys_path(&sys_path); - +pub fn uri_from_path_buf(sys_path: PathBuf) -> String { let raw_path = sys_path.to_string_lossy().to_string(); let normalized_path = raw_path.replace('\\', "/"); @@ -70,7 +61,5 @@ pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result>() .join("/"); - let uri = format!("file:///{}", encoded_path); - - Ok(uri) + format!("file:///{}", encoded_path) } diff --git a/turbopack/crates/turbopack-browser/src/chunking_context.rs b/turbopack/crates/turbopack-browser/src/chunking_context.rs index fb6f4e079c179f..02b2a9b45517ad 100644 --- a/turbopack/crates/turbopack-browser/src/chunking_context.rs +++ b/turbopack/crates/turbopack-browser/src/chunking_context.rs @@ -13,7 +13,7 @@ use turbopack_core::{ chunk::{ Chunk, ChunkGroupResult, ChunkItem, ChunkType, ChunkableModule, ChunkingConfig, ChunkingConfigs, ChunkingContext, EntryChunkGroupResult, EvaluatableAsset, - EvaluatableAssets, MinifyType, ModuleId, SourceMapsType, + EvaluatableAssets, MinifyType, ModuleId, SourceMapSourceType, SourceMapsType, availability_info::AvailabilityInfo, chunk_group::{MakeChunkGroupResult, make_chunk_group}, module_id_strategies::{DevModuleIdStrategy, ModuleIdStrategy}, @@ -91,8 +91,8 @@ impl BrowserChunkingContextBuilder { self } - pub fn use_file_source_map_uris(mut self) -> Self { - self.chunking_context.should_use_file_source_map_uris = true; + pub fn source_map_source_type(mut self, source_map_source_type: SourceMapSourceType) -> Self { + self.chunking_context.source_map_source_type = source_map_source_type; self } @@ -229,8 +229,8 @@ pub struct BrowserChunkingContext { name: Option, /// The root path of the project root_path: FileSystemPath, - /// Whether to write file sources as file:// paths in source maps - should_use_file_source_map_uris: bool, + /// The strategy to use for generating source map source uris + source_map_source_type: SourceMapSourceType, /// This path is used to compute the url to request chunks from output_root: FileSystemPath, /// The relative path from the output_root to the root_path. @@ -311,7 +311,7 @@ impl BrowserChunkingContext { client_root, client_roots: Default::default(), chunk_root_path, - should_use_file_source_map_uris: false, + source_map_source_type: SourceMapSourceType::TurbopackUri, asset_root_path, asset_root_paths: Default::default(), chunk_base_path: None, @@ -617,8 +617,8 @@ impl ChunkingContext for BrowserChunkingContext { } #[turbo_tasks::function] - fn should_use_file_source_map_uris(&self) -> Vc { - Vc::cell(self.should_use_file_source_map_uris) + fn source_map_source_type(&self) -> Vc { + self.source_map_source_type.cell() } #[turbo_tasks::function] diff --git a/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs b/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs index 2418a71a336d46..0646860763fc3a 100644 --- a/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs +++ b/turbopack/crates/turbopack-cli/src/dev/web_entry_source.rs @@ -6,7 +6,9 @@ use turbo_tasks_fs::FileSystemPath; use turbopack_browser::{BrowserChunkingContext, react_refresh::assert_can_resolve_react_refresh}; use turbopack_cli_utils::runtime_entry::{RuntimeEntries, RuntimeEntry}; use turbopack_core::{ - chunk::{ChunkableModule, ChunkingContext, EvaluatableAsset, SourceMapsType}, + chunk::{ + ChunkableModule, ChunkingContext, EvaluatableAsset, SourceMapSourceType, SourceMapsType, + }, environment::Environment, file_source::FileSource, module::Module, @@ -51,7 +53,7 @@ pub async fn get_client_chunking_context( RuntimeType::Development, ) .hot_module_replacement() - .use_file_source_map_uris() + .source_map_source_type(SourceMapSourceType::AbsoluteFileUri) .dynamic_chunk_content_loading(true) .build(), )) diff --git a/turbopack/crates/turbopack-core/src/chunk/chunking_context.rs b/turbopack/crates/turbopack-core/src/chunk/chunking_context.rs index 684e89bbe5b6a1..9b13a6906067d5 100644 --- a/turbopack/crates/turbopack-core/src/chunk/chunking_context.rs +++ b/turbopack/crates/turbopack-core/src/chunk/chunking_context.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{Result, bail}; use rustc_hash::FxHashMap; use serde::{Deserialize, Serialize}; use turbo_rcstr::RcStr; @@ -133,13 +133,22 @@ pub struct ChunkingConfig { #[turbo_tasks::value(transparent)] pub struct ChunkingConfigs(FxHashMap>, ChunkingConfig>); +#[turbo_tasks::value(shared)] +#[derive(Debug, Clone, Copy, Hash, TaskInput, Default)] +pub enum SourceMapSourceType { + AbsoluteFileUri, + RelativeUri, + #[default] + TurbopackUri, +} + /// A context for the chunking that influences the way chunks are created #[turbo_tasks::value_trait] pub trait ChunkingContext { #[turbo_tasks::function] fn name(self: Vc) -> Vc; #[turbo_tasks::function] - fn should_use_file_source_map_uris(self: Vc) -> Vc; + fn source_map_source_type(self: Vc) -> Vc; /// The root path of the project #[turbo_tasks::function] fn root_path(self: Vc) -> Vc; @@ -385,6 +394,13 @@ pub trait ChunkingContextExt { ) -> Vc where Self: Send; + + /// Computes the relative path from the chunk output root to the project root. + /// + /// This is used to compute relative paths for source maps in certain configurations. + fn relative_path_from_chunk_root_to_project_root(self: Vc) -> Vc + where + Self: Send; } impl>> ChunkingContextExt for T { @@ -499,6 +515,52 @@ impl>> ChunkingConte availability_info, ) } + + fn relative_path_from_chunk_root_to_project_root(self: Vc) -> Vc { + relative_path_from_chunk_root_to_project_root(Vc::upcast_non_strict(self)) + } +} + +#[turbo_tasks::function] +async fn relative_path_from_chunk_root_to_project_root( + chunking_context: Vc>, +) -> Result> { + // Example, + // project root: /project/root + // output root: /project/root/dist + // chunk root path: /project/root/dist/ssr/chunks + // output_root_to_chunk_root: ../ + // + // Example2, + // project root: /project/root + // output root: /project/out + // chunk root path: /project/out/ssr/chunks + // output_root_to_chunk_root: ../root + // + // From that we want to return ../../../root to get from a path in `chunks` to a path in the + // project root. + + let chunk_root_path = chunking_context.chunk_root_path().await?; + let output_root = chunking_context.output_root().await?; + let chunk_to_output_root = chunk_root_path.get_relative_path_to(&output_root); + let Some(chunk_to_output_root) = chunk_to_output_root else { + bail!( + "expected chunk_root_path: {chunk_root_path} to be inside of output_root: \ + {output_root}", + chunk_root_path = chunk_root_path.value_to_string().await?, + output_root = output_root.value_to_string().await? + ); + }; + let output_root_to_chunk_root_path = chunking_context.output_root_to_root_path().await?; + + // Note we cannot use `normalize_path` here since it rejects paths that start with `../` + Ok(Vc::cell( + format!( + "{}/{}", + chunk_to_output_root, output_root_to_chunk_root_path + ) + .into(), + )) } #[turbo_tasks::function] diff --git a/turbopack/crates/turbopack-core/src/chunk/mod.rs b/turbopack/crates/turbopack-core/src/chunk/mod.rs index cc10ba4c5312a7..53861abd936e0b 100644 --- a/turbopack/crates/turbopack-core/src/chunk/mod.rs +++ b/turbopack/crates/turbopack-core/src/chunk/mod.rs @@ -29,7 +29,8 @@ pub use self::{ }, chunking_context::{ ChunkGroupResult, ChunkGroupType, ChunkingConfig, ChunkingConfigs, ChunkingContext, - ChunkingContextExt, EntryChunkGroupResult, MangleType, MinifyType, SourceMapsType, + ChunkingContextExt, EntryChunkGroupResult, MangleType, MinifyType, SourceMapSourceType, + SourceMapsType, }, data::{ChunkData, ChunkDataOption, ChunksData}, evaluate::{EvaluatableAsset, EvaluatableAssetExt, EvaluatableAssets}, diff --git a/turbopack/crates/turbopack-core/src/source_map/utils.rs b/turbopack/crates/turbopack-core/src/source_map/utils.rs index 9329ad965ce5a0..d955eaf43c09a7 100644 --- a/turbopack/crates/turbopack-core/src/source_map/utils.rs +++ b/turbopack/crates/turbopack-core/src/source_map/utils.rs @@ -6,9 +6,10 @@ use once_cell::sync::Lazy; use regex::Regex; use serde::{Deserialize, Serialize}; use serde_json::value::RawValue; +use turbo_rcstr::RcStr; use turbo_tasks::{ResolvedVc, ValueToString}; use turbo_tasks_fs::{ - DiskFileSystem, FileContent, FileSystemPath, rope::Rope, util::uri_from_file, + DiskFileSystem, FileContent, FileSystemPath, rope::Rope, util::uri_from_path_buf, }; use url::Url; @@ -71,6 +72,7 @@ struct SourceMapJson { ignore_list: Option>, // A somewhat widespread non-standard extension + #[serde(skip_serializing_if = "Option::is_none")] debug_id: Option>, #[serde(skip_serializing_if = "Option::is_none")] @@ -224,12 +226,18 @@ fn unencoded_str_to_raw_value(unencoded: &str) -> Box { .expect("serde_json::to_string should produce valid JSON") } -/// Turns `turbopack:///[project]` references in sourcemap sources into absolute `file://` uris. This -/// is useful for debugging environments. -pub async fn fileify_source_map( +/// Helper function to transform turbopack:/// file references in a sourcemap. +/// Handles parsing the sourcemap, resolving the filesystem, applying transformations, and +/// serializing back. +/// The transform function is given the source string as found in the sourcemap (i.e. a URI). +async fn transform_relative_files( map: Option<&Rope>, - context_path: FileSystemPath, -) -> Result> { + context_path: &FileSystemPath, + mut transform: F, +) -> Result> +where + F: FnMut(&DiskFileSystem, &str) -> Result, +{ let Some(map) = map else { return Ok(None); }; @@ -243,29 +251,75 @@ pub async fn fileify_source_map( let context_fs = &*ResolvedVc::try_downcast_type::(context_fs) .context("Expected the chunking context to have a DiskFileSystem")? .await?; + let prefix = format!("{}///[{}]/", SOURCE_URL_PROTOCOL, context_fs.name()); - let transform_source = async |src: &mut Option| { - if let Some(src) = src - && let Some(src_rest) = src.strip_prefix(&prefix) - { - *src = uri_from_file(context_path.clone(), Some(src_rest)).await?; + let mut apply_transform = |src: &mut String| -> Result<()> { + if let Some(src_rest) = src.strip_prefix(&prefix) { + *src = transform(context_fs, src_rest)?; } - anyhow::Ok(()) + Ok(()) }; - for src in map.sources.iter_mut().flatten() { - transform_source(src).await?; + for src in map.sources.iter_mut().flatten().flatten() { + apply_transform(src)?; } for section in map.sections.iter_mut().flatten() { - for src in section.map.sources.iter_mut().flatten() { - transform_source(src).await?; + for src in section.map.sources.iter_mut().flatten().flatten() { + apply_transform(src)?; } } - let map = Rope::from(serde_json::to_vec(&map)?); + Ok(Some(Rope::from(serde_json::to_vec(&map)?))) +} - Ok(Some(map)) +/// Turns `turbopack:///[project]` references in sourcemap sources into absolute `file://` uris. This +/// is useful for debugging environments. +pub async fn absolute_fileify_source_map( + map: Option<&Rope>, + context_path: FileSystemPath, +) -> Result> { + transform_relative_files(map, &context_path, |context_fs, src_rest| { + let path = context_path.join(src_rest)?; + + Ok(uri_from_path_buf(context_fs.to_sys_path(&path))) + }) + .await +} + +fn uri_encode_path(path: &str) -> String { + path.split('/') + .map(|s| urlencoding::encode(s)) + .collect::>() + .join("/") +} +/// Turns `turbopack:///[project]` references in sourcemap sources into relative './' prefixed uris. +/// This is useful in server environments and especially build environments. +pub async fn relative_fileify_source_map( + map: Option<&Rope>, + context_path: FileSystemPath, + relative_path_to_output_root: RcStr, +) -> Result> { + let relative_path_to_output_root = relative_path_to_output_root + .split('/') + .map(|s| urlencoding::encode(s)) + .collect::>() + .join("/"); + transform_relative_files(map, &context_path, |_context_fs, src_rest| { + // NOTE: we just include the relative path prefix here instead of using `sourceRoot` + // since the spec on sourceRoot is broken. + + // TODO(bgw): this shouldn't be necessary to uri encode since the strings we get out of the + // source map should already be uri encoded, however in the case of the turbopack scheme in + // particular we are inconsistent so be defensive here. + let src_rest = uri_encode_path(src_rest); + if relative_path_to_output_root.is_empty() { + Ok(src_rest.to_string()) + } else { + Ok(format!("{relative_path_to_output_root}/{src_rest}",)) + } + }) + .await } #[cfg(test)] diff --git a/turbopack/crates/turbopack-css/src/chunk/mod.rs b/turbopack/crates/turbopack-css/src/chunk/mod.rs index 76c1e4c261fa3e..baa71427f1757c 100644 --- a/turbopack/crates/turbopack-css/src/chunk/mod.rs +++ b/turbopack/crates/turbopack-css/src/chunk/mod.rs @@ -18,8 +18,8 @@ use turbopack_core::{ chunk::{ AsyncModuleInfo, Chunk, ChunkItem, ChunkItemBatchGroup, ChunkItemExt, ChunkItemOrBatchWithAsyncModuleInfo, ChunkItemWithAsyncModuleInfo, ChunkType, - ChunkableModule, ChunkingContext, MinifyType, OutputChunk, OutputChunkRuntimeInfo, - round_chunk_item_size, + ChunkableModule, ChunkingContext, ChunkingContextExt, MinifyType, OutputChunk, + OutputChunkRuntimeInfo, SourceMapSourceType, round_chunk_item_size, }, code_builder::{Code, CodeBuilder}, ident::AssetIdent, @@ -32,7 +32,10 @@ use turbopack_core::{ output::{OutputAsset, OutputAssets}, reference_type::ImportContext, server_fs::ServerFileSystem, - source_map::{GenerateSourceMap, OptionStringifiedSourceMap, utils::fileify_source_map}, + source_map::{ + GenerateSourceMap, OptionStringifiedSourceMap, + utils::{absolute_fileify_source_map, relative_fileify_source_map}, + }, }; use self::{single_item_chunk::chunk::SingleItemCssChunk, source_map::CssChunkSourceMapAsset}; @@ -96,18 +99,27 @@ impl CssChunk { let close = write_import_context(&mut body, content.import_context).await?; - let source_map = if *self - .chunking_context() - .should_use_file_source_map_uris() - .await? - { - fileify_source_map( - content.source_map.as_ref(), - self.chunking_context().root_path().owned().await?, - ) - .await? - } else { - content.source_map.clone() + let chunking_context = self.chunking_context(); + let source_map = match *chunking_context.source_map_source_type().await? { + SourceMapSourceType::AbsoluteFileUri => { + absolute_fileify_source_map( + content.source_map.as_ref(), + chunking_context.root_path().owned().await?, + ) + .await? + } + SourceMapSourceType::RelativeUri => { + relative_fileify_source_map( + content.source_map.as_ref(), + chunking_context.root_path().owned().await?, + chunking_context + .relative_path_from_chunk_root_to_project_root() + .owned() + .await?, + ) + .await? + } + SourceMapSourceType::TurbopackUri => content.source_map.clone(), }; body.push_source(&content.inner_code, source_map); diff --git a/turbopack/crates/turbopack-ecmascript/src/chunk/item.rs b/turbopack/crates/turbopack-ecmascript/src/chunk/item.rs index 15bd1106055a8c..a6e9705a272d20 100644 --- a/turbopack/crates/turbopack-ecmascript/src/chunk/item.rs +++ b/turbopack/crates/turbopack-ecmascript/src/chunk/item.rs @@ -3,18 +3,21 @@ use std::io::Write; use anyhow::{Result, bail}; use serde::{Deserialize, Serialize}; use smallvec::SmallVec; -use turbo_rcstr::rcstr; +use turbo_rcstr::{RcStr, rcstr}; use turbo_tasks::{ NonLocalValue, ResolvedVc, TaskInput, TryJoinIterExt, Upcast, ValueToString, Vc, trace::TraceRawVcs, }; use turbo_tasks_fs::{FileSystemPath, rope::Rope}; use turbopack_core::{ - chunk::{AsyncModuleInfo, ChunkItem, ChunkItemWithAsyncModuleInfo, ChunkingContext, ModuleId}, + chunk::{ + AsyncModuleInfo, ChunkItem, ChunkItemWithAsyncModuleInfo, ChunkingContext, + ChunkingContextExt, ModuleId, SourceMapSourceType, + }, code_builder::{Code, CodeBuilder}, error::PrettyPrintError, issue::{IssueExt, IssueSeverity, StyledString, code_gen::CodeGenerationIssue}, - source_map::utils::fileify_source_map, + source_map::utils::{absolute_fileify_source_map, relative_fileify_source_map}, }; use crate::{ @@ -24,6 +27,26 @@ use crate::{ utils::StringifyJs, }; +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Hash, + Serialize, + Deserialize, + TraceRawVcs, + TaskInput, + NonLocalValue, + Default, +)] +pub enum RewriteSourcePath { + AbsoluteFilePath(FileSystemPath), + RelativeFilePath(FileSystemPath, RcStr), + #[default] + None, +} + #[turbo_tasks::value(shared)] #[derive(Default, Clone)] pub struct EcmascriptChunkItemContent { @@ -31,7 +54,7 @@ pub struct EcmascriptChunkItemContent { pub source_map: Option, pub additional_ids: SmallVec<[ResolvedVc; 1]>, pub options: EcmascriptChunkItemOptions, - pub rewrite_source_path: Option, + pub rewrite_source_path: RewriteSourcePath, pub placeholder_for_future_extensions: (), } @@ -53,10 +76,18 @@ impl EcmascriptChunkItemContent { let strict = content.strict; Ok(EcmascriptChunkItemContent { - rewrite_source_path: if *chunking_context.should_use_file_source_map_uris().await? { - Some(chunking_context.root_path().owned().await?) - } else { - None + rewrite_source_path: match *chunking_context.source_map_source_type().await? { + SourceMapSourceType::AbsoluteFileUri => { + RewriteSourcePath::AbsoluteFilePath(chunking_context.root_path().owned().await?) + } + SourceMapSourceType::RelativeUri => RewriteSourcePath::RelativeFilePath( + chunking_context.root_path().owned().await?, + chunking_context + .relative_path_from_chunk_root_to_project_root() + .owned() + .await?, + ), + SourceMapSourceType::TurbopackUri => RewriteSourcePath::None, }, inner_code: content.inner_code.clone(), source_map: content.source_map.clone(), @@ -112,10 +143,19 @@ impl EcmascriptChunkItemContent { )?; } - let source_map = if let Some(rewrite_source_path) = &self.rewrite_source_path { - fileify_source_map(self.source_map.as_ref(), rewrite_source_path.clone()).await? - } else { - self.source_map.clone() + let source_map = match &self.rewrite_source_path { + RewriteSourcePath::AbsoluteFilePath(path) => { + absolute_fileify_source_map(self.source_map.as_ref(), path.clone()).await? + } + RewriteSourcePath::RelativeFilePath(path, relative_path) => { + relative_fileify_source_map( + self.source_map.as_ref(), + path.clone(), + relative_path.clone(), + ) + .await? + } + RewriteSourcePath::None => self.source_map.clone(), }; code.push_source(&self.inner_code, source_map); diff --git a/turbopack/crates/turbopack-ecmascript/src/tree_shake/chunk_item.rs b/turbopack/crates/turbopack-ecmascript/src/tree_shake/chunk_item.rs index 9a1cebe9398b31..0f212054ab23e3 100644 --- a/turbopack/crates/turbopack-ecmascript/src/tree_shake/chunk_item.rs +++ b/turbopack/crates/turbopack-ecmascript/src/tree_shake/chunk_item.rs @@ -13,7 +13,7 @@ use crate::{ EcmascriptAnalyzableExt, chunk::{ EcmascriptChunkItem, EcmascriptChunkItemContent, EcmascriptChunkItemOptions, - EcmascriptChunkPlaceable, EcmascriptChunkType, + EcmascriptChunkPlaceable, EcmascriptChunkType, item::RewriteSourcePath, }, references::async_module::AsyncModuleOptions, runtime_functions::{TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_IMPORT}, @@ -166,7 +166,7 @@ impl EcmascriptChunkItem for SideEffectsModuleChunkItem { Ok(EcmascriptChunkItemContent { inner_code: code, source_map: None, - rewrite_source_path: None, + rewrite_source_path: RewriteSourcePath::None, options: EcmascriptChunkItemOptions { strict: true, async_module: if has_top_level_await { diff --git a/turbopack/crates/turbopack-nodejs/src/chunking_context.rs b/turbopack/crates/turbopack-nodejs/src/chunking_context.rs index c877f39598bee3..31cf20a84b4ea5 100644 --- a/turbopack/crates/turbopack-nodejs/src/chunking_context.rs +++ b/turbopack/crates/turbopack-nodejs/src/chunking_context.rs @@ -8,7 +8,7 @@ use turbopack_core::{ chunk::{ Chunk, ChunkGroupResult, ChunkItem, ChunkType, ChunkableModule, ChunkingConfig, ChunkingConfigs, ChunkingContext, EntryChunkGroupResult, EvaluatableAssets, MinifyType, - ModuleId, SourceMapsType, + ModuleId, SourceMapSourceType, SourceMapsType, availability_info::AvailabilityInfo, chunk_group::{MakeChunkGroupResult, make_chunk_group}, module_id_strategies::{DevModuleIdStrategy, ModuleIdStrategy}, @@ -99,8 +99,8 @@ impl NodeJsChunkingContextBuilder { self } - pub fn use_file_source_map_uris(mut self) -> Self { - self.chunking_context.should_use_file_source_map_uris = true; + pub fn source_map_source_type(mut self, source_map_source_type: SourceMapSourceType) -> Self { + self.chunking_context.source_map_source_type = source_map_source_type; self } @@ -182,8 +182,8 @@ pub struct NodeJsChunkingContext { module_id_strategy: ResolvedVc>, /// The module export usage info, if available. export_usage: Option>, - /// Whether to use file:// uris for source map sources - should_use_file_source_map_uris: bool, + /// The strategy to use for generating source map source uris + source_map_source_type: SourceMapSourceType, /// The chunking configs chunking_configs: Vec<(ResolvedVc>, ChunkingConfig)>, /// Enable debug IDs for chunks and source maps. @@ -222,7 +222,7 @@ impl NodeJsChunkingContext { minify_type: MinifyType::NoMinify, source_maps_type: SourceMapsType::Full, manifest_chunks: false, - should_use_file_source_map_uris: false, + source_map_source_type: SourceMapSourceType::TurbopackUri, module_id_strategy: ResolvedVc::upcast(DevModuleIdStrategy::new_resolved()), export_usage: None, chunking_configs: Default::default(), @@ -387,8 +387,8 @@ impl ChunkingContext for NodeJsChunkingContext { } #[turbo_tasks::function] - fn should_use_file_source_map_uris(&self) -> Vc { - Vc::cell(self.should_use_file_source_map_uris) + fn source_map_source_type(&self) -> Vc { + self.source_map_source_type.cell() } #[turbo_tasks::function] diff --git a/turbopack/crates/turbopack-tests/tests/snapshot.rs b/turbopack/crates/turbopack-tests/tests/snapshot.rs index c5c4edb1ee5c45..09b68e5e5c4ea8 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot.rs +++ b/turbopack/crates/turbopack-tests/tests/snapshot.rs @@ -33,7 +33,7 @@ use turbopack_core::{ asset::Asset, chunk::{ ChunkingConfig, ChunkingContext, ChunkingContextExt, EvaluatableAsset, EvaluatableAssetExt, - EvaluatableAssets, MinifyType, availability_info::AvailabilityInfo, + EvaluatableAssets, MinifyType, SourceMapSourceType, availability_info::AvailabilityInfo, }, compile_time_defines, compile_time_info::{CompileTimeDefineValue, CompileTimeInfo, DefinableNameSegment}, @@ -91,6 +91,8 @@ struct SnapshotOptions { production_chunking: bool, #[serde(default)] enable_debug_ids: bool, + #[serde(default)] + source_map_source_type: SourceMapSourceType, } #[derive(Debug, Deserialize, Default)] @@ -121,6 +123,7 @@ impl Default for SnapshotOptions { scope_hoisting: false, production_chunking: false, enable_debug_ids: false, + source_map_source_type: SourceMapSourceType::default(), } } } @@ -460,7 +463,8 @@ async fn run_test_operation(resource: RcStr) -> Result> { .minify_type(options.minify_type) .module_merging(options.scope_hoisting) .export_usage(export_usage) - .debug_ids(options.enable_debug_ids); + .debug_ids(options.enable_debug_ids) + .source_map_source_type(options.source_map_source_type); if options.production_chunking { builder = builder.chunking_config( @@ -489,7 +493,8 @@ async fn run_test_operation(resource: RcStr) -> Result> { .minify_type(options.minify_type) .module_merging(options.scope_hoisting) .export_usage(export_usage) - .debug_ids(options.enable_debug_ids); + .debug_ids(options.enable_debug_ids) + .source_map_source_type(options.source_map_source_type); if options.production_chunking { builder = builder.chunking_config( diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/options.json b/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/options.json index 21dada2cba4b19..a1b371cb3b60c6 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/options.json +++ b/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/options.json @@ -3,5 +3,6 @@ "runtimeType": "Development", "minifyType": "NoMinify", "environment": "NodeJs", - "enableDebugIds": true + "enableDebugIds": true, + "sourceMapSourceType": "RelativeUri" } diff --git a/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/output/aaf3a_crates_turbopack-tests_tests_snapshot_debug-ids_node_input_index_b515b56f.js.map b/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/output/aaf3a_crates_turbopack-tests_tests_snapshot_debug-ids_node_input_index_b515b56f.js.map index f2ee6c74569091..bb66d25fc986d2 100644 --- a/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/output/aaf3a_crates_turbopack-tests_tests_snapshot_debug-ids_node_input_index_b515b56f.js.map +++ b/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/output/aaf3a_crates_turbopack-tests_tests_snapshot_debug-ids_node_input_index_b515b56f.js.map @@ -3,5 +3,5 @@ "sources": [], "debugId": "3d97c2d1-90e5-a3ef-c710-5c78b21b3b3a", "sections": [ - {"offset": {"line": 4, "column": 0}, "map": {"version":3,"sources":["turbopack:///[project]/turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/input/index.js"],"sourcesContent":["console.log('Hello World')\n"],"names":[],"mappings":"AAAA,QAAQ,GAAG,CAAC"}}] + {"offset": {"line": 4, "column": 0}, "map": {"version":3,"sources":["../../../../../../../../turbopack/crates/turbopack-tests/tests/snapshot/debug-ids/node/input/index.js"],"sourcesContent":["console.log('Hello World')\n"],"names":[],"mappings":"AAAA,QAAQ,GAAG,CAAC"}}] } \ No newline at end of file