Skip to content

Turbopack: defer sourcemaps processing to codegen #78855

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions turbopack/crates/turbopack-ecmascript/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ use turbopack_core::{
FindContextFileResult,
},
source::Source,
source_map::OptionStringifiedSourceMap,
source_map::GenerateSourceMap,
};
// TODO remove this
pub use turbopack_resolve::ecmascript as resolve;
Expand Down Expand Up @@ -819,7 +819,7 @@ pub struct EcmascriptModuleContentOptions {
code_generation: ResolvedVc<CodeGens>,
async_module: ResolvedVc<OptionAsyncModule>,
generate_source_map: bool,
original_source_map: ResolvedVc<OptionStringifiedSourceMap>,
original_source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
exports: ResolvedVc<EcmascriptExports>,
async_module_info: Option<ResolvedVc<AsyncModuleInfo>>,
}
Expand Down Expand Up @@ -945,7 +945,7 @@ impl EcmascriptModuleContent {
specified_module_type,
vec![],
generate_source_map,
OptionStringifiedSourceMap::none().to_resolved().await?,
None,
)
.await?;
emit_content(content).await
Expand All @@ -958,7 +958,7 @@ struct CodeGenResult {
comments: Either<ImmutableComments, Arc<ImmutableComments>>,
is_esm: bool,
generate_source_map: bool,
original_source_map: Option<ResolvedVc<OptionStringifiedSourceMap>>,
original_source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
}

async fn process_parse_result(
Expand All @@ -967,7 +967,7 @@ async fn process_parse_result(
specified_module_type: SpecifiedModuleType,
code_gens: Vec<CodeGeneration>,
generate_source_map: bool,
original_source_map: ResolvedVc<OptionStringifiedSourceMap>,
original_source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
) -> Result<CodeGenResult> {
let parsed = parsed.final_read_hint().await?;

Expand Down Expand Up @@ -1025,7 +1025,7 @@ async fn process_parse_result(
comments,
is_esm,
generate_source_map,
original_source_map: Some(original_source_map),
original_source_map,
}
}
ParseResult::Unparseable { messages } => {
Expand Down Expand Up @@ -1130,7 +1130,7 @@ async fn emit_content(content: CodeGenResult) -> Result<Vc<EcmascriptModuleConte
Some(generate_js_source_map(
source_map.clone(),
mappings,
original_source_map.await?.as_ref(),
original_source_map.generate_source_map().await?.as_ref(),
)?)
} else {
Some(generate_js_source_map(source_map.clone(), mappings, None)?)
Expand Down
55 changes: 16 additions & 39 deletions turbopack/crates/turbopack-ecmascript/src/references/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use turbo_tasks::{
trace::TraceRawVcs, FxIndexMap, FxIndexSet, NonLocalValue, ReadRef, ResolvedVc, TaskInput,
TryJoinIterExt, Upcast, Value, ValueToString, Vc,
};
use turbo_tasks_fs::{rope::Rope, FileSystemPath};
use turbo_tasks_fs::FileSystemPath;
use turbopack_core::{
compile_time_info::{
CompileTimeInfo, DefineableNameSegment, FreeVarReference, FreeVarReferences,
Expand All @@ -76,9 +76,7 @@ use turbopack_core::{
resolve, FindContextFileResult, ModulePart,
},
source::Source,
source_map::{
utils::resolve_source_map_sources, GenerateSourceMap, OptionStringifiedSourceMap,
},
source_map::GenerateSourceMap,
};
use turbopack_resolve::{
ecmascript::{apply_cjs_specific_options, cjs_resolve_source},
Expand Down Expand Up @@ -148,6 +146,7 @@ use crate::{
node::PackageJsonReference,
require_context::{RequireContextAssetReference, RequireContextMap},
type_issue::SpecifiedModuleTypeIssue,
util::InlineSourceMap,
},
runtime_functions::{
TUBROPACK_RUNTIME_FUNCTION_SHORTCUTS, TURBOPACK_EXPORT_NAMESPACE, TURBOPACK_EXPORT_VALUE,
Expand All @@ -174,7 +173,7 @@ pub struct AnalyzeEcmascriptModuleResult {
pub has_side_effect_free_directive: bool,
/// `true` when the analysis was successful.
pub successful: bool,
pub source_map: ResolvedVc<OptionStringifiedSourceMap>,
pub source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
}

#[turbo_tasks::value_impl]
Expand Down Expand Up @@ -223,7 +222,7 @@ pub struct AnalyzeEcmascriptModuleResultBuilder {
exports: EcmascriptExports,
async_module: ResolvedVc<OptionAsyncModule>,
successful: bool,
source_map: Option<ResolvedVc<OptionStringifiedSourceMap>>,
source_map: Option<ResolvedVc<Box<dyn GenerateSourceMap>>>,
has_side_effect_free_directive: bool,
}

Expand Down Expand Up @@ -289,7 +288,7 @@ impl AnalyzeEcmascriptModuleResultBuilder {
}

/// Sets the analysis result ES export.
pub fn set_source_map(&mut self, source_map: ResolvedVc<OptionStringifiedSourceMap>) {
pub fn set_source_map(&mut self, source_map: ResolvedVc<Box<dyn GenerateSourceMap>>) {
self.source_map = Some(source_map);
}

Expand Down Expand Up @@ -401,12 +400,6 @@ impl AnalyzeEcmascriptModuleResultBuilder {

let references: Vec<_> = self.references.into_iter().collect();

let source_map = if let Some(source_map) = self.source_map {
source_map
} else {
OptionStringifiedSourceMap::none().to_resolved().await?
};

self.code_gens.shrink_to_fit();
Ok(AnalyzeEcmascriptModuleResult::cell(
AnalyzeEcmascriptModuleResult {
Expand All @@ -424,7 +417,7 @@ impl AnalyzeEcmascriptModuleResultBuilder {
async_module: self.async_module,
has_side_effect_free_directive: self.has_side_effect_free_directive,
successful: self.successful,
source_map,
source_map: self.source_map,
},
))
}
Expand Down Expand Up @@ -705,27 +698,24 @@ pub(crate) async fn analyse_ecmascript_module_internal(
.to_resolved()
.await?;
analysis.add_reference(reference);
let source_map = reference.generate_source_map();
analysis.set_source_map(source_map.to_resolved().await?);
analysis.set_source_map(ResolvedVc::upcast(reference));
source_map_from_comment = true;
} else if JSON_DATA_URL_BASE64.is_match(path) {
let source_map = maybe_decode_data_url(path.into());
let source_map =
resolve_source_map_sources(source_map.as_ref(), origin_path).await?;
analysis.set_source_map(ResolvedVc::cell(source_map));
analysis.set_source_map(ResolvedVc::upcast(
InlineSourceMap {
origin_path: origin_path.to_resolved().await?,
source_map: path.into(),
}
.resolved_cell(),
));
source_map_from_comment = true;
}
}
if !source_map_from_comment {
if let Some(generate_source_map) =
ResolvedVc::try_sidecast::<Box<dyn GenerateSourceMap>>(source)
{
analysis.set_source_map(
generate_source_map
.generate_source_map()
.to_resolved()
.await?,
);
analysis.set_source_map(generate_source_map);
}
}
anyhow::Ok(())
Expand Down Expand Up @@ -3665,16 +3655,3 @@ fn is_invoking_node_process_eval(args: &[JsValue]) -> bool {

false
}

fn maybe_decode_data_url(url: RcStr) -> Option<Rope> {
const DATA_PREAMBLE: &str = "data:application/json;base64,";

if !url.starts_with(DATA_PREAMBLE) {
return None;
}
let data_b64 = &url[DATA_PREAMBLE.len()..];
data_encoding::BASE64
.decode(data_b64.as_bytes())
.ok()
.map(Rope::from)
}
42 changes: 40 additions & 2 deletions turbopack/crates/turbopack-ecmascript/src/references/util.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
use anyhow::Result;
use swc_core::{ecma::ast::Expr, quote};
use turbo_rcstr::RcStr;
use turbo_tasks::Vc;
use turbopack_core::resolve::parse::Request;
use turbo_tasks::{ResolvedVc, Vc};
use turbo_tasks_fs::{rope::Rope, FileSystemPath};
use turbopack_core::{
resolve::parse::Request,
source_map::{
utils::resolve_source_map_sources, GenerateSourceMap, OptionStringifiedSourceMap,
},
};

/// Creates a IIFE expression that throws a "Cannot find module" error for the
/// given request string
Expand Down Expand Up @@ -36,3 +42,35 @@ pub async fn request_to_string(request: Vc<Request>) -> Result<Vc<RcStr>> {
.unwrap_or_else(|| "unknown".into()),
))
}

#[turbo_tasks::value(shared)]
#[derive(Debug, Clone)]
pub struct InlineSourceMap {
/// The file path of the module containing the sourcemap data URL
pub origin_path: ResolvedVc<FileSystemPath>,
/// The Base64 encoded JSON sourcemap string
pub source_map: RcStr,
}

#[turbo_tasks::value_impl]
impl GenerateSourceMap for InlineSourceMap {
#[turbo_tasks::function]
pub async fn generate_source_map(&self) -> Result<Vc<OptionStringifiedSourceMap>> {
let source_map = maybe_decode_data_url(&self.source_map);
let source_map = resolve_source_map_sources(source_map.as_ref(), *self.origin_path).await?;
Ok(Vc::cell(source_map))
}
}

fn maybe_decode_data_url(url: &str) -> Option<Rope> {
const DATA_PREAMBLE: &str = "data:application/json;base64,";

if !url.starts_with(DATA_PREAMBLE) {
return None;
}
let data_b64 = &url[DATA_PREAMBLE.len()..];
data_encoding::BASE64
.decode(data_b64.as_bytes())
.ok()
.map(Rope::from)
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use turbopack_core::{
module_graph::ModuleGraph,
reference::ModuleReferences,
resolve::ModulePart,
source_map::OptionStringifiedSourceMap,
};

use super::chunk_item::EcmascriptModuleFacadeChunkItem;
Expand Down Expand Up @@ -224,7 +223,7 @@ impl EcmascriptAnalyzable for EcmascriptModuleFacadeModule {
code_generation: CodeGens::empty().to_resolved().await?,
async_module: ResolvedVc::cell(Some(self.async_module().to_resolved().await?)),
generate_source_map: false,
original_source_map: OptionStringifiedSourceMap::none().to_resolved().await?,
original_source_map: None,
exports: self.get_exports().to_resolved().await?,
async_module_info,
}
Expand Down
Loading