Skip to content

Commit

Permalink
Revert "feat(turbopack): support basic next/dynamic" (#56885)
Browse files Browse the repository at this point in the history
  • Loading branch information
sokra committed Oct 16, 2023
1 parent c1c419f commit 8a51ebc
Show file tree
Hide file tree
Showing 17 changed files with 443 additions and 730 deletions.
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions packages/next-swc/crates/core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ either = "1"
fxhash = "0.2.1"
hex = "0.4.3"
once_cell = { workspace = true }
next-transform-font = {workspace = true}
pathdiff = "0.2.0"
regex = "1.5"
rustc-hash = "1"
Expand All @@ -23,9 +24,6 @@ serde_json = "1"
sha1 = "0.10.1"
tracing = { version = "0.1.37" }

next-transform-dynamic = { workspace = true }
next-transform-font = { workspace = true }

turbopack-binding = { workspace = true, features = [
"__swc_core",
"__swc_core_next_core",
Expand Down
5 changes: 2 additions & 3 deletions packages/next-swc/crates/core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ use std::{cell::RefCell, path::PathBuf, rc::Rc, sync::Arc};
use auto_cjs::contains_cjs;
use either::Either;
use fxhash::FxHashSet;
use next_transform_dynamic::{next_dynamic, NextDynamicMode};
use next_transform_font::next_font_loaders;
use serde::Deserialize;
use turbopack_binding::swc::{
Expand All @@ -59,6 +58,7 @@ mod auto_cjs;
pub mod cjs_optimizer;
pub mod disallow_re_export_all_in_page;
pub mod named_import_transform;
pub mod next_dynamic;
pub mod next_ssg;
pub mod optimize_barrel;
pub mod optimize_server_react;
Expand Down Expand Up @@ -226,7 +226,7 @@ where
!opts.disable_next_ssg
),
amp_attributes::amp_attributes(),
next_dynamic(
next_dynamic::next_dynamic(
opts.is_development,
opts.is_server,
match &opts.server_components {
Expand All @@ -238,7 +238,6 @@ where
},
_ => false,
},
NextDynamicMode::Webpack,
file.name.clone(),
opts.pages_dir.clone()
),
Expand Down
325 changes: 325 additions & 0 deletions packages/next-swc/crates/core/src/next_dynamic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,325 @@
use std::path::{Path, PathBuf};

use pathdiff::diff_paths;
use turbopack_binding::swc::core::{
common::{errors::HANDLER, FileName, DUMMY_SP},
ecma::{
ast::{
ArrayLit, ArrowExpr, BinExpr, BinaryOp, BlockStmtOrExpr, Bool, CallExpr, Callee, Expr,
ExprOrSpread, Id, Ident, ImportDecl, ImportSpecifier, KeyValueProp, Lit, MemberExpr,
MemberProp, Null, ObjectLit, Prop, PropName, PropOrSpread, Str, Tpl,
},
atoms::js_word,
utils::ExprFactory,
visit::{Fold, FoldWith},
},
};

pub fn next_dynamic(
is_development: bool,
is_server: bool,
is_server_components: bool,
filename: FileName,
pages_dir: Option<PathBuf>,
) -> impl Fold {
NextDynamicPatcher {
is_development,
is_server,
is_server_components,
pages_dir,
filename,
dynamic_bindings: vec![],
is_next_dynamic_first_arg: false,
dynamically_imported_specifier: None,
}
}

#[derive(Debug)]
struct NextDynamicPatcher {
is_development: bool,
is_server: bool,
is_server_components: bool,
pages_dir: Option<PathBuf>,
filename: FileName,
dynamic_bindings: Vec<Id>,
is_next_dynamic_first_arg: bool,
dynamically_imported_specifier: Option<String>,
}

impl Fold for NextDynamicPatcher {
fn fold_import_decl(&mut self, decl: ImportDecl) -> ImportDecl {
let ImportDecl {
ref src,
ref specifiers,
..
} = decl;
if &src.value == "next/dynamic" {
for specifier in specifiers {
if let ImportSpecifier::Default(default_specifier) = specifier {
self.dynamic_bindings.push(default_specifier.local.to_id());
}
}
}

decl
}

fn fold_call_expr(&mut self, expr: CallExpr) -> CallExpr {
if self.is_next_dynamic_first_arg {
if let Callee::Import(..) = &expr.callee {
match &*expr.args[0].expr {
Expr::Lit(Lit::Str(Str { value, .. })) => {
self.dynamically_imported_specifier = Some(value.to_string());
}
Expr::Tpl(Tpl { exprs, quasis, .. }) if exprs.is_empty() => {
self.dynamically_imported_specifier = Some(quasis[0].raw.to_string());
}
_ => {}
}
}
return expr.fold_children_with(self);
}
let mut expr = expr.fold_children_with(self);
if let Callee::Expr(i) = &expr.callee {
if let Expr::Ident(identifier) = &**i {
if self.dynamic_bindings.contains(&identifier.to_id()) {
if expr.args.is_empty() {
HANDLER.with(|handler| {
handler
.struct_span_err(
identifier.span,
"next/dynamic requires at least one argument",
)
.emit()
});
return expr;
} else if expr.args.len() > 2 {
HANDLER.with(|handler| {
handler
.struct_span_err(
identifier.span,
"next/dynamic only accepts 2 arguments",
)
.emit()
});
return expr;
}
if expr.args.len() == 2 {
match &*expr.args[1].expr {
Expr::Object(_) => {}
_ => {
HANDLER.with(|handler| {
handler
.struct_span_err(
identifier.span,
"next/dynamic options must be an object literal.\nRead more: https://nextjs.org/docs/messages/invalid-dynamic-options-type",
)
.emit();
});
return expr;
}
}
}

self.is_next_dynamic_first_arg = true;
expr.args[0].expr = expr.args[0].expr.clone().fold_with(self);
self.is_next_dynamic_first_arg = false;

if self.dynamically_imported_specifier.is_none() {
return expr;
}

// dev client or server:
// loadableGenerated: {
// modules:
// ["/project/src/file-being-transformed.js -> " + '../components/hello'] }

// prod client
// loadableGenerated: {
// webpack: () => [require.resolveWeak('../components/hello')],
let generated = Box::new(Expr::Object(ObjectLit {
span: DUMMY_SP,
props: if self.is_development || self.is_server {
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new("modules".into(), DUMMY_SP)),
value: Box::new(Expr::Array(ArrayLit {
elems: vec![Some(ExprOrSpread {
expr: Box::new(Expr::Bin(BinExpr {
span: DUMMY_SP,
op: BinaryOp::Add,
left: Box::new(Expr::Lit(Lit::Str(Str {
value: format!(
"{} -> ",
rel_filename(
self.pages_dir.as_deref(),
&self.filename
)
)
.into(),
span: DUMMY_SP,
raw: None,
}))),
right: Box::new(Expr::Lit(Lit::Str(Str {
value: self
.dynamically_imported_specifier
.as_ref()
.unwrap()
.clone()
.into(),
span: DUMMY_SP,
raw: None,
}))),
})),
spread: None,
})],
span: DUMMY_SP,
})),
})))]
} else {
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new("webpack".into(), DUMMY_SP)),
value: Box::new(Expr::Arrow(ArrowExpr {
params: vec![],
body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Array(
ArrayLit {
elems: vec![Some(ExprOrSpread {
expr: Box::new(Expr::Call(CallExpr {
callee: Callee::Expr(Box::new(Expr::Member(
MemberExpr {
obj: Box::new(Expr::Ident(Ident {
sym: js_word!("require"),
span: DUMMY_SP,
optional: false,
})),
prop: MemberProp::Ident(Ident {
sym: "resolveWeak".into(),
span: DUMMY_SP,
optional: false,
}),
span: DUMMY_SP,
},
))),
args: vec![ExprOrSpread {
expr: Box::new(Expr::Lit(Lit::Str(Str {
value: self
.dynamically_imported_specifier
.as_ref()
.unwrap()
.clone()
.into(),
span: DUMMY_SP,
raw: None,
}))),
spread: None,
}],
span: DUMMY_SP,
type_args: None,
})),
spread: None,
})],
span: DUMMY_SP,
},
)))),
is_async: false,
is_generator: false,
span: DUMMY_SP,
return_type: None,
type_params: None,
})),
})))]
},
}));

let mut props =
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new("loadableGenerated".into(), DUMMY_SP)),
value: generated,
})))];

let mut has_ssr_false = false;

if expr.args.len() == 2 {
if let Expr::Object(ObjectLit {
props: options_props,
..
}) = &*expr.args[1].expr
{
for prop in options_props.iter() {
if let Some(KeyValueProp { key, value }) = match prop {
PropOrSpread::Prop(prop) => match &**prop {
Prop::KeyValue(key_value_prop) => Some(key_value_prop),
_ => None,
},
_ => None,
} {
if let Some(Ident {
sym,
span: _,
optional: _,
}) = match key {
PropName::Ident(ident) => Some(ident),
_ => None,
} {
if sym == "ssr" {
if let Some(Lit::Bool(Bool {
value: false,
span: _,
})) = value.as_lit()
{
has_ssr_false = true
}
}
}
}
}
props.extend(options_props.iter().cloned());
}
}

if has_ssr_false && self.is_server && !self.is_server_components {
expr.args[0] = Lit::Null(Null { span: DUMMY_SP }).as_arg();
}

let second_arg = ExprOrSpread {
spread: None,
expr: Box::new(Expr::Object(ObjectLit {
span: DUMMY_SP,
props,
})),
};

if expr.args.len() == 2 {
expr.args[1] = second_arg;
} else {
expr.args.push(second_arg)
}
self.dynamically_imported_specifier = None;
}
}
}
expr
}
}

fn rel_filename(base: Option<&Path>, file: &FileName) -> String {
let base = match base {
Some(v) => v,
None => return file.to_string(),
};

let file = match file {
FileName::Real(v) => v,
_ => {
return file.to_string();
}
};

let rel_path = diff_paths(file, base);

let rel_path = match rel_path {
Some(v) => v,
None => return file.display().to_string(),
};

rel_path.display().to_string()
}

0 comments on commit 8a51ebc

Please sign in to comment.