Skip to content

Commit 3da9d70

Browse files
authored
Turbopack: avoid deriving css source map path from generated code path (#77735)
### What? avoid using the original asset path for the source map path instead compute our own path based on similar input. This will become more important when we are using content hashes for files.
1 parent 1751db0 commit 3da9d70

File tree

15 files changed

+412
-236
lines changed

15 files changed

+412
-236
lines changed

Diff for: test/integration/css-minify/test/index.test.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@ function runTests() {
2525
"/* [project]/test/integration/css-minify/styles/global.css [client] (css) */
2626
.a{--var-1:-50%;--var-2:-50%}.b{--var-1:0;--var-2:-50%}
2727
28-
/*# sourceMappingURL=test_integration_css-minify_styles_global_411632c3.css.map*/
29-
"
28+
/*# sourceMappingURL=test_integration_css-minify_styles_global_411632c3.css.map*/"
3029
`)
3130
} else {
3231
expect(css).toMatchInlineSnapshot(

Diff for: turbopack/crates/turbopack-browser/src/ecmascript/chunk.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use turbo_tasks_fs::FileSystemPath;
55
use turbopack_core::{
66
asset::{Asset, AssetContent},
77
chunk::{Chunk, ChunkingContext, OutputChunk, OutputChunkRuntimeInfo},
8+
ident::AssetIdent,
89
introspect::{Introspectable, IntrospectableChildren},
910
output::{OutputAsset, OutputAssets},
1011
source_map::{GenerateSourceMap, OptionStringifiedSourceMap, SourceMapAsset},
@@ -35,6 +36,22 @@ impl EcmascriptBrowserChunk {
3536
}
3637
.cell()
3738
}
39+
40+
#[turbo_tasks::function]
41+
async fn source_map(self: Vc<Self>) -> Result<Vc<SourceMapAsset>> {
42+
let this = self.await?;
43+
Ok(SourceMapAsset::new(
44+
Vc::upcast(*this.chunking_context),
45+
this.ident_for_path(),
46+
Vc::upcast(self),
47+
))
48+
}
49+
}
50+
51+
impl EcmascriptBrowserChunk {
52+
fn ident_for_path(&self) -> Vc<AssetIdent> {
53+
self.chunk.ident().with_modifier(modifier())
54+
}
3855
}
3956

4057
#[turbo_tasks::value_impl]
@@ -71,6 +88,7 @@ impl EcmascriptBrowserChunk {
7188
*this.chunking_context,
7289
self,
7390
this.chunk.chunk_content(),
91+
self.source_map(),
7492
))
7593
}
7694

@@ -84,7 +102,7 @@ impl EcmascriptBrowserChunk {
84102
impl OutputAsset for EcmascriptBrowserChunk {
85103
#[turbo_tasks::function]
86104
fn path(&self) -> Vc<FileSystemPath> {
87-
let ident = self.chunk.ident().with_modifier(modifier());
105+
let ident = self.ident_for_path();
88106
self.chunking_context.chunk_path(ident, ".js".into())
89107
}
90108

@@ -107,9 +125,7 @@ impl OutputAsset for EcmascriptBrowserChunk {
107125
references.extend(chunk_references.iter().copied());
108126

109127
if include_source_map {
110-
references.push(ResolvedVc::upcast(
111-
SourceMapAsset::new(Vc::upcast(self)).to_resolved().await?,
112-
));
128+
references.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
113129
}
114130

115131
Ok(Vc::cell(references))

Diff for: turbopack/crates/turbopack-browser/src/ecmascript/content.rs

+23-17
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ use anyhow::{bail, Result};
44
use indoc::writedoc;
55
use turbo_rcstr::RcStr;
66
use turbo_tasks::{ResolvedVc, Vc};
7-
use turbo_tasks_fs::File;
7+
use turbo_tasks_fs::{rope::RopeBuilder, File};
88
use turbopack_core::{
99
asset::AssetContent,
1010
chunk::{ChunkingContext, MinifyType, ModuleId},
1111
code_builder::{Code, CodeBuilder},
1212
output::OutputAsset,
13-
source_map::{GenerateSourceMap, OptionStringifiedSourceMap},
13+
source_map::{GenerateSourceMap, OptionStringifiedSourceMap, SourceMapAsset},
1414
version::{MergeableVersionedContent, Version, VersionedContent, VersionedContentMerger},
1515
};
1616
use turbopack_ecmascript::{chunk::EcmascriptChunkContent, minify::minify, utils::StringifyJs};
@@ -26,6 +26,7 @@ pub struct EcmascriptBrowserChunkContent {
2626
pub(super) chunking_context: ResolvedVc<BrowserChunkingContext>,
2727
pub(super) chunk: ResolvedVc<EcmascriptBrowserChunk>,
2828
pub(super) content: ResolvedVc<EcmascriptChunkContent>,
29+
pub(super) source_map: ResolvedVc<SourceMapAsset>,
2930
}
3031

3132
#[turbo_tasks::value_impl]
@@ -35,11 +36,13 @@ impl EcmascriptBrowserChunkContent {
3536
chunking_context: ResolvedVc<BrowserChunkingContext>,
3637
chunk: ResolvedVc<EcmascriptBrowserChunk>,
3738
content: ResolvedVc<EcmascriptChunkContent>,
39+
source_map: ResolvedVc<SourceMapAsset>,
3840
) -> Result<Vc<Self>> {
3941
Ok(EcmascriptBrowserChunkContent {
4042
chunking_context,
4143
chunk,
4244
content,
45+
source_map,
4346
}
4447
.cell())
4548
}
@@ -80,7 +83,7 @@ impl EcmascriptBrowserChunkContent {
8083
output_root.to_string()
8184
);
8285
};
83-
let mut code = CodeBuilder::default();
86+
let mut code = CodeBuilder::new(source_maps);
8487

8588
// When a chunk is executed, it will either register itself with the current
8689
// instance of the runtime, or it will push itself onto the list of pending
@@ -109,17 +112,6 @@ impl EcmascriptBrowserChunkContent {
109112

110113
write!(code, "\n}}]);")?;
111114

112-
if source_maps && code.has_source_map() {
113-
let filename = chunk_path.file_name();
114-
write!(
115-
code,
116-
// findSourceMapURL assumes this co-located sourceMappingURL,
117-
// and needs to be adjusted in case this is ever changed.
118-
"\n\n//# sourceMappingURL={}.map",
119-
urlencoding::encode(filename)
120-
)?;
121-
}
122-
123115
let mut code = code.build();
124116

125117
if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() {
@@ -134,10 +126,24 @@ impl EcmascriptBrowserChunkContent {
134126
impl VersionedContent for EcmascriptBrowserChunkContent {
135127
#[turbo_tasks::function]
136128
async fn content(self: Vc<Self>) -> Result<Vc<AssetContent>> {
129+
let this = self.await?;
137130
let code = self.code().await?;
138-
Ok(AssetContent::file(
139-
File::from(code.source_code().clone()).into(),
140-
))
131+
132+
let rope = if code.has_source_map() {
133+
let mut rope_builder = RopeBuilder::default();
134+
rope_builder.concat(code.source_code());
135+
let source_map_path = this.source_map.path().await?;
136+
write!(
137+
rope_builder,
138+
"\n\n//# sourceMappingURL={}",
139+
urlencoding::encode(source_map_path.file_name())
140+
)?;
141+
rope_builder.build()
142+
} else {
143+
code.source_code().clone()
144+
};
145+
146+
Ok(AssetContent::file(File::from(rope).into()))
141147
}
142148

143149
#[turbo_tasks::function]

Diff for: turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs

+54-38
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use indoc::writedoc;
55
use serde::Serialize;
66
use turbo_rcstr::RcStr;
77
use turbo_tasks::{ReadRef, ResolvedVc, TryJoinIterExt, Value, ValueToString, Vc};
8-
use turbo_tasks_fs::{File, FileSystemPath};
8+
use turbo_tasks_fs::{rope::RopeBuilder, File, FileSystemPath};
99
use turbopack_core::{
1010
asset::{Asset, AssetContent},
1111
chunk::{
@@ -130,7 +130,7 @@ impl EcmascriptBrowserEvaluateChunk {
130130
runtime_module_ids,
131131
};
132132

133-
let mut code = CodeBuilder::default();
133+
let mut code = CodeBuilder::new(source_maps);
134134

135135
// We still use the `TURBOPACK` global variable to store the chunk here,
136136
// as there may be another runtime already loaded in the page.
@@ -178,17 +178,6 @@ impl EcmascriptBrowserEvaluateChunk {
178178
}
179179
}
180180

181-
if source_maps && code.has_source_map() {
182-
let filename = chunk_path.file_name();
183-
write!(
184-
code,
185-
// findSourceMapURL assumes this co-located sourceMappingURL,
186-
// and needs to be adjusted in case this is ever changed.
187-
"\n\n//# sourceMappingURL={}.map",
188-
urlencoding::encode(filename)
189-
)?;
190-
}
191-
192181
let mut code = code.build();
193182

194183
if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() {
@@ -197,25 +186,9 @@ impl EcmascriptBrowserEvaluateChunk {
197186

198187
Ok(code.cell())
199188
}
200-
}
201-
202-
#[turbo_tasks::value_impl]
203-
impl ValueToString for EcmascriptBrowserEvaluateChunk {
204-
#[turbo_tasks::function]
205-
fn to_string(&self) -> Vc<RcStr> {
206-
Vc::cell("Ecmascript Browser Evaluate Chunk".into())
207-
}
208-
}
209189

210-
#[turbo_tasks::function]
211-
fn modifier() -> Vc<RcStr> {
212-
Vc::cell("ecmascript browser evaluate chunk".into())
213-
}
214-
215-
#[turbo_tasks::value_impl]
216-
impl OutputAsset for EcmascriptBrowserEvaluateChunk {
217190
#[turbo_tasks::function]
218-
async fn path(&self) -> Result<Vc<FileSystemPath>> {
191+
async fn ident_for_path(&self) -> Result<Vc<AssetIdent>> {
219192
let mut ident = self.ident.owned().await?;
220193

221194
ident.add_modifier(modifier().to_resolved().await?);
@@ -238,8 +211,40 @@ impl OutputAsset for EcmascriptBrowserEvaluateChunk {
238211
.await?,
239212
);
240213

241-
let ident = AssetIdent::new(Value::new(ident));
242-
Ok(self.chunking_context.chunk_path(ident, ".js".into()))
214+
Ok(AssetIdent::new(Value::new(ident)))
215+
}
216+
217+
#[turbo_tasks::function]
218+
async fn source_map(self: Vc<Self>) -> Result<Vc<SourceMapAsset>> {
219+
let this = self.await?;
220+
Ok(SourceMapAsset::new(
221+
Vc::upcast(*this.chunking_context),
222+
self.ident_for_path(),
223+
Vc::upcast(self),
224+
))
225+
}
226+
}
227+
228+
#[turbo_tasks::value_impl]
229+
impl ValueToString for EcmascriptBrowserEvaluateChunk {
230+
#[turbo_tasks::function]
231+
fn to_string(&self) -> Vc<RcStr> {
232+
Vc::cell("Ecmascript Browser Evaluate Chunk".into())
233+
}
234+
}
235+
236+
#[turbo_tasks::function]
237+
fn modifier() -> Vc<RcStr> {
238+
Vc::cell("ecmascript browser evaluate chunk".into())
239+
}
240+
241+
#[turbo_tasks::value_impl]
242+
impl OutputAsset for EcmascriptBrowserEvaluateChunk {
243+
#[turbo_tasks::function]
244+
async fn path(self: Vc<Self>) -> Result<Vc<FileSystemPath>> {
245+
let this = self.await?;
246+
let ident = self.ident_for_path();
247+
Ok(this.chunking_context.chunk_path(ident, ".js".into()))
243248
}
244249

245250
#[turbo_tasks::function]
@@ -253,9 +258,7 @@ impl OutputAsset for EcmascriptBrowserEvaluateChunk {
253258
.await?;
254259

255260
if include_source_map {
256-
references.push(ResolvedVc::upcast(
257-
SourceMapAsset::new(Vc::upcast(self)).to_resolved().await?,
258-
));
261+
references.push(ResolvedVc::upcast(self.source_map().to_resolved().await?));
259262
}
260263

261264
for chunk_data in &*self.chunks_data().await? {
@@ -271,9 +274,22 @@ impl Asset for EcmascriptBrowserEvaluateChunk {
271274
#[turbo_tasks::function]
272275
async fn content(self: Vc<Self>) -> Result<Vc<AssetContent>> {
273276
let code = self.code().await?;
274-
Ok(AssetContent::file(
275-
File::from(code.source_code().clone()).into(),
276-
))
277+
278+
let rope = if code.has_source_map() {
279+
let mut rope_builder = RopeBuilder::default();
280+
rope_builder.concat(code.source_code());
281+
let source_map_path = self.source_map().path().await?;
282+
write!(
283+
rope_builder,
284+
"\n\n//# sourceMappingURL={}",
285+
urlencoding::encode(source_map_path.file_name())
286+
)?;
287+
rope_builder.build()
288+
} else {
289+
code.source_code().clone()
290+
};
291+
292+
Ok(AssetContent::file(File::from(rope).into()))
277293
}
278294
}
279295

0 commit comments

Comments
 (0)