@@ -5,12 +5,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
55use smallvec:: SmallVec ;
66use 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} ;
2116use turbo_rcstr:: { RcStr , rcstr} ;
2217use 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
2720use super :: { JsValue , ModuleValue , top_level_await:: has_top_level_await} ;
2821use 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
5247static 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)
6051static 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
367348impl 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
0 commit comments