Skip to content

Commit b84a02b

Browse files
authoredApr 4, 2025··
Turbopack: use document.currentScript instead of chunk path literal (#77773)
### What? Instead of embedding the chunk filename into the chunk itself (which is a probably for content hashing), use `document.currentScript` to grab the chunk path.
1 parent 6bc472a commit b84a02b

File tree

15 files changed

+234
-122
lines changed

15 files changed

+234
-122
lines changed
 

Diff for: ‎crates/next-core/src/next_client/context.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use turbopack::{
1313
},
1414
resolve_options_context::ResolveOptionsContext,
1515
};
16-
use turbopack_browser::{react_refresh::assert_can_resolve_react_refresh, BrowserChunkingContext};
16+
use turbopack_browser::{
17+
react_refresh::assert_can_resolve_react_refresh, BrowserChunkingContext, CurrentChunkMethod,
18+
};
1719
use turbopack_core::{
1820
chunk::{
1921
module_id_strategies::ModuleIdStrategy, ChunkingConfig, ChunkingContext, MinifyType,
@@ -462,6 +464,7 @@ pub async fn get_client_chunking_context(
462464
SourceMapsType::None
463465
})
464466
.asset_base_path(asset_prefix)
467+
.current_chunk_method(CurrentChunkMethod::DocumentCurrentScript)
465468
.module_id_strategy(module_id_strategy);
466469

467470
if next_mode.is_development() {

Diff for: ‎turbopack/crates/turbopack-browser/src/chunking_context.rs

+23
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@ use crate::ecmascript::{
3232
list::asset::{EcmascriptDevChunkList, EcmascriptDevChunkListSource},
3333
};
3434

35+
#[turbo_tasks::value]
36+
#[derive(Debug, Clone, Copy, Hash)]
37+
pub enum CurrentChunkMethod {
38+
StringLiteral,
39+
DocumentCurrentScript,
40+
}
41+
42+
pub const CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR: &str =
43+
"typeof document === \"object\" ? document.currentScript : undefined";
44+
3545
pub struct BrowserChunkingContextBuilder {
3646
chunking_context: BrowserChunkingContext,
3747
}
@@ -92,6 +102,11 @@ impl BrowserChunkingContextBuilder {
92102
self
93103
}
94104

105+
pub fn current_chunk_method(mut self, method: CurrentChunkMethod) -> Self {
106+
self.chunking_context.current_chunk_method = method;
107+
self
108+
}
109+
95110
pub fn module_id_strategy(
96111
mut self,
97112
module_id_strategy: ResolvedVc<Box<dyn ModuleIdStrategy>>,
@@ -160,6 +175,8 @@ pub struct BrowserChunkingContext {
160175
minify_type: MinifyType,
161176
/// Whether to generate source maps
162177
source_maps_type: SourceMapsType,
178+
/// Method to use when figuring out the current chunk src
179+
current_chunk_method: CurrentChunkMethod,
163180
/// Whether to use manifest chunks for lazy compilation
164181
manifest_chunks: bool,
165182
/// The module id strategy to use
@@ -198,6 +215,7 @@ impl BrowserChunkingContext {
198215
runtime_type,
199216
minify_type: MinifyType::NoMinify,
200217
source_maps_type: SourceMapsType::Full,
218+
current_chunk_method: CurrentChunkMethod::StringLiteral,
201219
manifest_chunks: false,
202220
module_id_strategy: ResolvedVc::upcast(DevModuleIdStrategy::new_resolved()),
203221
chunking_configs: Default::default(),
@@ -297,6 +315,11 @@ impl BrowserChunkingContext {
297315
},
298316
)
299317
}
318+
319+
#[turbo_tasks::function]
320+
pub fn current_chunk_method(&self) -> Vc<CurrentChunkMethod> {
321+
self.current_chunk_method.cell()
322+
}
300323
}
301324

302325
#[turbo_tasks::value_impl]

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

+29-16
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::io::Write;
22

33
use anyhow::{bail, Result};
4+
use either::Either;
45
use indoc::writedoc;
56
use turbo_rcstr::RcStr;
67
use turbo_tasks::{ResolvedVc, Vc};
@@ -19,7 +20,10 @@ use super::{
1920
chunk::EcmascriptBrowserChunk, content_entry::EcmascriptBrowserChunkContentEntries,
2021
merged::merger::EcmascriptBrowserChunkContentMerger, version::EcmascriptBrowserChunkVersion,
2122
};
22-
use crate::BrowserChunkingContext;
23+
use crate::{
24+
chunking_context::{CurrentChunkMethod, CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR},
25+
BrowserChunkingContext,
26+
};
2327

2428
#[turbo_tasks::value(serialization = "none")]
2529
pub struct EcmascriptBrowserChunkContent {
@@ -67,21 +71,31 @@ impl EcmascriptBrowserChunkContent {
6771
#[turbo_tasks::function]
6872
async fn code(self: Vc<Self>) -> Result<Vc<Code>> {
6973
let this = self.await?;
70-
let output_root = this.chunking_context.output_root().await?;
7174
let source_maps = *this
7275
.chunking_context
7376
.reference_chunk_source_maps(*ResolvedVc::upcast(this.chunk))
7477
.await?;
75-
let chunk_path_vc = this.chunk.path();
76-
let chunk_path = chunk_path_vc.await?;
77-
let chunk_server_path = if let Some(path) = output_root.get_path_to(&chunk_path) {
78-
path
79-
} else {
80-
bail!(
81-
"chunk path {} is not in output root {}",
82-
chunk_path.to_string(),
83-
output_root.to_string()
84-
);
78+
// Lifetime hack to pull out the var into this scope
79+
let chunk_path;
80+
let script_or_path = match *this.chunking_context.current_chunk_method().await? {
81+
CurrentChunkMethod::StringLiteral => {
82+
let output_root = this.chunking_context.output_root().await?;
83+
let chunk_path_vc = this.chunk.path();
84+
chunk_path = chunk_path_vc.await?;
85+
let chunk_server_path = if let Some(path) = output_root.get_path_to(&chunk_path) {
86+
path
87+
} else {
88+
bail!(
89+
"chunk path {} is not in output root {}",
90+
chunk_path.to_string(),
91+
output_root.to_string()
92+
);
93+
};
94+
Either::Left(StringifyJs(chunk_server_path))
95+
}
96+
CurrentChunkMethod::DocumentCurrentScript => {
97+
Either::Right(CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR)
98+
}
8599
};
86100
let mut code = CodeBuilder::new(source_maps);
87101

@@ -95,9 +109,8 @@ impl EcmascriptBrowserChunkContent {
95109
writedoc!(
96110
code,
97111
r#"
98-
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([{chunk_path}, {{
99-
"#,
100-
chunk_path = StringifyJs(chunk_server_path)
112+
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([{script_or_path}, {{
113+
"#
101114
)?;
102115

103116
let content = this.content.await?;
@@ -115,7 +128,7 @@ impl EcmascriptBrowserChunkContent {
115128
let mut code = code.build();
116129

117130
if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() {
118-
code = minify(&*chunk_path_vc.await?, &code, source_maps, mangle)?;
131+
code = minify(&code, source_maps, mangle)?;
119132
}
120133

121134
Ok(code.cell())

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

+28-15
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::io::Write;
22

33
use anyhow::{bail, Result};
4+
use either::Either;
45
use indoc::writedoc;
56
use serde::Serialize;
67
use turbo_rcstr::RcStr;
@@ -26,7 +27,10 @@ use turbopack_ecmascript::{
2627
};
2728
use turbopack_ecmascript_runtime::RuntimeType;
2829

29-
use crate::BrowserChunkingContext;
30+
use crate::{
31+
chunking_context::{CurrentChunkMethod, CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR},
32+
BrowserChunkingContext,
33+
};
3034

3135
/// An Ecmascript chunk that:
3236
/// * Contains the Turbopack browser runtime code; and
@@ -74,22 +78,32 @@ impl EcmascriptBrowserEvaluateChunk {
7478
let chunking_context = this.chunking_context.await?;
7579
let environment = this.chunking_context.environment();
7680

77-
let output_root = this.chunking_context.output_root().await?;
7881
let output_root_to_root_path = this.chunking_context.output_root_to_root_path();
7982
let source_maps = *this
8083
.chunking_context
8184
.reference_chunk_source_maps(Vc::upcast(self))
8285
.await?;
83-
let chunk_path_vc = self.path();
84-
let chunk_path = chunk_path_vc.await?;
85-
let chunk_public_path = if let Some(path) = output_root.get_path_to(&chunk_path) {
86-
path
87-
} else {
88-
bail!(
89-
"chunk path {} is not in output root {}",
90-
chunk_path.to_string(),
91-
output_root.to_string()
92-
);
86+
// Lifetime hack to pull out the var into this scope
87+
let chunk_path;
88+
let script_or_path = match *this.chunking_context.current_chunk_method().await? {
89+
CurrentChunkMethod::StringLiteral => {
90+
let output_root = this.chunking_context.output_root().await?;
91+
let chunk_path_vc = self.path();
92+
chunk_path = chunk_path_vc.await?;
93+
let chunk_server_path = if let Some(path) = output_root.get_path_to(&chunk_path) {
94+
path
95+
} else {
96+
bail!(
97+
"chunk path {} is not in output root {}",
98+
chunk_path.to_string(),
99+
output_root.to_string()
100+
);
101+
};
102+
Either::Left(StringifyJs(chunk_server_path))
103+
}
104+
CurrentChunkMethod::DocumentCurrentScript => {
105+
Either::Right(CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR)
106+
}
93107
};
94108

95109
let other_chunks_data = self.chunks_data().await?;
@@ -139,12 +153,11 @@ impl EcmascriptBrowserEvaluateChunk {
139153
code,
140154
r#"
141155
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([
142-
{},
156+
{script_or_path},
143157
{{}},
144158
{}
145159
]);
146160
"#,
147-
StringifyJs(&chunk_public_path),
148161
StringifyJs(&params),
149162
)?;
150163

@@ -181,7 +194,7 @@ impl EcmascriptBrowserEvaluateChunk {
181194
let mut code = code.build();
182195

183196
if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() {
184-
code = minify(&*chunk_path_vc.await?, &code, source_maps, mangle)?;
197+
code = minify(&code, source_maps, mangle)?;
185198
}
186199

187200
Ok(code.cell())

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

+58-39
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
use std::io::Write;
22

33
use anyhow::{Context, Result};
4+
use either::Either;
45
use indoc::writedoc;
5-
use serde::Serialize;
6-
use turbo_tasks::{FxIndexMap, IntoTraitRef, ResolvedVc, TryJoinIterExt, Vc};
6+
use serde::{Deserialize, Serialize};
7+
use turbo_rcstr::RcStr;
8+
use turbo_tasks::{
9+
trace::TraceRawVcs, FxIndexMap, IntoTraitRef, NonLocalValue, ResolvedVc, TryJoinIterExt, Vc,
10+
};
711
use turbo_tasks_fs::File;
812
use turbopack_core::{
913
asset::{Asset, AssetContent},
@@ -21,11 +25,20 @@ use super::{
2125
update::update_chunk_list,
2226
version::EcmascriptDevChunkListVersion,
2327
};
28+
use crate::chunking_context::{
29+
CurrentChunkMethod, CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR,
30+
};
31+
32+
#[derive(Clone, Debug, Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, NonLocalValue)]
33+
enum CurrentChunkMethodWithData {
34+
StringLiteral(RcStr),
35+
DocumentCurrentScript,
36+
}
2437

2538
/// Contents of an [`EcmascriptDevChunkList`].
2639
#[turbo_tasks::value]
2740
pub(super) struct EcmascriptDevChunkListContent {
28-
chunk_list_path: String,
41+
current_chunk_method: CurrentChunkMethodWithData,
2942
pub(super) chunks_contents: FxIndexMap<String, ResolvedVc<Box<dyn VersionedContent>>>,
3043
source: EcmascriptDevChunkListSource,
3144
}
@@ -37,25 +50,35 @@ impl EcmascriptDevChunkListContent {
3750
pub async fn new(chunk_list: Vc<EcmascriptDevChunkList>) -> Result<Vc<Self>> {
3851
let chunk_list_ref = chunk_list.await?;
3952
let output_root = chunk_list_ref.chunking_context.output_root().await?;
53+
let current_chunk_method = match *chunk_list_ref
54+
.chunking_context
55+
.current_chunk_method()
56+
.await?
57+
{
58+
CurrentChunkMethod::StringLiteral => {
59+
let path = output_root
60+
.get_path_to(&*chunk_list.path().await?)
61+
.context("chunk list path not in output root")?
62+
.into();
63+
CurrentChunkMethodWithData::StringLiteral(path)
64+
}
65+
CurrentChunkMethod::DocumentCurrentScript => {
66+
CurrentChunkMethodWithData::DocumentCurrentScript
67+
}
68+
};
4069
Ok(EcmascriptDevChunkListContent {
41-
chunk_list_path: output_root
42-
.get_path_to(&*chunk_list.path().await?)
43-
.context("chunk list path not in output root")?
44-
.to_string(),
70+
current_chunk_method,
4571
chunks_contents: chunk_list_ref
4672
.chunks
4773
.await?
4874
.iter()
49-
.map(|chunk| {
50-
let output_root = output_root.clone();
51-
async move {
52-
Ok((
53-
output_root
54-
.get_path_to(&*chunk.path().await?)
55-
.map(|path| path.to_string()),
56-
chunk.versioned_content().to_resolved().await?,
57-
))
58-
}
75+
.map(async |chunk| {
76+
Ok((
77+
output_root
78+
.get_path_to(&*chunk.path().await?)
79+
.map(|path| path.to_string()),
80+
chunk.versioned_content().to_resolved().await?,
81+
))
5982
})
6083
.try_join()
6184
.await?
@@ -111,10 +134,17 @@ impl EcmascriptDevChunkListContent {
111134
pub(super) async fn code(self: Vc<Self>) -> Result<Vc<Code>> {
112135
let this = self.await?;
113136

114-
let params = EcmascriptDevChunkListParams {
115-
path: &this.chunk_list_path,
116-
chunks: this.chunks_contents.keys().map(|s| s.as_str()).collect(),
117-
source: this.source,
137+
let chunks = this
138+
.chunks_contents
139+
.keys()
140+
.map(|s| s.as_str())
141+
.collect::<Vec<_>>();
142+
143+
let script_or_path = match &this.current_chunk_method {
144+
CurrentChunkMethodWithData::StringLiteral(path) => Either::Left(StringifyJs(path)),
145+
CurrentChunkMethodWithData::DocumentCurrentScript => {
146+
Either::Right(CURRENT_CHUNK_METHOD_DOCUMENT_CURRENT_SCRIPT_EXPR)
147+
}
118148
};
119149

120150
let mut code = CodeBuilder::default();
@@ -125,14 +155,14 @@ impl EcmascriptDevChunkListContent {
125155
writedoc!(
126156
code,
127157
r#"
128-
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([
129-
{},
130-
{{}},
131-
]);
132-
(globalThis.TURBOPACK_CHUNK_LISTS = globalThis.TURBOPACK_CHUNK_LISTS || []).push({:#});
158+
(globalThis.TURBOPACK_CHUNK_LISTS = globalThis.TURBOPACK_CHUNK_LISTS || []).push({{
159+
script: {script_or_path},
160+
chunks: {:#},
161+
source: {:#}
162+
}});
133163
"#,
134-
StringifyJs(&this.chunk_list_path),
135-
StringifyJs(&params),
164+
StringifyJs(&chunks),
165+
StringifyJs(&this.source),
136166
)?;
137167

138168
Ok(Code::cell(code.build()))
@@ -159,14 +189,3 @@ impl VersionedContent for EcmascriptDevChunkListContent {
159189
update_chunk_list(self, from_version)
160190
}
161191
}
162-
163-
#[derive(Debug, Clone, Serialize)]
164-
#[serde(rename_all = "camelCase")]
165-
struct EcmascriptDevChunkListParams<'a> {
166-
/// Path to the chunk list to register.
167-
path: &'a str,
168-
/// All chunks that belong to the chunk list.
169-
chunks: Vec<&'a str>,
170-
/// Where this chunk list is from.
171-
source: EcmascriptDevChunkListSource,
172-
}

Diff for: ‎turbopack/crates/turbopack-browser/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ pub(crate) mod chunking_context;
77
pub mod ecmascript;
88
pub mod react_refresh;
99

10-
pub use chunking_context::{BrowserChunkingContext, BrowserChunkingContextBuilder};
10+
pub use chunking_context::{
11+
BrowserChunkingContext, BrowserChunkingContextBuilder, CurrentChunkMethod,
12+
};
1113

1214
pub fn register() {
1315
turbo_tasks::register();

Diff for: ‎turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/dev-base.ts

+5-20
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@ const devModuleCache: ModuleCache<HotModule> = Object.create(null);
2020
type RefreshRuntimeGlobals =
2121
import("@next/react-refresh-utils/dist/runtime").RefreshRuntimeGlobals;
2222

23-
// Workers are loaded via blob object urls and aren't relative to the main context, this gets
24-
// prefixed to chunk urls in the worker.
25-
// declare var TURBOPACK_WORKER_LOCATION: string;
26-
// declare var CHUNK_BASE_PATH: string;
2723
declare var $RefreshHelpers$: RefreshRuntimeGlobals["$RefreshHelpers$"];
2824
declare var $RefreshReg$: RefreshRuntimeGlobals["$RefreshReg$"];
2925
declare var $RefreshSig$: RefreshRuntimeGlobals["$RefreshSig$"];
@@ -1080,11 +1076,13 @@ function disposeChunk(chunkPath: ChunkPath): boolean {
10801076
* Subscribes to chunk list updates from the update server and applies them.
10811077
*/
10821078
function registerChunkList(
1083-
chunkUpdateProvider: ChunkUpdateProvider,
10841079
chunkList: ChunkList
10851080
) {
1086-
const chunkListPath = chunkList.path;
1087-
chunkUpdateProvider.push([
1081+
const chunkListScript = chunkList.script;
1082+
const chunkListPath = getPathFromScript(chunkListScript);
1083+
// The "chunk" is also registered to finish the loading in the backend
1084+
BACKEND.registerChunk(chunkListPath as string as ChunkPath);
1085+
globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS!.push([
10881086
chunkListPath,
10891087
handleApply.bind(null, chunkListPath),
10901088
]);
@@ -1108,16 +1106,3 @@ function registerChunkList(
11081106
}
11091107

11101108
globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS ??= [];
1111-
1112-
const chunkListsToRegister = globalThis.TURBOPACK_CHUNK_LISTS;
1113-
if (Array.isArray(chunkListsToRegister)) {
1114-
for (const chunkList of chunkListsToRegister) {
1115-
registerChunkList(globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS, chunkList);
1116-
}
1117-
}
1118-
1119-
globalThis.TURBOPACK_CHUNK_LISTS = {
1120-
push: (chunkList) => {
1121-
registerChunkList(globalThis.TURBOPACK_CHUNK_UPDATE_LISTENERS!, chunkList);
1122-
},
1123-
} satisfies ChunkListProvider;

Diff for: ‎turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts

+32-4
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,17 @@
1111
/// <reference path="../base/globals.d.ts" />
1212
/// <reference path="../../../shared/runtime-utils.ts" />
1313

14+
// Used in WebWorkers to tell the runtime about the chunk base path
1415
declare var TURBOPACK_WORKER_LOCATION: string;
16+
// Used in WebWorkers to tell the runtime about the current chunk url since it can't be detected via document.currentScript
17+
// Note it's stored in reversed order to use push and pop
18+
declare var TURBOPACK_NEXT_CHUNK_URLS: ChunkUrl[] | undefined;
19+
20+
// Injected by rust code
1521
declare var CHUNK_BASE_PATH: string;
1622
declare var CHUNK_SUFFIX_PATH: string;
23+
24+
// Provided by build or dev base
1725
declare function instantiateModule(id: ModuleId, source: SourceInfo): Module;
1826

1927
type RuntimeParams = {
@@ -22,13 +30,13 @@ type RuntimeParams = {
2230
};
2331

2432
type ChunkRegistration = [
25-
chunkPath: ChunkPath,
33+
chunkPath: ChunkScript,
2634
chunkModules: ModuleFactories,
2735
params: RuntimeParams | undefined
2836
];
2937

3038
type ChunkList = {
31-
path: ChunkListPath;
39+
script: ChunkListScript;
3240
chunks: ChunkData[];
3341
source: "entry" | "dynamic";
3442
};
@@ -245,7 +253,9 @@ function resolveAbsolutePath(modulePath?: string): string {
245253
}
246254

247255
function getWorkerBlobURL(chunks: ChunkPath[]): string {
248-
let bootstrap = `self.TURBOPACK_WORKER_LOCATION = ${JSON.stringify(location.origin)};importScripts(${chunks.map(c => (`self.TURBOPACK_WORKER_LOCATION + ${JSON.stringify(getChunkRelativeUrl(c))}`)).join(", ")});`;
256+
let bootstrap = `self.TURBOPACK_WORKER_LOCATION = ${JSON.stringify(location.origin)};
257+
self.TURBOPACK_NEXT_CHUNK_URLS = ${JSON.stringify(chunks.reverse().map(getChunkRelativeUrl), null, 2)};
258+
importScripts(...self.TURBOPACK_NEXT_CHUNK_URLS.map(c => self.TURBOPACK_WORKER_LOCATION + c).reverse());`;
249259
let blob = new Blob([bootstrap], { type: "text/javascript" });
250260
return URL.createObjectURL(blob);
251261
}
@@ -304,6 +314,23 @@ function getChunkRelativeUrl(chunkPath: ChunkPath | ChunkListPath): ChunkUrl {
304314
.join("/")}${CHUNK_SUFFIX_PATH}` as ChunkUrl;
305315
}
306316

317+
/**
318+
* Return the ChunkPath from a ChunkScript.
319+
*/
320+
function getPathFromScript(chunkScript: ChunkPath | ChunkScript): ChunkPath;
321+
function getPathFromScript(chunkScript: ChunkListPath | ChunkListScript): ChunkListPath;
322+
function getPathFromScript(chunkScript: ChunkPath | ChunkListPath | ChunkScript | ChunkListScript): ChunkPath | ChunkListPath {
323+
if (typeof chunkScript === "string") {
324+
return chunkScript as ChunkPath | ChunkListPath;
325+
}
326+
const chunkUrl = typeof TURBOPACK_NEXT_CHUNK_URLS !== "undefined"
327+
? TURBOPACK_NEXT_CHUNK_URLS.pop()!
328+
: chunkScript.getAttribute("src")!;
329+
const src = decodeURIComponent(chunkUrl.replace(/[?#].*$/, ""));
330+
const path = src.startsWith(CHUNK_BASE_PATH) ? src.slice(CHUNK_BASE_PATH.length) : src;
331+
return path as ChunkPath | ChunkListPath;
332+
}
333+
307334
/**
308335
* Marks a chunk list as a runtime chunk list. There can be more than one
309336
* runtime chunk list. For instance, integration tests can have multiple chunk
@@ -314,10 +341,11 @@ function markChunkListAsRuntime(chunkListPath: ChunkListPath) {
314341
}
315342

316343
function registerChunk([
317-
chunkPath,
344+
chunkScript,
318345
chunkModules,
319346
runtimeParams,
320347
]: ChunkRegistration) {
348+
const chunkPath = getPathFromScript(chunkScript);
321349
for (const [moduleId, moduleFactory] of Object.entries(chunkModules)) {
322350
if (!moduleFactories[moduleId]) {
323351
moduleFactories[moduleId] = moduleFactory;

Diff for: ‎turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/dom/runtime-backend-dom.ts

+1
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ const chunkResolvers: Map<ChunkUrl, ChunkResolver> = new Map();
151151
if (isCss(chunkUrl)) {
152152
// ignore
153153
} else if (isJs(chunkUrl)) {
154+
self.TURBOPACK_NEXT_CHUNK_URLS!.push(chunkUrl);
154155
importScripts(TURBOPACK_WORKER_LOCATION + chunkUrl);
155156
} else {
156157
throw new Error(`can't infer type of chunk from URL ${chunkUrl} in worker`);

Diff for: ‎turbopack/crates/turbopack-ecmascript-runtime/js/src/shared/runtime-types.d.ts

+3
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@
77
* specific to the runtime context.
88
*/
99

10+
type CurrentScript = { getAttribute: (name: string) => string | null };
1011
type ChunkListPath = string & { readonly brand: unique symbol };
12+
type ChunkListScript = CurrentScript & { readonly brand: unique symbol };
1113
type ChunkPath = string & { readonly brand: unique symbol };
14+
type ChunkScript = CurrentScript & { readonly brand: unique symbol };
1215
type ChunkUrl = string & { readonly brand: unique symbol };
1316
type ModuleId = string;
1417

Diff for: ‎turbopack/crates/turbopack-ecmascript-runtime/src/browser_runtime.rs

+16-1
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,29 @@ pub async fn get_browser_runtime_code(
149149
);
150150
}
151151

152-
// Registering chunks depends on the BACKEND variable, which is set by the
152+
// Registering chunks and chunk lists depends on the BACKEND variable, which is set by the
153153
// specific runtime code, hence it must be appended after it.
154154
writedoc!(
155155
code,
156156
r#"
157157
const chunksToRegister = globalThis.TURBOPACK;
158158
globalThis.TURBOPACK = {{ push: registerChunk }};
159159
chunksToRegister.forEach(registerChunk);
160+
"#
161+
)?;
162+
if matches!(*runtime_type, RuntimeType::Development) {
163+
writedoc!(
164+
code,
165+
r#"
166+
const chunkListsToRegister = globalThis.TURBOPACK_CHUNK_LISTS || [];
167+
chunkListsToRegister.forEach(registerChunkList);
168+
globalThis.TURBOPACK_CHUNK_LISTS = {{ push: registerChunkList }};
169+
"#
170+
)?;
171+
}
172+
writedoc!(
173+
code,
174+
r#"
160175
}})();
161176
"#
162177
)?;

Diff for: ‎turbopack/crates/turbopack-ecmascript/src/minify.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,20 @@ use swc_core::{
2323
},
2424
};
2525
use tracing::{instrument, Level};
26-
use turbo_tasks_fs::FileSystemPath;
2726
use turbopack_core::code_builder::{Code, CodeBuilder};
2827

2928
use crate::parse::generate_js_source_map;
3029

3130
#[instrument(level = Level::INFO, skip_all)]
32-
pub fn minify(path: &FileSystemPath, code: &Code, source_maps: bool, mangle: bool) -> Result<Code> {
31+
pub fn minify(code: &Code, source_maps: bool, mangle: bool) -> Result<Code> {
3332
let source_maps = source_maps
3433
.then(|| code.generate_source_map_ref())
3534
.transpose()?;
3635

3736
let cm = Arc::new(SwcSourceMap::new(FilePathMapping::empty()));
3837
let (src, mut src_map_buf) = {
3938
let fm = cm.new_source_file(
40-
FileName::Custom(path.path.to_string()).into(),
39+
FileName::Anon.into(),
4140
code.source_code().to_str()?.into_owned(),
4241
);
4342

Diff for: ‎turbopack/crates/turbopack-nodejs/src/ecmascript/node/content.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ impl EcmascriptBuildNodeChunkContent {
5252
.chunking_context
5353
.reference_chunk_source_maps(*ResolvedVc::upcast(this.chunk))
5454
.await?;
55-
let chunk_path_vc = this.chunk.path();
5655

5756
let mut code = CodeBuilder::default();
5857

@@ -79,7 +78,7 @@ impl EcmascriptBuildNodeChunkContent {
7978
let mut code = code.build();
8079

8180
if let MinifyType::Minify { mangle } = this.chunking_context.await?.minify_type() {
82-
code = minify(&*chunk_path_vc.await?, &code, source_maps, mangle)?;
81+
code = minify(&code, source_maps, mangle)?;
8382
}
8483

8584
Ok(code.cell())

Diff for: ‎turbopack/crates/turbopack-tests/tests/snapshot/runtime/default_dev_runtime/output/b1abf_turbopack-tests_tests_snapshot_runtime_default_dev_runtime_input_index_75df6705.js

+25-16
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: ‎turbopack/crates/turbopack-tests/tests/snapshot/runtime/default_dev_runtime/output/b1abf_turbopack-tests_tests_snapshot_runtime_default_dev_runtime_input_index_75df6705.js.map

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.