Skip to content

Commit 8a51ebc

Browse files
authoredOct 16, 2023
Revert "feat(turbopack): support basic next/dynamic" (#56885)
1 parent c1c419f commit 8a51ebc

File tree

17 files changed

+443
-730
lines changed

17 files changed

+443
-730
lines changed
 

‎Cargo.lock

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

‎packages/next-swc/crates/core/Cargo.toml

+1-3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ either = "1"
1515
fxhash = "0.2.1"
1616
hex = "0.4.3"
1717
once_cell = { workspace = true }
18+
next-transform-font = {workspace = true}
1819
pathdiff = "0.2.0"
1920
regex = "1.5"
2021
rustc-hash = "1"
@@ -23,9 +24,6 @@ serde_json = "1"
2324
sha1 = "0.10.1"
2425
tracing = { version = "0.1.37" }
2526

26-
next-transform-dynamic = { workspace = true }
27-
next-transform-font = { workspace = true }
28-
2927
turbopack-binding = { workspace = true, features = [
3028
"__swc_core",
3129
"__swc_core_next_core",

‎packages/next-swc/crates/core/src/lib.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc, sync::Arc};
3737
use auto_cjs::contains_cjs;
3838
use either::Either;
3939
use fxhash::FxHashSet;
40-
use next_transform_dynamic::{next_dynamic, NextDynamicMode};
4140
use next_transform_font::next_font_loaders;
4241
use serde::Deserialize;
4342
use turbopack_binding::swc::{
@@ -59,6 +58,7 @@ mod auto_cjs;
5958
pub mod cjs_optimizer;
6059
pub mod disallow_re_export_all_in_page;
6160
pub mod named_import_transform;
61+
pub mod next_dynamic;
6262
pub mod next_ssg;
6363
pub mod optimize_barrel;
6464
pub mod optimize_server_react;
@@ -226,7 +226,7 @@ where
226226
!opts.disable_next_ssg
227227
),
228228
amp_attributes::amp_attributes(),
229-
next_dynamic(
229+
next_dynamic::next_dynamic(
230230
opts.is_development,
231231
opts.is_server,
232232
match &opts.server_components {
@@ -238,7 +238,6 @@ where
238238
},
239239
_ => false,
240240
},
241-
NextDynamicMode::Webpack,
242241
file.name.clone(),
243242
opts.pages_dir.clone()
244243
),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
use std::path::{Path, PathBuf};
2+
3+
use pathdiff::diff_paths;
4+
use turbopack_binding::swc::core::{
5+
common::{errors::HANDLER, FileName, DUMMY_SP},
6+
ecma::{
7+
ast::{
8+
ArrayLit, ArrowExpr, BinExpr, BinaryOp, BlockStmtOrExpr, Bool, CallExpr, Callee, Expr,
9+
ExprOrSpread, Id, Ident, ImportDecl, ImportSpecifier, KeyValueProp, Lit, MemberExpr,
10+
MemberProp, Null, ObjectLit, Prop, PropName, PropOrSpread, Str, Tpl,
11+
},
12+
atoms::js_word,
13+
utils::ExprFactory,
14+
visit::{Fold, FoldWith},
15+
},
16+
};
17+
18+
pub fn next_dynamic(
19+
is_development: bool,
20+
is_server: bool,
21+
is_server_components: bool,
22+
filename: FileName,
23+
pages_dir: Option<PathBuf>,
24+
) -> impl Fold {
25+
NextDynamicPatcher {
26+
is_development,
27+
is_server,
28+
is_server_components,
29+
pages_dir,
30+
filename,
31+
dynamic_bindings: vec![],
32+
is_next_dynamic_first_arg: false,
33+
dynamically_imported_specifier: None,
34+
}
35+
}
36+
37+
#[derive(Debug)]
38+
struct NextDynamicPatcher {
39+
is_development: bool,
40+
is_server: bool,
41+
is_server_components: bool,
42+
pages_dir: Option<PathBuf>,
43+
filename: FileName,
44+
dynamic_bindings: Vec<Id>,
45+
is_next_dynamic_first_arg: bool,
46+
dynamically_imported_specifier: Option<String>,
47+
}
48+
49+
impl Fold for NextDynamicPatcher {
50+
fn fold_import_decl(&mut self, decl: ImportDecl) -> ImportDecl {
51+
let ImportDecl {
52+
ref src,
53+
ref specifiers,
54+
..
55+
} = decl;
56+
if &src.value == "next/dynamic" {
57+
for specifier in specifiers {
58+
if let ImportSpecifier::Default(default_specifier) = specifier {
59+
self.dynamic_bindings.push(default_specifier.local.to_id());
60+
}
61+
}
62+
}
63+
64+
decl
65+
}
66+
67+
fn fold_call_expr(&mut self, expr: CallExpr) -> CallExpr {
68+
if self.is_next_dynamic_first_arg {
69+
if let Callee::Import(..) = &expr.callee {
70+
match &*expr.args[0].expr {
71+
Expr::Lit(Lit::Str(Str { value, .. })) => {
72+
self.dynamically_imported_specifier = Some(value.to_string());
73+
}
74+
Expr::Tpl(Tpl { exprs, quasis, .. }) if exprs.is_empty() => {
75+
self.dynamically_imported_specifier = Some(quasis[0].raw.to_string());
76+
}
77+
_ => {}
78+
}
79+
}
80+
return expr.fold_children_with(self);
81+
}
82+
let mut expr = expr.fold_children_with(self);
83+
if let Callee::Expr(i) = &expr.callee {
84+
if let Expr::Ident(identifier) = &**i {
85+
if self.dynamic_bindings.contains(&identifier.to_id()) {
86+
if expr.args.is_empty() {
87+
HANDLER.with(|handler| {
88+
handler
89+
.struct_span_err(
90+
identifier.span,
91+
"next/dynamic requires at least one argument",
92+
)
93+
.emit()
94+
});
95+
return expr;
96+
} else if expr.args.len() > 2 {
97+
HANDLER.with(|handler| {
98+
handler
99+
.struct_span_err(
100+
identifier.span,
101+
"next/dynamic only accepts 2 arguments",
102+
)
103+
.emit()
104+
});
105+
return expr;
106+
}
107+
if expr.args.len() == 2 {
108+
match &*expr.args[1].expr {
109+
Expr::Object(_) => {}
110+
_ => {
111+
HANDLER.with(|handler| {
112+
handler
113+
.struct_span_err(
114+
identifier.span,
115+
"next/dynamic options must be an object literal.\nRead more: https://nextjs.org/docs/messages/invalid-dynamic-options-type",
116+
)
117+
.emit();
118+
});
119+
return expr;
120+
}
121+
}
122+
}
123+
124+
self.is_next_dynamic_first_arg = true;
125+
expr.args[0].expr = expr.args[0].expr.clone().fold_with(self);
126+
self.is_next_dynamic_first_arg = false;
127+
128+
if self.dynamically_imported_specifier.is_none() {
129+
return expr;
130+
}
131+
132+
// dev client or server:
133+
// loadableGenerated: {
134+
// modules:
135+
// ["/project/src/file-being-transformed.js -> " + '../components/hello'] }
136+
137+
// prod client
138+
// loadableGenerated: {
139+
// webpack: () => [require.resolveWeak('../components/hello')],
140+
let generated = Box::new(Expr::Object(ObjectLit {
141+
span: DUMMY_SP,
142+
props: if self.is_development || self.is_server {
143+
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
144+
key: PropName::Ident(Ident::new("modules".into(), DUMMY_SP)),
145+
value: Box::new(Expr::Array(ArrayLit {
146+
elems: vec![Some(ExprOrSpread {
147+
expr: Box::new(Expr::Bin(BinExpr {
148+
span: DUMMY_SP,
149+
op: BinaryOp::Add,
150+
left: Box::new(Expr::Lit(Lit::Str(Str {
151+
value: format!(
152+
"{} -> ",
153+
rel_filename(
154+
self.pages_dir.as_deref(),
155+
&self.filename
156+
)
157+
)
158+
.into(),
159+
span: DUMMY_SP,
160+
raw: None,
161+
}))),
162+
right: Box::new(Expr::Lit(Lit::Str(Str {
163+
value: self
164+
.dynamically_imported_specifier
165+
.as_ref()
166+
.unwrap()
167+
.clone()
168+
.into(),
169+
span: DUMMY_SP,
170+
raw: None,
171+
}))),
172+
})),
173+
spread: None,
174+
})],
175+
span: DUMMY_SP,
176+
})),
177+
})))]
178+
} else {
179+
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
180+
key: PropName::Ident(Ident::new("webpack".into(), DUMMY_SP)),
181+
value: Box::new(Expr::Arrow(ArrowExpr {
182+
params: vec![],
183+
body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Array(
184+
ArrayLit {
185+
elems: vec![Some(ExprOrSpread {
186+
expr: Box::new(Expr::Call(CallExpr {
187+
callee: Callee::Expr(Box::new(Expr::Member(
188+
MemberExpr {
189+
obj: Box::new(Expr::Ident(Ident {
190+
sym: js_word!("require"),
191+
span: DUMMY_SP,
192+
optional: false,
193+
})),
194+
prop: MemberProp::Ident(Ident {
195+
sym: "resolveWeak".into(),
196+
span: DUMMY_SP,
197+
optional: false,
198+
}),
199+
span: DUMMY_SP,
200+
},
201+
))),
202+
args: vec![ExprOrSpread {
203+
expr: Box::new(Expr::Lit(Lit::Str(Str {
204+
value: self
205+
.dynamically_imported_specifier
206+
.as_ref()
207+
.unwrap()
208+
.clone()
209+
.into(),
210+
span: DUMMY_SP,
211+
raw: None,
212+
}))),
213+
spread: None,
214+
}],
215+
span: DUMMY_SP,
216+
type_args: None,
217+
})),
218+
spread: None,
219+
})],
220+
span: DUMMY_SP,
221+
},
222+
)))),
223+
is_async: false,
224+
is_generator: false,
225+
span: DUMMY_SP,
226+
return_type: None,
227+
type_params: None,
228+
})),
229+
})))]
230+
},
231+
}));
232+
233+
let mut props =
234+
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
235+
key: PropName::Ident(Ident::new("loadableGenerated".into(), DUMMY_SP)),
236+
value: generated,
237+
})))];
238+
239+
let mut has_ssr_false = false;
240+
241+
if expr.args.len() == 2 {
242+
if let Expr::Object(ObjectLit {
243+
props: options_props,
244+
..
245+
}) = &*expr.args[1].expr
246+
{
247+
for prop in options_props.iter() {
248+
if let Some(KeyValueProp { key, value }) = match prop {
249+
PropOrSpread::Prop(prop) => match &**prop {
250+
Prop::KeyValue(key_value_prop) => Some(key_value_prop),
251+
_ => None,
252+
},
253+
_ => None,
254+
} {
255+
if let Some(Ident {
256+
sym,
257+
span: _,
258+
optional: _,
259+
}) = match key {
260+
PropName::Ident(ident) => Some(ident),
261+
_ => None,
262+
} {
263+
if sym == "ssr" {
264+
if let Some(Lit::Bool(Bool {
265+
value: false,
266+
span: _,
267+
})) = value.as_lit()
268+
{
269+
has_ssr_false = true
270+
}
271+
}
272+
}
273+
}
274+
}
275+
props.extend(options_props.iter().cloned());
276+
}
277+
}
278+
279+
if has_ssr_false && self.is_server && !self.is_server_components {
280+
expr.args[0] = Lit::Null(Null { span: DUMMY_SP }).as_arg();
281+
}
282+
283+
let second_arg = ExprOrSpread {
284+
spread: None,
285+
expr: Box::new(Expr::Object(ObjectLit {
286+
span: DUMMY_SP,
287+
props,
288+
})),
289+
};
290+
291+
if expr.args.len() == 2 {
292+
expr.args[1] = second_arg;
293+
} else {
294+
expr.args.push(second_arg)
295+
}
296+
self.dynamically_imported_specifier = None;
297+
}
298+
}
299+
}
300+
expr
301+
}
302+
}
303+
304+
fn rel_filename(base: Option<&Path>, file: &FileName) -> String {
305+
let base = match base {
306+
Some(v) => v,
307+
None => return file.to_string(),
308+
};
309+
310+
let file = match file {
311+
FileName::Real(v) => v,
312+
_ => {
313+
return file.to_string();
314+
}
315+
};
316+
317+
let rel_path = diff_paths(file, base);
318+
319+
let rel_path = match rel_path {
320+
Some(v) => v,
321+
None => return file.display().to_string(),
322+
};
323+
324+
rel_path.display().to_string()
325+
}

‎packages/next-swc/crates/core/tests/errors.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@ use std::path::PathBuf;
22

33
use next_swc::{
44
disallow_re_export_all_in_page::disallow_re_export_all_in_page,
5+
next_dynamic::next_dynamic,
56
next_ssg::next_ssg,
67
react_server_components::server_components,
78
server_actions::{
89
server_actions, {self},
910
},
1011
};
11-
use next_transform_dynamic::{next_dynamic, NextDynamicMode};
1212
use next_transform_font::{next_font_loaders, Config as FontLoaderConfig};
1313
use turbopack_binding::swc::{
1414
core::{
@@ -56,7 +56,6 @@ fn next_dynamic_errors(input: PathBuf) {
5656
true,
5757
false,
5858
false,
59-
NextDynamicMode::Webpack,
6059
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
6160
Some("/some-project/src".into()),
6261
)

‎packages/next-swc/crates/core/tests/fixture.rs

+1-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use next_swc::{
44
amp_attributes::amp_attributes,
55
cjs_optimizer::cjs_optimizer,
66
named_import_transform::named_import_transform,
7+
next_dynamic::next_dynamic,
78
next_ssg::next_ssg,
89
optimize_barrel::optimize_barrel,
910
optimize_server_react::optimize_server_react,
@@ -14,7 +15,6 @@ use next_swc::{
1415
},
1516
shake_exports::{shake_exports, Config as ShakeExportsConfig},
1617
};
17-
use next_transform_dynamic::{next_dynamic, NextDynamicMode};
1818
use next_transform_font::{next_font_loaders, Config as FontLoaderConfig};
1919
use serde::de::DeserializeOwned;
2020
use turbopack_binding::swc::{
@@ -64,7 +64,6 @@ fn next_dynamic_fixture(input: PathBuf) {
6464
true,
6565
false,
6666
false,
67-
NextDynamicMode::Webpack,
6867
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
6968
Some("/some-project/src".into()),
7069
)
@@ -80,7 +79,6 @@ fn next_dynamic_fixture(input: PathBuf) {
8079
false,
8180
false,
8281
false,
83-
NextDynamicMode::Webpack,
8482
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
8583
Some("/some-project/src".into()),
8684
)
@@ -96,7 +94,6 @@ fn next_dynamic_fixture(input: PathBuf) {
9694
false,
9795
true,
9896
false,
99-
NextDynamicMode::Webpack,
10097
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
10198
Some("/some-project/src".into()),
10299
)
@@ -119,7 +116,6 @@ fn app_dir_next_dynamic_fixture(input: PathBuf) {
119116
true,
120117
false,
121118
true,
122-
NextDynamicMode::Webpack,
123119
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
124120
Some("/some-project/src".into()),
125121
)
@@ -135,7 +131,6 @@ fn app_dir_next_dynamic_fixture(input: PathBuf) {
135131
false,
136132
false,
137133
true,
138-
NextDynamicMode::Webpack,
139134
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
140135
Some("/some-project/src".into()),
141136
)
@@ -151,7 +146,6 @@ fn app_dir_next_dynamic_fixture(input: PathBuf) {
151146
false,
152147
true,
153148
true,
154-
NextDynamicMode::Webpack,
155149
FileName::Real(PathBuf::from("/some-project/src/some-file.js")),
156150
Some("/some-project/src".into()),
157151
)

‎packages/next-swc/crates/next-api/src/app.rs

+3-108
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::collections::HashMap;
2-
31
use anyhow::{bail, Context, Result};
42
use next_core::{
53
app_structure::{
@@ -23,8 +21,7 @@ use next_core::{
2321
next_edge::route_regex::get_named_middleware_regex,
2422
next_manifests::{
2523
AppBuildManifest, AppPathsManifest, BuildManifest, ClientReferenceManifest,
26-
EdgeFunctionDefinition, LoadableManifest, MiddlewareMatcher, MiddlewaresManifestV2,
27-
PagesManifest, Regions,
24+
EdgeFunctionDefinition, MiddlewareMatcher, MiddlewaresManifestV2, PagesManifest, Regions,
2825
},
2926
next_server::{
3027
get_server_module_options_context, get_server_resolve_options_context,
@@ -42,7 +39,7 @@ use turbopack_binding::{
4239
turbopack::{
4340
core::{
4441
asset::{Asset, AssetContent},
45-
chunk::{availability_info::AvailabilityInfo, ChunkingContext, EvaluatableAssets},
42+
chunk::{ChunkingContext, EvaluatableAssets},
4643
file_source::FileSource,
4744
module::Module,
4845
output::{OutputAsset, OutputAssets},
@@ -56,10 +53,6 @@ use turbopack_binding::{
5653
};
5754

5855
use crate::{
59-
dynamic_imports::{
60-
collect_chunk_group, collect_evaluated_chunk_group, collect_next_dynamic_imports,
61-
DynamicImportedChunks,
62-
},
6356
project::Project,
6457
route::{Endpoint, Route, Routes, WrittenEndpoint},
6558
server_actions::create_server_actions_manifest,
@@ -686,67 +679,6 @@ impl AppEndpoint {
686679
)))
687680
}
688681

689-
async fn create_react_loadable_manifest(
690-
dynamic_import_entries: Vc<DynamicImportedChunks>,
691-
ty: &'static str,
692-
node_root: Vc<FileSystemPath>,
693-
pathname: &str,
694-
) -> Result<Vc<OutputAssets>> {
695-
let dynamic_import_entries = &*dynamic_import_entries.await?;
696-
697-
let mut output = vec![];
698-
let mut loadable_manifest: HashMap<String, LoadableManifest> = Default::default();
699-
700-
for (origin, dynamic_imports) in dynamic_import_entries.into_iter() {
701-
let origin_path = &*origin.ident().path().await?;
702-
703-
for (import, chunk_output) in dynamic_imports {
704-
let chunk_output = chunk_output.await?;
705-
output.extend(chunk_output.iter().copied());
706-
707-
let id = format!("{} -> {}", origin_path, import);
708-
709-
let server_path = node_root.join("server".to_string());
710-
let server_path_value = server_path.await?;
711-
let files = chunk_output
712-
.iter()
713-
.map(move |&file| {
714-
let server_path_value = server_path_value.clone();
715-
async move {
716-
Ok(server_path_value
717-
.get_path_to(&*file.ident().path().await?)
718-
.map(|path| path.to_string()))
719-
}
720-
})
721-
.try_flat_join()
722-
.await?;
723-
724-
let manifest_item = LoadableManifest {
725-
id: id.clone(),
726-
files,
727-
};
728-
729-
loadable_manifest.insert(id, manifest_item);
730-
}
731-
}
732-
733-
let loadable_path_prefix = get_asset_prefix_from_pathname(pathname);
734-
let loadable_manifest = Vc::upcast(VirtualOutputAsset::new(
735-
node_root.join(format!(
736-
"server/app{loadable_path_prefix}/{ty}/react-loadable-manifest.json",
737-
)),
738-
AssetContent::file(
739-
FileContent::Content(File::from(serde_json::to_string_pretty(
740-
&loadable_manifest,
741-
)?))
742-
.cell(),
743-
),
744-
));
745-
746-
output.push(loadable_manifest);
747-
Ok(Vc::cell(output))
748-
}
749-
750682
let endpoint_output = match app_entry.config.await?.runtime.unwrap_or_default() {
751683
NextRuntime::Edge => {
752684
// create edge chunks
@@ -782,7 +714,7 @@ impl AppEndpoint {
782714

783715
let files = chunking_context.evaluated_chunk_group(
784716
app_entry.rsc_entry.ident(),
785-
Vc::cell(evaluatable_assets.clone()),
717+
Vc::cell(evaluatable_assets),
786718
);
787719
server_assets.extend(files.await?.iter().copied());
788720

@@ -869,24 +801,6 @@ impl AppEndpoint {
869801
)?;
870802
server_assets.push(app_paths_manifest_output);
871803

872-
// create react-loadable-manifest for next/dynamic
873-
let dynamic_import_modules =
874-
collect_next_dynamic_imports(app_entry.rsc_entry).await?;
875-
let dynamic_import_entries = collect_evaluated_chunk_group(
876-
chunking_context,
877-
dynamic_import_modules,
878-
Vc::cell(evaluatable_assets),
879-
)
880-
.await?;
881-
let loadable_manifest_output = create_react_loadable_manifest(
882-
dynamic_import_entries,
883-
ty,
884-
node_root,
885-
&app_entry.pathname,
886-
)
887-
.await?;
888-
server_assets.extend(loadable_manifest_output.await?.iter().copied());
889-
890804
AppEndpointOutput::Edge {
891805
files,
892806
server_assets: Vc::cell(server_assets),
@@ -943,25 +857,6 @@ impl AppEndpoint {
943857
)?;
944858
server_assets.push(app_paths_manifest_output);
945859

946-
// create react-loadable-manifest for next/dynamic
947-
let availability_info = Value::new(AvailabilityInfo::Root);
948-
let dynamic_import_modules =
949-
collect_next_dynamic_imports(app_entry.rsc_entry).await?;
950-
let dynamic_import_entries = collect_chunk_group(
951-
this.app_project.project().rsc_chunking_context(),
952-
dynamic_import_modules,
953-
availability_info,
954-
)
955-
.await?;
956-
let loadable_manifest_output = create_react_loadable_manifest(
957-
dynamic_import_entries,
958-
ty,
959-
node_root,
960-
&app_entry.pathname,
961-
)
962-
.await?;
963-
server_assets.extend(loadable_manifest_output.await?.iter().copied());
964-
965860
AppEndpointOutput::NodeJs {
966861
rsc_chunk,
967862
server_assets: Vc::cell(server_assets),

‎packages/next-swc/crates/next-api/src/dynamic_imports.rs

-319
This file was deleted.

‎packages/next-swc/crates/next-api/src/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
#![feature(async_fn_in_trait)]
44

55
mod app;
6-
mod dynamic_imports;
76
mod entrypoints;
87
mod middleware;
98
mod pages;

‎packages/next-swc/crates/next-api/src/pages.rs

+9-124
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use std::collections::HashMap;
2-
31
use anyhow::{bail, Context, Result};
42
use indexmap::IndexMap;
53
use next_core::{
@@ -13,8 +11,8 @@ use next_core::{
1311
next_dynamic::NextDynamicTransition,
1412
next_edge::route_regex::get_named_middleware_regex,
1513
next_manifests::{
16-
BuildManifest, EdgeFunctionDefinition, LoadableManifest, MiddlewareMatcher,
17-
MiddlewaresManifestV2, PagesManifest,
14+
BuildManifest, EdgeFunctionDefinition, MiddlewareMatcher, MiddlewaresManifestV2,
15+
PagesManifest,
1816
},
1917
next_pages::create_page_ssr_entry_module,
2018
next_server::{
@@ -39,7 +37,7 @@ use turbopack_binding::{
3937
build::BuildChunkingContext,
4038
core::{
4139
asset::AssetContent,
42-
chunk::{availability_info::AvailabilityInfo, ChunkingContext, EvaluatableAssets},
40+
chunk::{ChunkingContext, EvaluatableAssets},
4341
context::AssetContext,
4442
file_source::FileSource,
4543
issue::{IssueSeverity, OptionIssueSource},
@@ -65,10 +63,6 @@ use turbopack_binding::{
6563
};
6664

6765
use crate::{
68-
dynamic_imports::{
69-
collect_chunk_group, collect_evaluated_chunk_group, collect_next_dynamic_imports,
70-
DynamicImportedChunks,
71-
},
7266
project::Project,
7367
route::{Endpoint, Route, Routes, WrittenEndpoint},
7468
server_paths::all_server_paths,
@@ -615,21 +609,9 @@ impl PageEndpoint {
615609
evaluatable_assets.push(evaluatable);
616610

617611
let edge_files = edge_chunking_context
618-
.evaluated_chunk_group(ssr_module.ident(), Vc::cell(evaluatable_assets.clone()));
619-
620-
let dynamic_import_modules = collect_next_dynamic_imports(ssr_module).await?;
621-
let dynamic_import_entries = collect_evaluated_chunk_group(
622-
edge_chunking_context,
623-
dynamic_import_modules,
624-
Vc::cell(evaluatable_assets.clone()),
625-
)
626-
.await?;
612+
.evaluated_chunk_group(ssr_module.ident(), Vc::cell(evaluatable_assets));
627613

628-
Ok(SsrChunk::Edge {
629-
files: edge_files,
630-
dynamic_import_entries,
631-
}
632-
.cell())
614+
Ok(SsrChunk::Edge { files: edge_files }.cell())
633615
} else {
634616
let ssr_module = create_page_ssr_entry_module(
635617
this.pathname,
@@ -651,15 +633,8 @@ impl PageEndpoint {
651633
runtime_entries,
652634
);
653635

654-
let availability_info = Value::new(AvailabilityInfo::Root);
655-
let dynamic_import_modules = collect_next_dynamic_imports(ssr_module).await?;
656-
let dynamic_import_entries =
657-
collect_chunk_group(chunking_context, dynamic_import_modules, availability_info)
658-
.await?;
659-
660636
Ok(SsrChunk::NodeJs {
661637
entry: ssr_entry_chunk,
662-
dynamic_import_entries,
663638
}
664639
.cell())
665640
}
@@ -753,78 +728,6 @@ impl PageEndpoint {
753728
)))
754729
}
755730

756-
#[turbo_tasks::function]
757-
async fn react_loadable_manifest(
758-
self: Vc<Self>,
759-
dynamic_import_entries: Vc<DynamicImportedChunks>,
760-
) -> Result<Vc<OutputAssets>> {
761-
let this = self.await?;
762-
let node_root = this.pages_project.project().node_root();
763-
let pages_dir = this.pages_project.pages_dir().await?;
764-
765-
let dynamic_import_entries = &*dynamic_import_entries.await?;
766-
767-
let mut output = vec![];
768-
let mut loadable_manifest: HashMap<String, LoadableManifest> = Default::default();
769-
for (origin, dynamic_imports) in dynamic_import_entries.into_iter() {
770-
let origin_path = &*origin.ident().path().await?;
771-
772-
for (import, chunk_output) in dynamic_imports {
773-
let chunk_output = chunk_output.await?;
774-
output.extend(chunk_output.iter().copied());
775-
776-
// https://github.com/vercel/next.js/blob/b7c85b87787283d8fb86f705f67bdfabb6b654bb/packages/next-swc/crates/next-transform-dynamic/src/lib.rs#L230
777-
// For the pages dir, next_dynamic transform puts relative paths to the pages
778-
// dir for the origin import.
779-
let id = format!(
780-
"{} -> {}",
781-
pages_dir
782-
.get_path_to(origin_path)
783-
.map_or_else(|| origin_path.to_string(), |path| path.to_string()),
784-
import
785-
);
786-
787-
let server_path = node_root.join("server".to_string());
788-
let server_path_value = server_path.await?;
789-
let files = chunk_output
790-
.iter()
791-
.map(move |file| {
792-
let server_path_value = server_path_value.clone();
793-
async move {
794-
Ok(server_path_value
795-
.get_path_to(&*file.ident().path().await?)
796-
.map(|path| path.to_string()))
797-
}
798-
})
799-
.try_flat_join()
800-
.await?;
801-
802-
let manifest_item = LoadableManifest {
803-
id: id.clone(),
804-
files,
805-
};
806-
807-
loadable_manifest.insert(id, manifest_item);
808-
}
809-
}
810-
811-
let loadable_path_prefix = get_asset_prefix_from_pathname(&this.pathname.await?);
812-
let loadable_manifest = Vc::upcast(VirtualOutputAsset::new(
813-
node_root.join(format!(
814-
"server/pages{loadable_path_prefix}/react-loadable-manifest.json"
815-
)),
816-
AssetContent::file(
817-
FileContent::Content(File::from(serde_json::to_string_pretty(
818-
&loadable_manifest,
819-
)?))
820-
.cell(),
821-
),
822-
));
823-
824-
output.push(loadable_manifest);
825-
Ok(Vc::cell(output))
826-
}
827-
828731
#[turbo_tasks::function]
829732
async fn build_manifest(
830733
self: Vc<Self>,
@@ -893,27 +796,18 @@ impl PageEndpoint {
893796
};
894797

895798
let page_output = match *ssr_chunk.await? {
896-
SsrChunk::NodeJs {
897-
entry,
898-
dynamic_import_entries,
899-
} => {
799+
SsrChunk::NodeJs { entry } => {
900800
let pages_manifest = self.pages_manifest(entry);
901801
server_assets.push(pages_manifest);
902802
server_assets.push(entry);
903803

904-
let loadable_manifest_output = self.react_loadable_manifest(dynamic_import_entries);
905-
server_assets.extend(loadable_manifest_output.await?.iter().copied());
906-
907804
PageEndpointOutput::NodeJs {
908805
entry_chunk: entry,
909806
server_assets: Vc::cell(server_assets),
910807
client_assets: Vc::cell(client_assets),
911808
}
912809
}
913-
SsrChunk::Edge {
914-
files,
915-
dynamic_import_entries,
916-
} => {
810+
SsrChunk::Edge { files } => {
917811
let node_root = this.pages_project.project().node_root();
918812
let files_value = files.await?;
919813
if let Some(&file) = files_value.first() {
@@ -973,9 +867,6 @@ impl PageEndpoint {
973867
));
974868
server_assets.push(middleware_manifest_v2);
975869

976-
let loadable_manifest_output = self.react_loadable_manifest(dynamic_import_entries);
977-
server_assets.extend(loadable_manifest_output.await?.iter().copied());
978-
979870
PageEndpointOutput::Edge {
980871
files,
981872
server_assets: Vc::cell(server_assets),
@@ -1110,12 +1001,6 @@ impl PageEndpointOutput {
11101001

11111002
#[turbo_tasks::value]
11121003
pub enum SsrChunk {
1113-
NodeJs {
1114-
entry: Vc<Box<dyn OutputAsset>>,
1115-
dynamic_import_entries: Vc<DynamicImportedChunks>,
1116-
},
1117-
Edge {
1118-
files: Vc<OutputAssets>,
1119-
dynamic_import_entries: Vc<DynamicImportedChunks>,
1120-
},
1004+
NodeJs { entry: Vc<Box<dyn OutputAsset>> },
1005+
Edge { files: Vc<OutputAssets> },
11211006
}

‎packages/next-swc/crates/next-core/src/next_manifests/mod.rs

-11
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,6 @@ pub struct AppPathsManifest {
145145
pub node_server_app_paths: PagesManifest,
146146
}
147147

148-
// A struct represent a single entry in react-loadable-manifest.json.
149-
// The manifest is in a format of:
150-
// { [`${origin} -> ${imported}`]: { id: `${origin} -> ${imported}`, files:
151-
// string[] } }
152-
#[derive(Serialize, Default, Debug)]
153-
#[serde(rename_all = "camelCase")]
154-
pub struct LoadableManifest {
155-
pub id: String,
156-
pub files: Vec<String>,
157-
}
158-
159148
#[derive(Serialize, Default, Debug)]
160149
#[serde(rename_all = "camelCase")]
161150
pub struct ServerReferenceManifest {

‎packages/next-swc/crates/next-core/src/next_shared/transforms/next_dynamic.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,12 @@ impl CustomTransformer for NextJsDynamic {
6565
},
6666
self.is_server,
6767
self.is_server_components,
68-
NextDynamicMode::Webpack,
68+
NextDynamicMode::Turbopack {
69+
dynamic_transition_name: match self.mode {
70+
NextMode::Development => "next-client-chunks".to_string(),
71+
NextMode::Build => "next-dynamic".to_string(),
72+
},
73+
},
6974
FileName::Real(ctx.file_path_str.into()),
7075
self.pages_dir.clone(),
7176
));

‎packages/next-swc/crates/next-transform-dynamic/src/lib.rs

-6
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ use swc_core::{
1919
quote,
2020
};
2121

22-
/// Creates a SWC visitor to transform `next/dynamic` calls to have the
23-
/// corresponding `loadableGenerated` property.
24-
///
25-
/// [NOTE] We do not use `NextDynamicMode::Turbopack` yet. It isn't compatible
26-
/// with current loadable manifest, which causes hydration errors.
2722
pub fn next_dynamic(
2823
is_development: bool,
2924
is_server: bool,
@@ -94,7 +89,6 @@ enum NextDynamicPatcherState {
9489
Webpack,
9590
/// In Turbo mode, contains a list of modules that need to be imported with
9691
/// the given transition under a particular ident.
97-
#[allow(unused)]
9892
Turbopack {
9993
dynamic_transition_name: String,
10094
imports: Vec<TurbopackImport>,

‎packages/next/src/server/lib/router-utils/setup-dev-bundler.ts

+12-36
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@ import {
7878
PAGES_MANIFEST,
7979
PHASE_DEVELOPMENT_SERVER,
8080
SERVER_REFERENCE_MANIFEST,
81-
REACT_LOADABLE_MANIFEST,
8281
} from '../../../shared/lib/constants'
8382

8483
import { getMiddlewareRouteMatcher } from '../../../shared/lib/router/utils/middleware-route-matcher'
@@ -118,7 +117,6 @@ import { normalizeMetadataRoute } from '../../../lib/metadata/get-metadata-route
118117
import { clearModuleContext } from '../render-server'
119118
import type { ActionManifest } from '../../../build/webpack/plugins/flight-client-entry-plugin'
120119
import { denormalizePagePath } from '../../../shared/lib/page-path/denormalize-page-path'
121-
import type { LoadableManifest } from '../../load-components'
122120

123121
const wsServer = new ws.Server({ noServer: true })
124122

@@ -505,7 +503,6 @@ async function startWatcher(opts: SetupOpts) {
505503
ws,
506504
Map<string, AsyncIterator<any>>
507505
>()
508-
const loadbleManifests = new Map<string, LoadableManifest>()
509506
const clients = new Set<ws>()
510507

511508
async function loadMiddlewareManifest(
@@ -563,16 +560,6 @@ async function startWatcher(opts: SetupOpts) {
563560
)
564561
}
565562

566-
async function loadLoadableManifest(
567-
pageName: string,
568-
type: 'app' | 'pages' = 'pages'
569-
): Promise<void> {
570-
loadbleManifests.set(
571-
pageName,
572-
await loadPartialManifest(REACT_LOADABLE_MANIFEST, pageName, type)
573-
)
574-
}
575-
576563
const buildingReported = new Set<string>()
577564

578565
async function changeSubscription(
@@ -710,14 +697,6 @@ async function startWatcher(opts: SetupOpts) {
710697
return manifest
711698
}
712699

713-
function mergeLoadableManifests(manifests: Iterable<LoadableManifest>) {
714-
const manifest: LoadableManifest = {}
715-
for (const m of manifests) {
716-
Object.assign(manifest, m)
717-
}
718-
return manifest
719-
}
720-
721700
async function writeFileAtomic(
722701
filePath: string,
723702
content: string
@@ -887,14 +866,13 @@ async function startWatcher(opts: SetupOpts) {
887866
)
888867
}
889868

890-
async function writeLoadableManifest(): Promise<void> {
891-
const loadableManifest = mergeLoadableManifests(loadbleManifests.values())
892-
const loadableManifestPath = path.join(distDir, REACT_LOADABLE_MANIFEST)
893-
deleteCache(loadableManifestPath)
894-
await writeFileAtomic(
895-
loadableManifestPath,
896-
JSON.stringify(loadableManifest, null, 2)
869+
async function writeOtherManifests(): Promise<void> {
870+
const loadableManifestPath = path.join(
871+
distDir,
872+
'react-loadable-manifest.json'
897873
)
874+
deleteCache(loadableManifestPath)
875+
await writeFileAtomic(loadableManifestPath, JSON.stringify({}, null, 2))
898876
}
899877

900878
async function subscribeToHmrEvents(id: string, client: ws) {
@@ -1074,8 +1052,8 @@ async function startWatcher(opts: SetupOpts) {
10741052
await writeAppPathsManifest()
10751053
await writeMiddlewareManifest()
10761054
await writeActionManifest()
1055+
await writeOtherManifests()
10771056
await writeFontManifest()
1078-
await writeLoadableManifest()
10791057

10801058
const turbopackHotReloader: NextJsHotReloaderInterface = {
10811059
turbopackProject: project,
@@ -1242,7 +1220,7 @@ async function startWatcher(opts: SetupOpts) {
12421220
await writeFallbackBuildManifest()
12431221
await writePagesManifest()
12441222
await writeMiddlewareManifest()
1245-
await writeLoadableManifest()
1223+
await writeOtherManifests()
12461224

12471225
return
12481226
}
@@ -1351,13 +1329,12 @@ async function startWatcher(opts: SetupOpts) {
13511329
} else {
13521330
middlewareManifests.delete(page)
13531331
}
1354-
await loadLoadableManifest(page, 'pages')
13551332

13561333
await writeBuildManifest(opts.fsChecker.rewrites)
13571334
await writeFallbackBuildManifest()
13581335
await writePagesManifest()
13591336
await writeMiddlewareManifest()
1360-
await writeLoadableManifest()
1337+
await writeOtherManifests()
13611338

13621339
processIssues(page, page, writtenEndpoint)
13631340

@@ -1381,11 +1358,10 @@ async function startWatcher(opts: SetupOpts) {
13811358
} else {
13821359
middlewareManifests.delete(page)
13831360
}
1384-
await loadLoadableManifest(page, 'pages')
13851361

13861362
await writePagesManifest()
13871363
await writeMiddlewareManifest()
1388-
await writeLoadableManifest()
1364+
await writeOtherManifests()
13891365

13901366
processIssues(page, page, writtenEndpoint)
13911367

@@ -1419,7 +1395,7 @@ async function startWatcher(opts: SetupOpts) {
14191395
await writeAppPathsManifest()
14201396
await writeMiddlewareManifest()
14211397
await writeActionManifest()
1422-
await writeLoadableManifest()
1398+
await writeOtherManifests()
14231399

14241400
processIssues(page, page, writtenEndpoint, true)
14251401

@@ -1444,7 +1420,7 @@ async function startWatcher(opts: SetupOpts) {
14441420
await writeAppPathsManifest()
14451421
await writeMiddlewareManifest()
14461422
await writeMiddlewareManifest()
1447-
await writeLoadableManifest()
1423+
await writeOtherManifests()
14481424

14491425
processIssues(page, page, writtenEndpoint, true)
14501426

‎packages/next/src/server/load-components.ts

-11
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,6 @@ export type ManifestItem = {
3333

3434
export type ReactLoadableManifest = { [moduleId: string]: ManifestItem }
3535

36-
/**
37-
* A manifest entry type for the react-loadable-manifest.json.
38-
*
39-
* The whole manifest.json is a type of `Record<pathName, LoadableManifest>`
40-
* where pathName is a string-based key points to the path of the page contains
41-
* each dynamic imports.
42-
*/
43-
export interface LoadableManifest {
44-
[k: string]: { id: string | number; files: string[] }
45-
}
46-
4736
export type LoadComponentsReturnType<NextModule = any> = {
4837
Component: NextComponentType
4938
pageConfig: PageConfig

‎test/development/basic/next-dynamic.test.ts

+59-66
Original file line numberDiff line numberDiff line change
@@ -237,35 +237,32 @@ describe.each([
237237
})
238238
}
239239
})
240-
// Turbopack doesn't have this feature.
241-
;(process.env.TURBOPACK ? describe.skip : describe)(
242-
'custom chunkfilename',
243-
() => {
244-
it('should render the correct filename', async () => {
245-
const $ = await get$(basePath + '/dynamic/chunkfilename')
246-
expect($('body').text()).toMatch(/test chunkfilename/)
247-
expect($('html').html()).toMatch(/hello-world\.js/)
248-
})
249240

250-
it('should render the component on client side', async () => {
251-
let browser
252-
try {
253-
browser = await webdriver(
254-
next.url,
255-
basePath + '/dynamic/chunkfilename'
256-
)
257-
await check(
258-
() => browser.elementByCss('body').text(),
259-
/test chunkfilename/
260-
)
261-
} finally {
262-
if (browser) {
263-
await browser.close()
264-
}
241+
describe('custom chunkfilename', () => {
242+
it('should render the correct filename', async () => {
243+
const $ = await get$(basePath + '/dynamic/chunkfilename')
244+
expect($('body').text()).toMatch(/test chunkfilename/)
245+
expect($('html').html()).toMatch(/hello-world\.js/)
246+
})
247+
248+
it('should render the component on client side', async () => {
249+
let browser
250+
try {
251+
browser = await webdriver(
252+
next.url,
253+
basePath + '/dynamic/chunkfilename'
254+
)
255+
await check(
256+
() => browser.elementByCss('body').text(),
257+
/test chunkfilename/
258+
)
259+
} finally {
260+
if (browser) {
261+
await browser.close()
265262
}
266-
})
267-
}
268-
)
263+
}
264+
})
265+
})
269266

270267
describe('custom loading', () => {
271268
it('should render custom loading on the server side when `ssr:false` and `loading` is provided', async () => {
@@ -292,49 +289,45 @@ describe.each([
292289
})
293290
})
294291

295-
// TODO: Make this test work with Turbopack. Currently the test relies on `chunkFileName` which is not supported by Turbopack.
296-
;(process.env.TURBOPACK ? describe.skip : describe)(
297-
'Multiple modules',
298-
() => {
299-
it('should only include the rendered module script tag', async () => {
300-
const $ = await get$(basePath + '/dynamic/multiple-modules')
301-
const html = $('html').html()
292+
describe('Multiple modules', () => {
293+
it('should only include the rendered module script tag', async () => {
294+
const $ = await get$(basePath + '/dynamic/multiple-modules')
295+
const html = $('html').html()
296+
expect(html).toMatch(/hello1\.js/)
297+
expect(html).not.toMatch(/hello2\.js/)
298+
})
299+
300+
it('should only load the rendered module in the browser', async () => {
301+
let browser
302+
try {
303+
browser = await webdriver(
304+
next.url,
305+
basePath + '/dynamic/multiple-modules'
306+
)
307+
const html = await browser.eval(
308+
'document.documentElement.innerHTML'
309+
)
302310
expect(html).toMatch(/hello1\.js/)
303311
expect(html).not.toMatch(/hello2\.js/)
304-
})
305-
306-
it('should only load the rendered module in the browser', async () => {
307-
let browser
308-
try {
309-
browser = await webdriver(
310-
next.url,
311-
basePath + '/dynamic/multiple-modules'
312-
)
313-
const html = await browser.eval(
314-
'document.documentElement.innerHTML'
315-
)
316-
expect(html).toMatch(/hello1\.js/)
317-
expect(html).not.toMatch(/hello2\.js/)
318-
} finally {
319-
if (browser) {
320-
await browser.close()
321-
}
312+
} finally {
313+
if (browser) {
314+
await browser.close()
322315
}
323-
})
316+
}
317+
})
324318

325-
it('should only render one bundle if component is used multiple times', async () => {
326-
const $ = await get$(basePath + '/dynamic/multiple-modules')
327-
const html = $('html').html()
328-
try {
329-
expect(html.match(/chunks[\\/]hello1\.js/g).length).toBe(1)
330-
expect(html).not.toMatch(/hello2\.js/)
331-
} catch (err) {
332-
console.error(html)
333-
throw err
334-
}
335-
})
336-
}
337-
)
319+
it('should only render one bundle if component is used multiple times', async () => {
320+
const $ = await get$(basePath + '/dynamic/multiple-modules')
321+
const html = $('html').html()
322+
try {
323+
expect(html.match(/chunks[\\/]hello1\.js/g).length).toBe(1)
324+
expect(html).not.toMatch(/hello2\.js/)
325+
} catch (err) {
326+
console.error(html)
327+
throw err
328+
}
329+
})
330+
})
338331
})
339332
}
340333
)

‎test/integration/next-dynamic-lazy-compilation/test/index.test.js

+24-31
Original file line numberDiff line numberDiff line change
@@ -46,38 +46,31 @@ function runTests() {
4646
})
4747
}
4848

49-
// This test is not needed for Turbopack as it relies on an experimental webpack feature.
50-
;(process.env.TURBOPACK ? describe.skip : describe)(
51-
'next/dynamic lazy compilation',
52-
() => {
53-
describe('dev mode', () => {
54-
beforeAll(async () => {
55-
appPort = await findPort()
56-
app = await launchApp(appDir, appPort)
57-
})
58-
afterAll(() => killApp(app))
59-
60-
runTests(true)
49+
describe('next/dynamic', () => {
50+
describe('dev mode', () => {
51+
beforeAll(async () => {
52+
appPort = await findPort()
53+
app = await launchApp(appDir, appPort)
6154
})
62-
;(process.env.TURBOPACK ? describe.skip : describe)(
63-
'production mode',
64-
() => {
65-
beforeAll(async () => {
66-
await runNextCommand(['build', appDir])
55+
afterAll(() => killApp(app))
56+
57+
runTests(true)
58+
})
59+
;(process.env.TURBOPACK ? describe.skip : describe)('production mode', () => {
60+
beforeAll(async () => {
61+
await runNextCommand(['build', appDir])
6762

68-
app = nextServer({
69-
dir: appDir,
70-
dev: false,
71-
quiet: true,
72-
})
63+
app = nextServer({
64+
dir: appDir,
65+
dev: false,
66+
quiet: true,
67+
})
7368

74-
server = await startApp(app)
75-
appPort = server.address().port
76-
})
77-
afterAll(() => stopApp(server))
69+
server = await startApp(app)
70+
appPort = server.address().port
71+
})
72+
afterAll(() => stopApp(server))
7873

79-
runTests()
80-
}
81-
)
82-
}
83-
)
74+
runTests()
75+
})
76+
})

0 commit comments

Comments
 (0)
Please sign in to comment.