Skip to content

Commit 686a782

Browse files
committed
Allow to opt into different chunk chunk methods
1 parent 7b20227 commit 686a782

File tree

7 files changed

+130
-26
lines changed

7 files changed

+130
-26
lines changed

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() {

turbopack/crates/turbopack-browser/src/chunking_context.rs

+20
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ 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+
3542
pub struct BrowserChunkingContextBuilder {
3643
chunking_context: BrowserChunkingContext,
3744
}
@@ -92,6 +99,11 @@ impl BrowserChunkingContextBuilder {
9299
self
93100
}
94101

102+
pub fn current_chunk_method(mut self, method: CurrentChunkMethod) -> Self {
103+
self.chunking_context.current_chunk_method = method;
104+
self
105+
}
106+
95107
pub fn module_id_strategy(
96108
mut self,
97109
module_id_strategy: ResolvedVc<Box<dyn ModuleIdStrategy>>,
@@ -160,6 +172,8 @@ pub struct BrowserChunkingContext {
160172
minify_type: MinifyType,
161173
/// Whether to generate source maps
162174
source_maps_type: SourceMapsType,
175+
/// Method to use when figuring out the current chunk src
176+
current_chunk_method: CurrentChunkMethod,
163177
/// Whether to use manifest chunks for lazy compilation
164178
manifest_chunks: bool,
165179
/// The module id strategy to use
@@ -198,6 +212,7 @@ impl BrowserChunkingContext {
198212
runtime_type,
199213
minify_type: MinifyType::NoMinify,
200214
source_maps_type: SourceMapsType::Full,
215+
current_chunk_method: CurrentChunkMethod::StringLiteral,
201216
manifest_chunks: false,
202217
module_id_strategy: ResolvedVc::upcast(DevModuleIdStrategy::new_resolved()),
203218
chunking_configs: Default::default(),
@@ -297,6 +312,11 @@ impl BrowserChunkingContext {
297312
},
298313
)
299314
}
315+
316+
#[turbo_tasks::function]
317+
pub fn current_chunk_method(&self) -> Vc<CurrentChunkMethod> {
318+
self.current_chunk_method.cell()
319+
}
300320
}
301321

302322
#[turbo_tasks::value_impl]

turbopack/crates/turbopack-browser/src/ecmascript/content.rs

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

3-
use anyhow::Result;
3+
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,7 @@ use super::{
1920
chunk::EcmascriptBrowserChunk, content_entry::EcmascriptBrowserChunkContentEntries,
2021
merged::merger::EcmascriptBrowserChunkContentMerger, version::EcmascriptBrowserChunkVersion,
2122
};
22-
use crate::BrowserChunkingContext;
23+
use crate::{chunking_context::CurrentChunkMethod, BrowserChunkingContext};
2324

2425
#[turbo_tasks::value(serialization = "none")]
2526
pub struct EcmascriptBrowserChunkContent {
@@ -71,6 +72,26 @@ impl EcmascriptBrowserChunkContent {
7172
.chunking_context
7273
.reference_chunk_source_maps(*ResolvedVc::upcast(this.chunk))
7374
.await?;
75+
// Lifetime hack to pull out the var into this scope
76+
let chunk_path;
77+
let script_or_path = match *this.chunking_context.current_chunk_method().await? {
78+
CurrentChunkMethod::StringLiteral => {
79+
let output_root = this.chunking_context.output_root().await?;
80+
let chunk_path_vc = this.chunk.path();
81+
chunk_path = chunk_path_vc.await?;
82+
let chunk_server_path = if let Some(path) = output_root.get_path_to(&chunk_path) {
83+
path
84+
} else {
85+
bail!(
86+
"chunk path {} is not in output root {}",
87+
chunk_path.to_string(),
88+
output_root.to_string()
89+
);
90+
};
91+
Either::Left(StringifyJs(chunk_server_path))
92+
}
93+
CurrentChunkMethod::DocumentCurrentScript => Either::Right("document.currentScript"),
94+
};
7495
let mut code = CodeBuilder::new(source_maps);
7596

7697
// When a chunk is executed, it will either register itself with the current
@@ -83,8 +104,8 @@ impl EcmascriptBrowserChunkContent {
83104
writedoc!(
84105
code,
85106
r#"
86-
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([document.currentScript, {{
87-
"#,
107+
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([{script_or_path}, {{
108+
"#
88109
)?;
89110

90111
let content = this.content.await?;

turbopack/crates/turbopack-browser/src/ecmascript/evaluate/chunk.rs

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

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

29-
use crate::BrowserChunkingContext;
30+
use crate::{chunking_context::CurrentChunkMethod, BrowserChunkingContext};
3031

3132
/// An Ecmascript chunk that:
3233
/// * Contains the Turbopack browser runtime code; and
@@ -79,6 +80,26 @@ impl EcmascriptBrowserEvaluateChunk {
7980
.chunking_context
8081
.reference_chunk_source_maps(Vc::upcast(self))
8182
.await?;
83+
// Lifetime hack to pull out the var into this scope
84+
let chunk_path;
85+
let script_or_path = match *this.chunking_context.current_chunk_method().await? {
86+
CurrentChunkMethod::StringLiteral => {
87+
let output_root = this.chunking_context.output_root().await?;
88+
let chunk_path_vc = self.path();
89+
chunk_path = chunk_path_vc.await?;
90+
let chunk_server_path = if let Some(path) = output_root.get_path_to(&chunk_path) {
91+
path
92+
} else {
93+
bail!(
94+
"chunk path {} is not in output root {}",
95+
chunk_path.to_string(),
96+
output_root.to_string()
97+
);
98+
};
99+
Either::Left(StringifyJs(chunk_server_path))
100+
}
101+
CurrentChunkMethod::DocumentCurrentScript => Either::Right("document.currentScript"),
102+
};
82103

83104
let other_chunks_data = self.chunks_data().await?;
84105
let other_chunks_data = other_chunks_data.iter().try_join().await?;
@@ -127,7 +148,7 @@ impl EcmascriptBrowserEvaluateChunk {
127148
code,
128149
r#"
129150
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([
130-
document.currentScript,
151+
{script_or_path},
131152
{{}},
132153
{}
133154
]);

turbopack/crates/turbopack-browser/src/ecmascript/list/content.rs

+48-14
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
use std::io::Write;
22

3-
use anyhow::Result;
3+
use anyhow::{Context, Result};
4+
use either::Either;
45
use indoc::writedoc;
5-
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+
};
611
use turbo_tasks_fs::File;
712
use turbopack_core::{
813
asset::{Asset, AssetContent},
@@ -20,10 +25,18 @@ use super::{
2025
update::update_chunk_list,
2126
version::EcmascriptDevChunkListVersion,
2227
};
28+
use crate::chunking_context::CurrentChunkMethod;
29+
30+
#[derive(Clone, Debug, Serialize, Deserialize, TraceRawVcs, PartialEq, Eq, NonLocalValue)]
31+
enum CurrentChunkMethodWithData {
32+
StringLiteral(RcStr),
33+
DocumentCurrentScript,
34+
}
2335

2436
/// Contents of an [`EcmascriptDevChunkList`].
2537
#[turbo_tasks::value]
2638
pub(super) struct EcmascriptDevChunkListContent {
39+
current_chunk_method: CurrentChunkMethodWithData,
2740
pub(super) chunks_contents: FxIndexMap<String, ResolvedVc<Box<dyn VersionedContent>>>,
2841
source: EcmascriptDevChunkListSource,
2942
}
@@ -35,21 +48,35 @@ impl EcmascriptDevChunkListContent {
3548
pub async fn new(chunk_list: Vc<EcmascriptDevChunkList>) -> Result<Vc<Self>> {
3649
let chunk_list_ref = chunk_list.await?;
3750
let output_root = chunk_list_ref.chunking_context.output_root().await?;
51+
let current_chunk_method = match *chunk_list_ref
52+
.chunking_context
53+
.current_chunk_method()
54+
.await?
55+
{
56+
CurrentChunkMethod::StringLiteral => {
57+
let path = output_root
58+
.get_path_to(&*chunk_list.path().await?)
59+
.context("chunk list path not in output root")?
60+
.into();
61+
CurrentChunkMethodWithData::StringLiteral(path)
62+
}
63+
CurrentChunkMethod::DocumentCurrentScript => {
64+
CurrentChunkMethodWithData::DocumentCurrentScript
65+
}
66+
};
3867
Ok(EcmascriptDevChunkListContent {
68+
current_chunk_method,
3969
chunks_contents: chunk_list_ref
4070
.chunks
4171
.await?
4272
.iter()
43-
.map(|chunk| {
44-
let output_root = output_root.clone();
45-
async move {
46-
Ok((
47-
output_root
48-
.get_path_to(&*chunk.path().await?)
49-
.map(|path| path.to_string()),
50-
chunk.versioned_content().to_resolved().await?,
51-
))
52-
}
73+
.map(async |chunk| {
74+
Ok((
75+
output_root
76+
.get_path_to(&*chunk.path().await?)
77+
.map(|path| path.to_string()),
78+
chunk.versioned_content().to_resolved().await?,
79+
))
5380
})
5481
.try_join()
5582
.await?
@@ -111,6 +138,13 @@ impl EcmascriptDevChunkListContent {
111138
.map(|s| s.as_str())
112139
.collect::<Vec<_>>();
113140

141+
let script_or_path = match &this.current_chunk_method {
142+
CurrentChunkMethodWithData::StringLiteral(path) => Either::Left(StringifyJs(path)),
143+
CurrentChunkMethodWithData::DocumentCurrentScript => {
144+
Either::Right("document.currentScript")
145+
}
146+
};
147+
114148
let mut code = CodeBuilder::default();
115149

116150
// When loaded, JS chunks must register themselves with the `TURBOPACK` global
@@ -120,11 +154,11 @@ impl EcmascriptDevChunkListContent {
120154
code,
121155
r#"
122156
(globalThis.TURBOPACK = globalThis.TURBOPACK || []).push([
123-
document.currentScript,
157+
{script_or_path},
124158
{{}},
125159
]);
126160
(globalThis.TURBOPACK_CHUNK_LISTS = globalThis.TURBOPACK_CHUNK_LISTS || []).push({{
127-
script: document.currentScript,
161+
script: {script_or_path},
128162
chunks: {:#},
129163
source: {:#}
130164
}});

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();

turbopack/crates/turbopack-ecmascript-runtime/js/src/browser/runtime/base/runtime-base.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -307,9 +307,12 @@ function getChunkRelativeUrl(chunkPath: ChunkPath | ChunkListPath): ChunkUrl {
307307
/**
308308
* Return the ChunkPath from a ChunkScript.
309309
*/
310-
function getPathFromScript(chunkScript: ChunkScript): ChunkPath;
311-
function getPathFromScript(chunkScript: ChunkListScript): ChunkListPath;
312-
function getPathFromScript(chunkScript: ChunkScript | ChunkListScript): ChunkPath | ChunkListPath {
310+
function getPathFromScript(chunkScript: ChunkPath | ChunkScript): ChunkPath;
311+
function getPathFromScript(chunkScript: ChunkListPath | ChunkListScript): ChunkListPath;
312+
function getPathFromScript(chunkScript: ChunkPath | ChunkListPath | ChunkScript | ChunkListScript): ChunkPath | ChunkListPath {
313+
if (typeof chunkScript === "string") {
314+
return chunkScript as ChunkPath | ChunkListPath;
315+
}
313316
const src = decodeURIComponent(chunkScript.getAttribute("src")!);
314317
const path = src.startsWith(CHUNK_BASE_PATH) ? src.slice(CHUNK_BASE_PATH.length) : src;
315318
return path as ChunkPath | ChunkListPath;

0 commit comments

Comments
 (0)