Skip to content

Commit

Permalink
process source maps from webpack loaders (#7761)
Browse files Browse the repository at this point in the history
### Description

* Handle source maps returned webpack loaders
* add workaround for Node.js bug to allow it using sectioned source maps
* import source map for Source file

### Testing Instructions

<!--
  Give a quick description of steps to test your changes.
-->


Closes PACK-2783
  • Loading branch information
sokra authored Mar 19, 2024
1 parent d0275e0 commit 0f31686
Show file tree
Hide file tree
Showing 155 changed files with 215 additions and 7 deletions.
12 changes: 10 additions & 2 deletions crates/turbopack-core/src/source_map/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,13 @@ impl SourceMap {
}

pub async fn new_from_file(file: Vc<FileSystemPath>) -> Result<Option<Self>> {
let read = file.read().await?;
let Some(contents) = read.as_content() else {
let read = file.read();
Self::new_from_file_content(read).await
}

pub async fn new_from_file_content(content: Vc<FileContent>) -> Result<Option<Self>> {
let content = &content.await?;
let Some(contents) = content.as_content() else {
return Ok(None);
};
let Ok(map) = DecodedMap::from_reader(contents.read()) else {
Expand Down Expand Up @@ -259,9 +264,12 @@ impl SourceMap {
}

// My kingdom for a decent dedent macro with interpolation!
// NOTE: The empty `sources` array is technically incorrect, but there is a bug
// in Node.js that requires sectioned source maps to have a `sources` array.
let mut rope = RopeBuilder::from(
r#"{
"version": 3,
"sources": [],
"sections": ["#,
);

Expand Down
14 changes: 14 additions & 0 deletions crates/turbopack-ecmascript/src/references/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,7 @@ pub(crate) async fn analyse_ecmascript_module_internal(
}
}
}
let mut source_map_from_comment = false;
if let Some((_, path)) = paths_by_pos.into_iter().max_by_key(|&(pos, _)| pos) {
let origin_path = origin.origin_path();
if path.ends_with(".map") {
Expand All @@ -504,13 +505,26 @@ pub(crate) async fn analyse_ecmascript_module_internal(
source_map,
source_map_origin,
));
source_map_from_comment = true;
} else if path.starts_with("data:application/json;base64,") {
let source_map_origin = origin_path;
let source_map = maybe_decode_data_url(path.to_string());
analysis.set_source_map(convert_to_turbopack_source_map(
source_map,
source_map_origin,
));
source_map_from_comment = true;
}
}
if !source_map_from_comment {
if let Some(generate_source_map) =
Vc::try_resolve_sidecast::<Box<dyn GenerateSourceMap>>(source).await?
{
let source_map_origin = source.ident().path();
analysis.set_source_map(convert_to_turbopack_source_map(
generate_source_map.generate_source_map(),
source_map_origin,
));
}
}

Expand Down
10 changes: 9 additions & 1 deletion crates/turbopack-node/js/src/transforms/webpack-loaders.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,15 @@ const transform = (
}
if (!result.result) return reject(new Error("No result from loaders"));
const [source, map] = result.result;
resolve({ source, map });
resolve({
source,
map:
typeof map === "string"
? map
: typeof map === "object"
? JSON.stringify(map)
: undefined,
});
}
);
});
Expand Down
35 changes: 31 additions & 4 deletions crates/turbopack-node/src/transforms/webpack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use turbopack_core::{
resolve,
},
source::Source,
source_map::{GenerateSourceMap, OptionSourceMap, SourceMap},
source_transform::SourceTransform,
virtual_source::VirtualSource,
};
Expand Down Expand Up @@ -144,9 +145,18 @@ impl Asset for WebpackLoadersProcessedAsset {
}
}

#[turbo_tasks::value_impl]
impl GenerateSourceMap for WebpackLoadersProcessedAsset {
#[turbo_tasks::function]
async fn generate_source_map(self: Vc<Self>) -> Result<Vc<OptionSourceMap>> {
Ok(Vc::cell(self.process().await?.source_map))
}
}

#[turbo_tasks::value]
struct ProcessWebpackLoadersResult {
content: Vc<AssetContent>,
source_map: Option<Vc<SourceMap>>,
assets: Vec<Vc<VirtualSource>>,
}

Expand Down Expand Up @@ -180,15 +190,19 @@ impl WebpackLoadersProcessedAsset {
return Ok(ProcessWebpackLoadersResult {
content: AssetContent::File(FileContent::NotFound.cell()).cell(),
assets: Vec::new(),
source_map: None,
}
.cell());
};
let content = content.content().to_str()?;
let evaluate_context = transform.evaluate_context;

let webpack_loaders_executor = webpack_loaders_executor(evaluate_context).module();
let resource_fs_path = this.source.ident().path().await?;
let Some(resource_path) = project_path.await?.get_relative_path_to(&resource_fs_path)
let resource_fs_path = this.source.ident().path();
let resource_fs_path_ref = resource_fs_path.await?;
let Some(resource_path) = project_path
.await?
.get_relative_path_to(&resource_fs_path_ref)
else {
bail!("Resource path need to be on project filesystem");
};
Expand All @@ -215,6 +229,7 @@ impl WebpackLoadersProcessedAsset {
return Ok(ProcessWebpackLoadersResult {
content: AssetContent::File(FileContent::NotFound.cell()).cell(),
assets: Vec::new(),
source_map: None,
}
.cell());
};
Expand All @@ -223,11 +238,23 @@ impl WebpackLoadersProcessedAsset {
)
.context("Unable to deserializate response from webpack loaders transform operation")?;

// TODO handle SourceMap
// handle SourceMap
let source_map = if let Some(source_map) = processed.map {
SourceMap::new_from_file_content(FileContent::Content(File::from(source_map)).cell())
.await?
.map(|source_map| source_map.cell())
} else {
None
};
let file = File::from(processed.source);
let assets = emitted_assets_to_virtual_sources(processed.assets);
let content = AssetContent::File(FileContent::Content(file).cell()).cell();
Ok(ProcessWebpackLoadersResult { content, assets }.cell())
Ok(ProcessWebpackLoadersResult {
content,
assets,
source_map,
}
.cell())
}
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 0f31686

Please sign in to comment.