Skip to content

Commit f1eb8a9

Browse files
committed
require(/* turbopackChunkingType: parallel */
1 parent baad064 commit f1eb8a9

File tree

7 files changed

+163
-92
lines changed

7 files changed

+163
-92
lines changed

turbopack/crates/turbopack-ecmascript/src/analyzer/imports.rs

Lines changed: 40 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
55
use smallvec::SmallVec;
66
use swc_core::{
77
atoms::Wtf8Atom,
8-
common::{
9-
BytePos, Span, Spanned, SyntaxContext,
10-
comments::Comments,
11-
errors::{DiagnosticId, HANDLER},
12-
source_map::SmallPos,
13-
},
8+
common::{BytePos, Span, Spanned, SyntaxContext, comments::Comments, source_map::SmallPos},
149
ecma::{
1510
ast::*,
1611
atoms::{Atom, atom},
@@ -20,15 +15,14 @@ use swc_core::{
2015
};
2116
use turbo_rcstr::{RcStr, rcstr};
2217
use turbo_tasks::{FxIndexMap, FxIndexSet, ResolvedVc};
23-
use turbopack_core::{
24-
chunk::ChunkingType, issue::IssueSource, loader::WebpackLoaderItem, source::Source,
25-
};
18+
use turbopack_core::{issue::IssueSource, loader::WebpackLoaderItem, source::Source};
2619

2720
use super::{JsValue, ModuleValue, top_level_await::has_top_level_await};
2821
use crate::{
2922
SpecifiedModuleType,
3023
analyzer::{ConstantValue, ObjectPart},
3124
magic_identifier,
25+
references::util::{SpecifiedChunkingType, parse_chunking_type_annotation},
3226
tree_shake::{PartId, find_turbopack_part_id_in_asserts},
3327
};
3428

@@ -46,16 +40,13 @@ pub struct ImportAnnotations {
4640
turbopack_loader: Option<WebpackLoaderItem>,
4741
turbopack_rename_as: Option<RcStr>,
4842
turbopack_module_type: Option<RcStr>,
43+
chunking_type: Option<SpecifiedChunkingType>,
4944
}
5045

5146
/// Enables a specified transition for the annotated import
5247
static ANNOTATION_TRANSITION: Lazy<Wtf8Atom> =
5348
Lazy::new(|| crate::annotations::ANNOTATION_TRANSITION.into());
5449

55-
/// Changes the chunking type for the annotated import
56-
static ANNOTATION_CHUNKING_TYPE: Lazy<Wtf8Atom> =
57-
Lazy::new(|| crate::annotations::ANNOTATION_CHUNKING_TYPE.into());
58-
5950
/// Changes the type of the resolved module (only "json" is supported currently)
6051
static ATTRIBUTE_MODULE_TYPE: Lazy<Wtf8Atom> = Lazy::new(|| atom!("type").into());
6152

@@ -69,20 +60,21 @@ impl ImportAnnotations {
6960
serde_json::Map::new();
7061
let mut turbopack_rename_as: Option<RcStr> = None;
7162
let mut turbopack_module_type: Option<RcStr> = None;
63+
let mut chunking_type: Option<SpecifiedChunkingType> = None;
7264

7365
for prop in &with.props {
7466
let Some(kv) = prop.as_prop().and_then(|p| p.as_key_value()) else {
7567
continue;
7668
};
7769

7870
let key_str = match &kv.key {
79-
PropName::Ident(ident) => ident.sym.to_string(),
80-
PropName::Str(str) => str.value.to_string_lossy().into_owned(),
71+
PropName::Ident(ident) => Cow::Borrowed(ident.sym.as_str()),
72+
PropName::Str(str) => str.value.to_string_lossy(),
8173
_ => continue,
8274
};
8375

8476
// All turbopack* keys are extracted as string values (per TC39 import attributes spec)
85-
match key_str.as_str() {
77+
match &*key_str {
8678
"turbopackLoader" => {
8779
if let Some(Lit::Str(s)) = kv.value.as_lit() {
8880
turbopack_loader_name =
@@ -110,6 +102,14 @@ impl ImportAnnotations {
110102
Some(RcStr::from(s.value.to_string_lossy().into_owned()));
111103
}
112104
}
105+
"turbopack-chunking-type" => {
106+
if let Some(Lit::Str(s)) = kv.value.as_lit() {
107+
chunking_type = parse_chunking_type_annotation(
108+
kv.value.span(),
109+
&s.value.to_string_lossy(),
110+
);
111+
}
112+
}
113113
_ => {
114114
// For all other keys, only accept string values (per spec)
115115
if let Some(Lit::Str(str)) = kv.value.as_lit() {
@@ -118,23 +118,6 @@ impl ImportAnnotations {
118118
PropName::Str(s) => s.value.clone(),
119119
_ => continue,
120120
};
121-
// Validate known annotation values
122-
if key == *ANNOTATION_CHUNKING_TYPE {
123-
let value = str.value.to_string_lossy();
124-
if value != "parallel" && value != "none" {
125-
HANDLER.with(|handler| {
126-
handler.span_warn_with_code(
127-
kv.value.span(),
128-
&format!(
129-
"unknown turbopack-chunking-type: \"{value}\", \
130-
expected \"parallel\" or \"none\""
131-
),
132-
DiagnosticId::Error("turbopack-chunking-type".into()),
133-
);
134-
});
135-
continue;
136-
}
137-
}
138121
map.insert(key, str.value.clone());
139122
}
140123
}
@@ -150,12 +133,14 @@ impl ImportAnnotations {
150133
|| turbopack_loader.is_some()
151134
|| turbopack_rename_as.is_some()
152135
|| turbopack_module_type.is_some()
136+
|| chunking_type.is_some()
153137
{
154138
Some(ImportAnnotations {
155139
map,
156140
turbopack_loader,
157141
turbopack_rename_as,
158142
turbopack_module_type,
143+
chunking_type,
159144
})
160145
} else {
161146
None
@@ -193,6 +178,7 @@ impl ImportAnnotations {
193178
turbopack_loader: None,
194179
turbopack_rename_as: None,
195180
turbopack_module_type: None,
181+
chunking_type: None,
196182
})
197183
} else {
198184
None
@@ -205,23 +191,9 @@ impl ImportAnnotations {
205191
.map(|v| v.to_string_lossy())
206192
}
207193

208-
/// Returns the chunking type override from the `turbopack-chunking-type` annotation.
209-
///
210-
/// - `None` — no annotation present
211-
/// - `Some(None)` — annotation is `"none"` (opt out of chunking)
212-
/// - `Some(Some(..))` — explicit chunking type (e.g. `"parallel"`)
213-
///
214-
/// Unknown values are rejected during [`ImportAnnotations::parse`] and omitted.
215-
pub fn chunking_type(&self) -> Option<Option<ChunkingType>> {
216-
let chunking_type = self.get(&ANNOTATION_CHUNKING_TYPE)?;
217-
if chunking_type == "none" {
218-
Some(None)
219-
} else {
220-
Some(Some(ChunkingType::Parallel {
221-
inherit_async: true,
222-
hoisted: true,
223-
}))
224-
}
194+
/// Returns the content on the chunking-type annotation
195+
pub fn chunking_type(&self) -> Option<SpecifiedChunkingType> {
196+
self.chunking_type
225197
}
226198

227199
/// Returns the content on the type attribute
@@ -362,6 +334,15 @@ pub struct ImportAttributes {
362334
/// const { b } = await import(/* turbopackExports: "b" */ "module");
363335
/// ```
364336
pub export_names: Option<SmallVec<[RcStr; 1]>>,
337+
/// Whether to use a specific chunking type for this import.
338+
//
339+
/// This is set by using a or `turbopackChunkingType` comment.
340+
///
341+
/// Example:
342+
/// ```js
343+
/// const a = require(/* turbopackChunkingType: parallel */ "a");
344+
/// ```
345+
pub chunking_type: Option<SpecifiedChunkingType>,
365346
}
366347

367348
impl ImportAttributes {
@@ -370,6 +351,7 @@ impl ImportAttributes {
370351
ignore: false,
371352
optional: false,
372353
export_names: None,
354+
chunking_type: None,
373355
}
374356
}
375357

@@ -942,12 +924,13 @@ fn parse_directives(
942924
comments: &dyn Comments,
943925
value: Option<&ExprOrSpread>,
944926
) -> Option<ImportAttributes> {
945-
let comment_pos = value.map(|arg| arg.span_lo())?;
946-
let leading_comments = comments.get_leading(comment_pos)?;
927+
let value = value?;
928+
let leading_comments = comments.get_leading(value.span_lo())?;
947929

948930
let mut ignore = None;
949931
let mut optional = None;
950932
let mut export_names = None;
933+
let mut chunking_type = None;
951934

952935
// Process all comments, last one wins for each directive type
953936
for comment in leading_comments.iter() {
@@ -967,17 +950,21 @@ fn parse_directives(
967950
"webpackExports" | "turbopackExports" => {
968951
export_names = Some(parse_export_names(val));
969952
}
953+
"turbopackChunkingType" => {
954+
chunking_type = parse_chunking_type_annotation(value.span(), val);
955+
}
970956
_ => {} // ignore anything else
971957
}
972958
}
973959
}
974960

975961
// Return Some only if at least one directive was found
976-
if ignore.is_some() || optional.is_some() || export_names.is_some() {
962+
if ignore.is_some() || optional.is_some() || export_names.is_some() || chunking_type.is_some() {
977963
Some(ImportAttributes {
978964
ignore: ignore.unwrap_or(false),
979965
optional: optional.unwrap_or(false),
980966
export_names,
967+
chunking_type,
981968
})
982969
} else {
983970
None

turbopack/crates/turbopack-ecmascript/src/annotations.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,6 @@ pub const ANNOTATION_CHUNKING_TYPE: &str = "turbopack-chunking-type";
99
/// Enables a specified transition for the annotated import
1010
pub const ANNOTATION_TRANSITION: &str = "turbopack-transition";
1111

12-
pub fn with_chunking_type(chunking_type: &str) -> Box<ObjectLit> {
13-
with_clause(&[(ANNOTATION_CHUNKING_TYPE, chunking_type)])
14-
}
15-
16-
pub fn with_transition(transition_name: &str) -> Box<ObjectLit> {
17-
with_clause(&[(ANNOTATION_TRANSITION, transition_name)])
18-
}
19-
2012
pub fn with_clause<'a>(
2113
entries: impl IntoIterator<Item = &'a (&'a str, &'a str)>,
2214
) -> Box<ObjectLit> {

turbopack/crates/turbopack-ecmascript/src/errors.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,6 @@ pub mod failed_to_analyze {
1919
pub const NEW_WORKER: &str = "TP1203";
2020
pub const MODULE_HOT_ACCEPT: &str = "TP1204";
2121
pub const MODULE_HOT_DECLINE: &str = "TP1205";
22+
pub const CHUNKING_TYPE: &str = "TP1206";
2223
}
2324
}

turbopack/crates/turbopack-ecmascript/src/references/cjs.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use crate::{
2323
references::{
2424
AstPath,
2525
pattern_mapping::{PatternMapping, ResolveType},
26+
util::SpecifiedChunkingType,
2627
},
2728
runtime_functions::TURBOPACK_CACHE,
2829
};
@@ -80,10 +81,11 @@ impl ModuleReference for CjsAssetReference {
8081
#[derive(Hash, Debug, ValueToString)]
8182
#[value_to_string("require {request}")]
8283
pub struct CjsRequireAssetReference {
83-
pub origin: ResolvedVc<Box<dyn ResolveOrigin>>,
84-
pub request: ResolvedVc<Request>,
85-
pub issue_source: IssueSource,
86-
pub error_mode: ResolveErrorMode,
84+
origin: ResolvedVc<Box<dyn ResolveOrigin>>,
85+
request: ResolvedVc<Request>,
86+
issue_source: IssueSource,
87+
error_mode: ResolveErrorMode,
88+
chunking_type_attribute: Option<SpecifiedChunkingType>,
8789
}
8890

8991
impl CjsRequireAssetReference {
@@ -92,12 +94,14 @@ impl CjsRequireAssetReference {
9294
request: ResolvedVc<Request>,
9395
issue_source: IssueSource,
9496
error_mode: ResolveErrorMode,
97+
chunking_type_attribute: Option<SpecifiedChunkingType>,
9598
) -> Self {
9699
CjsRequireAssetReference {
97100
origin,
98101
request,
99102
issue_source,
100103
error_mode,
104+
chunking_type_attribute,
101105
}
102106
}
103107
}
@@ -116,10 +120,15 @@ impl ModuleReference for CjsRequireAssetReference {
116120
}
117121

118122
fn chunking_type(&self) -> Option<ChunkingType> {
119-
Some(ChunkingType::Parallel {
120-
inherit_async: false,
121-
hoisted: false,
122-
})
123+
self.chunking_type_attribute.map_or_else(
124+
|| {
125+
Some(ChunkingType::Parallel {
126+
inherit_async: false,
127+
hoisted: false,
128+
})
129+
},
130+
|c| c.as_chunking_type(false, false),
131+
)
123132
}
124133
}
125134

@@ -202,10 +211,11 @@ impl CjsRequireAssetReferenceCodeGen {
202211
#[derive(Hash, Debug, ValueToString)]
203212
#[value_to_string("require.resolve {request}")]
204213
pub struct CjsRequireResolveAssetReference {
205-
pub origin: ResolvedVc<Box<dyn ResolveOrigin>>,
206-
pub request: ResolvedVc<Request>,
207-
pub issue_source: IssueSource,
208-
pub error_mode: ResolveErrorMode,
214+
origin: ResolvedVc<Box<dyn ResolveOrigin>>,
215+
request: ResolvedVc<Request>,
216+
issue_source: IssueSource,
217+
error_mode: ResolveErrorMode,
218+
chunking_type_attribute: Option<SpecifiedChunkingType>,
209219
}
210220

211221
impl CjsRequireResolveAssetReference {
@@ -214,12 +224,14 @@ impl CjsRequireResolveAssetReference {
214224
request: ResolvedVc<Request>,
215225
issue_source: IssueSource,
216226
error_mode: ResolveErrorMode,
227+
chunking_type_attribute: Option<SpecifiedChunkingType>,
217228
) -> Self {
218229
CjsRequireResolveAssetReference {
219230
origin,
220231
request,
221232
issue_source,
222233
error_mode,
234+
chunking_type_attribute,
223235
}
224236
}
225237
}
@@ -238,10 +250,15 @@ impl ModuleReference for CjsRequireResolveAssetReference {
238250
}
239251

240252
fn chunking_type(&self) -> Option<ChunkingType> {
241-
Some(ChunkingType::Parallel {
242-
inherit_async: false,
243-
hoisted: false,
244-
})
253+
self.chunking_type_attribute.map_or_else(
254+
|| {
255+
Some(ChunkingType::Parallel {
256+
inherit_async: false,
257+
hoisted: false,
258+
})
259+
},
260+
|c| c.as_chunking_type(false, false),
261+
)
245262
}
246263
}
247264

0 commit comments

Comments
 (0)