Skip to content

Commit 8a51ebc

Browse files
authored
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

Lines changed: 0 additions & 1 deletion
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

Lines changed: 1 addition & 3 deletions
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

Lines changed: 2 additions & 3 deletions
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
),
Lines changed: 325 additions & 0 deletions
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+
}

0 commit comments

Comments
 (0)