mirror of
https://github.com/hanzoai/next.js.git
synced 2026-09-24 17:00:51 +00:00
Update wasm and next-custom-transforms crates to Rust edition 2024 (#90350)
The `wasm` and `next-custom-transforms` crates were still on Rust edition 2018 while the rest of the crates in this repo use edition 2024. This caused a pre-commit hook conflict:
- `cargo fmt` passes the crate's own edition (2018) to `rustfmt`, which uses **case-insensitive** import sorting
- The lint-staged pre-commit hook runs `rustfmt --edition 2024 --`, which uses **ASCII order** import sorting (uppercase before lowercase)
These two sort orders disagree on items like `{custom_before_pass, TransformOptions}` vs `{TransformOptions, custom_before_pass}`, causing an infinite flip-flop: every commit would reorder imports, and the next `cargo fmt` would reorder them back.
## Changes
- Bump `crates/wasm` and `crates/next-custom-transforms` from edition 2018 to 2024
- Add `+ use<C>` precise capturing to `server_actions()` return type to satisfy edition 2024's stricter `impl Trait` lifetime capture rules
- Add `style_edition = "2024"` to `.rustfmt.toml` as a safety net so `cargo fmt` uses 2024-style formatting regardless of individual crate editions
- Reformat all affected files with `cargo fmt`
- Apply new clippy rules
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
edition = "2024"
|
||||
style_edition = "2024"
|
||||
max_width = 100
|
||||
|
||||
comment_width = 100
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
edition = "2018"
|
||||
edition = "2024"
|
||||
name = "next-custom-transforms"
|
||||
version = "0.0.0"
|
||||
publish = false
|
||||
|
||||
@@ -8,12 +8,12 @@ use serde::Deserialize;
|
||||
use swc_core::{
|
||||
atoms::Atom,
|
||||
common::{
|
||||
FileName, Mark, SourceFile, SourceMap, SyntaxContext,
|
||||
comments::{Comments, NoopComments},
|
||||
pass::Optional,
|
||||
FileName, Mark, SourceFile, SourceMap, SyntaxContext,
|
||||
},
|
||||
ecma::{
|
||||
ast::{fn_pass, noop_pass, EsVersion, Pass},
|
||||
ast::{EsVersion, Pass, fn_pass, noop_pass},
|
||||
parser::parse_file_as_module,
|
||||
visit::visit_mut_pass,
|
||||
},
|
||||
@@ -23,7 +23,7 @@ use crate::{
|
||||
linter::linter,
|
||||
transforms::{
|
||||
cjs_finder::contains_cjs,
|
||||
dynamic::{next_dynamic, NextDynamicMode},
|
||||
dynamic::{NextDynamicMode, next_dynamic},
|
||||
fonts::next_font_loaders,
|
||||
lint_codemod_comments::lint_codemod_comments,
|
||||
react_server_components,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use swc_core::ecma::{
|
||||
ast::Pass,
|
||||
visit::{visit_pass, Visit},
|
||||
visit::{Visit, visit_pass},
|
||||
};
|
||||
|
||||
pub fn linter<V>(visitor: V) -> impl Pass
|
||||
|
||||
@@ -23,15 +23,13 @@ struct Finder {
|
||||
|
||||
impl Visit for Finder {
|
||||
fn visit_callee(&mut self, node: &Callee) {
|
||||
if self.is_interested {
|
||||
if let Callee::Expr(e) = node {
|
||||
if let Expr::Ident(c) = &**e {
|
||||
if c.sym.starts_with("use") {
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if self.is_interested
|
||||
&& let Callee::Expr(e) = node
|
||||
&& let Expr::Ident(c) = &**e
|
||||
&& c.sym.starts_with("use")
|
||||
{
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
node.visit_children_with(self);
|
||||
@@ -130,7 +128,7 @@ impl Visit for Finder {
|
||||
mod tests {
|
||||
use swc_core::{
|
||||
common::FileName,
|
||||
ecma::parser::{parse_file_as_program, EsSyntax},
|
||||
ecma::parser::{EsSyntax, parse_file_as_program},
|
||||
};
|
||||
use testing::run_test2;
|
||||
|
||||
|
||||
@@ -56,33 +56,22 @@ impl Visit for CjsFinder {
|
||||
// Note that `Object.defineProperty(module.exports, ...)` will be handled by
|
||||
// `visit_member_expr`.
|
||||
fn visit_call_expr(&mut self, e: &CallExpr) {
|
||||
if !self.ignore_exports {
|
||||
if let Callee::Expr(expr) = &e.callee {
|
||||
if let Expr::Member(member_expr) = &**expr {
|
||||
if let (Expr::Ident(obj), MemberProp::Ident(prop)) =
|
||||
(&*member_expr.obj, &member_expr.prop)
|
||||
{
|
||||
if &*obj.sym == "Object" && &*prop.sym == "defineProperty" {
|
||||
if let Some(ExprOrSpread { expr: expr0, .. }) = e.args.first() {
|
||||
if let Expr::Ident(arg0) = &**expr0 {
|
||||
if &*arg0.sym == "exports" {
|
||||
if let Some(ExprOrSpread { expr: expr1, .. }) =
|
||||
e.args.get(1)
|
||||
{
|
||||
if let Expr::Lit(Lit::Str(arg1)) = &**expr1 {
|
||||
if &*arg1.value == "__esModule" {
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !self.ignore_exports
|
||||
&& let Callee::Expr(expr) = &e.callee
|
||||
&& let Expr::Member(member_expr) = &**expr
|
||||
&& let (Expr::Ident(obj), MemberProp::Ident(prop)) =
|
||||
(&*member_expr.obj, &member_expr.prop)
|
||||
&& &*obj.sym == "Object"
|
||||
&& &*prop.sym == "defineProperty"
|
||||
&& let Some(ExprOrSpread { expr: expr0, .. }) = e.args.first()
|
||||
&& let Expr::Ident(arg0) = &**expr0
|
||||
&& &*arg0.sym == "exports"
|
||||
&& let Some(ExprOrSpread { expr: expr1, .. }) = e.args.get(1)
|
||||
&& let Expr::Lit(Lit::Str(arg1)) = &**expr1
|
||||
&& &*arg1.value == "__esModule"
|
||||
{
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
|
||||
e.callee.visit_with(self);
|
||||
@@ -113,15 +102,15 @@ impl Visit for CjsFinder {
|
||||
}
|
||||
|
||||
fn visit_member_expr(&mut self, e: &MemberExpr) {
|
||||
if let Expr::Ident(obj) = &*e.obj {
|
||||
if let MemberProp::Ident(prop) = &e.prop {
|
||||
// Detect `module.exports` and `exports.__esModule`
|
||||
if (!self.ignore_module && &*obj.sym == "module" && &*prop.sym == "exports")
|
||||
|| (!self.ignore_exports && &*obj.sym == "exports")
|
||||
{
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
if let Expr::Ident(obj) = &*e.obj
|
||||
&& let MemberProp::Ident(prop) = &e.prop
|
||||
{
|
||||
// Detect `module.exports` and `exports.__esModule`
|
||||
if (!self.ignore_module && &*obj.sym == "module" && &*prop.sym == "exports")
|
||||
|| (!self.ignore_exports && &*obj.sym == "exports")
|
||||
{
|
||||
self.found = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::Deserialize;
|
||||
use swc_core::{
|
||||
atoms::{atom, Wtf8Atom},
|
||||
common::{util::take::Take, SyntaxContext, DUMMY_SP},
|
||||
atoms::{Wtf8Atom, atom},
|
||||
common::{DUMMY_SP, SyntaxContext, util::take::Take},
|
||||
ecma::{
|
||||
ast::{
|
||||
CallExpr, Callee, Decl, Expr, Id, Ident, IdentName, Lit, MemberExpr, MemberProp,
|
||||
Module, ModuleItem, Pat, Script, Stmt, VarDecl, VarDeclKind, VarDeclarator,
|
||||
},
|
||||
atoms::Atom,
|
||||
utils::{prepend_stmts, private_ident, ExprFactory, IdentRenamer},
|
||||
visit::{noop_visit_mut_type, noop_visit_type, Visit, VisitMut, VisitMutWith, VisitWith},
|
||||
utils::{ExprFactory, IdentRenamer, prepend_stmts, private_ident},
|
||||
visit::{Visit, VisitMut, VisitMutWith, VisitWith, noop_visit_mut_type, noop_visit_type},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -83,83 +83,78 @@ impl VisitMut for CjsOptimizer {
|
||||
fn visit_mut_expr(&mut self, e: &mut Expr) {
|
||||
e.visit_mut_children_with(self);
|
||||
|
||||
if let Expr::Member(n) = e {
|
||||
if let MemberProp::Ident(prop) = &n.prop {
|
||||
if let Expr::Ident(obj) = &*n.obj {
|
||||
let key = obj.to_id();
|
||||
if self.data.ignored.contains(&key) {
|
||||
return;
|
||||
}
|
||||
if let Expr::Member(n) = e
|
||||
&& let MemberProp::Ident(prop) = &n.prop
|
||||
&& let Expr::Ident(obj) = &*n.obj
|
||||
{
|
||||
let key = obj.to_id();
|
||||
if self.data.ignored.contains(&key) {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(record) = self.data.imports.get(&key) {
|
||||
let mut replaced = false;
|
||||
if let Some(record) = self.data.imports.get(&key) {
|
||||
let mut replaced = false;
|
||||
|
||||
let new_id = self
|
||||
.data
|
||||
.replaced
|
||||
.entry((record.module_specifier.clone(), prop.sym.clone()))
|
||||
.or_insert_with(|| private_ident!(prop.sym.clone()).to_id())
|
||||
.clone();
|
||||
let new_id = self
|
||||
.data
|
||||
.replaced
|
||||
.entry((record.module_specifier.clone(), prop.sym.clone()))
|
||||
.or_insert_with(|| private_ident!(prop.sym.clone()).to_id())
|
||||
.clone();
|
||||
|
||||
if let Some(map) = self.should_rewrite(&record.module_specifier) {
|
||||
if let Some(renamed) = map.get(&prop.sym) {
|
||||
replaced = true;
|
||||
if !self.data.is_prepass {
|
||||
// Transform as `require('foo').bar`
|
||||
let var = VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: Pat::Ident(new_id.clone().into()),
|
||||
init: Some(Box::new(Expr::Member(MemberExpr {
|
||||
span: DUMMY_SP,
|
||||
obj: Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: Ident::new(
|
||||
atom!("require"),
|
||||
DUMMY_SP,
|
||||
self.unresolved_ctxt,
|
||||
)
|
||||
.as_callee(),
|
||||
args: vec![Expr::Lit(Lit::Str(
|
||||
renamed.clone().into(),
|
||||
))
|
||||
.as_arg()],
|
||||
..Default::default()
|
||||
})),
|
||||
prop: MemberProp::Ident(IdentName::new(
|
||||
prop.sym.clone(),
|
||||
DUMMY_SP,
|
||||
)),
|
||||
}))),
|
||||
definite: false,
|
||||
};
|
||||
if let Some(map) = self.should_rewrite(&record.module_specifier)
|
||||
&& let Some(renamed) = map.get(&prop.sym)
|
||||
{
|
||||
replaced = true;
|
||||
if !self.data.is_prepass {
|
||||
// Transform as `require('foo').bar`
|
||||
let var = VarDeclarator {
|
||||
span: DUMMY_SP,
|
||||
name: Pat::Ident(new_id.clone().into()),
|
||||
init: Some(Box::new(Expr::Member(MemberExpr {
|
||||
span: DUMMY_SP,
|
||||
obj: Box::new(Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: Ident::new(
|
||||
atom!("require"),
|
||||
DUMMY_SP,
|
||||
self.unresolved_ctxt,
|
||||
)
|
||||
.as_callee(),
|
||||
args: vec![
|
||||
Expr::Lit(Lit::Str(renamed.clone().into())).as_arg(),
|
||||
],
|
||||
..Default::default()
|
||||
})),
|
||||
prop: MemberProp::Ident(IdentName::new(prop.sym.clone(), DUMMY_SP)),
|
||||
}))),
|
||||
definite: false,
|
||||
};
|
||||
|
||||
if !self.data.extra_stmts.iter().any(|s| {
|
||||
if let Stmt::Decl(Decl::Var(v)) = &s {
|
||||
v.decls.iter().any(|d| d.name == var.name)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
self.data.extra_stmts.push(Stmt::Decl(Decl::Var(
|
||||
Box::new(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Const,
|
||||
decls: vec![var],
|
||||
..Default::default()
|
||||
}),
|
||||
)));
|
||||
}
|
||||
|
||||
*e = Expr::Ident(new_id.into());
|
||||
}
|
||||
if !self.data.extra_stmts.iter().any(|s| {
|
||||
if let Stmt::Decl(Decl::Var(v)) = &s {
|
||||
v.decls.iter().any(|d| d.name == var.name)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
self.data
|
||||
.extra_stmts
|
||||
.push(Stmt::Decl(Decl::Var(Box::new(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Const,
|
||||
decls: vec![var],
|
||||
..Default::default()
|
||||
}))));
|
||||
}
|
||||
|
||||
if !replaced {
|
||||
self.data.ignored.insert(key);
|
||||
}
|
||||
*e = Expr::Ident(new_id.into());
|
||||
}
|
||||
}
|
||||
|
||||
if !replaced {
|
||||
self.data.ignored.insert(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,10 +191,10 @@ impl VisitMut for CjsOptimizer {
|
||||
fn visit_mut_stmt(&mut self, n: &mut Stmt) {
|
||||
n.visit_mut_children_with(self);
|
||||
|
||||
if let Stmt::Decl(Decl::Var(v)) = n {
|
||||
if v.decls.is_empty() {
|
||||
n.take();
|
||||
}
|
||||
if let Stmt::Decl(Decl::Var(v)) = n
|
||||
&& v.decls.is_empty()
|
||||
{
|
||||
n.take();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,34 +207,31 @@ impl VisitMut for CjsOptimizer {
|
||||
args,
|
||||
..
|
||||
})) = n.init.as_deref()
|
||||
&& let Expr::Ident(ident) = &**callee
|
||||
&& ident.ctxt == self.unresolved_ctxt
|
||||
&& ident.sym == *"require"
|
||||
&& let Some(arg) = args.first()
|
||||
&& let Expr::Lit(Lit::Str(v)) = &*arg.expr
|
||||
{
|
||||
if let Expr::Ident(ident) = &**callee {
|
||||
if ident.ctxt == self.unresolved_ctxt && ident.sym == *"require" {
|
||||
if let Some(arg) = args.first() {
|
||||
if let Expr::Lit(Lit::Str(v)) = &*arg.expr {
|
||||
// TODO: Config
|
||||
// TODO: Config
|
||||
|
||||
if let Pat::Ident(name) = &n.name {
|
||||
if self.should_rewrite(&v.value).is_some() {
|
||||
let key = name.to_id();
|
||||
if let Pat::Ident(name) = &n.name
|
||||
&& self.should_rewrite(&v.value).is_some()
|
||||
{
|
||||
let key = name.to_id();
|
||||
|
||||
if !self.data.is_prepass {
|
||||
if !self.data.ignored.contains(&key) {
|
||||
// Drop variable declarator.
|
||||
n.name.take();
|
||||
}
|
||||
} else {
|
||||
self.data.imports.insert(
|
||||
key,
|
||||
ImportRecord {
|
||||
module_specifier: v.value.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !self.data.is_prepass {
|
||||
if !self.data.ignored.contains(&key) {
|
||||
// Drop variable declarator.
|
||||
n.name.take();
|
||||
}
|
||||
} else {
|
||||
self.data.imports.insert(
|
||||
key,
|
||||
ImportRecord {
|
||||
module_specifier: v.value.clone(),
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -269,12 +261,10 @@ impl Visit for Analyzer<'_> {
|
||||
callee: Callee::Expr(callee),
|
||||
..
|
||||
})) = n.init.as_deref()
|
||||
&& let Expr::Ident(ident) = &**callee
|
||||
&& ident.sym == *"require"
|
||||
{
|
||||
if let Expr::Ident(ident) = &**callee {
|
||||
if ident.sym == *"require" {
|
||||
safe_to_ignore = true;
|
||||
}
|
||||
}
|
||||
safe_to_ignore = true;
|
||||
}
|
||||
|
||||
if safe_to_ignore {
|
||||
|
||||
@@ -2,14 +2,14 @@ use std::fmt::Write;
|
||||
|
||||
use swc_core::{
|
||||
atoms::Atom,
|
||||
common::{util::take::Take, DUMMY_SP},
|
||||
common::{DUMMY_SP, util::take::Take},
|
||||
ecma::{
|
||||
ast::{
|
||||
CallExpr, Callee, ExportDefaultDecl, ExportDefaultExpr, Expr, FnDecl, FnExpr,
|
||||
KeyValueProp, MemberProp, ObjectLit, Pass, PropOrSpread, VarDeclarator,
|
||||
},
|
||||
utils::ExprFactory,
|
||||
visit::{visit_mut_pass, VisitMut, VisitMutWith},
|
||||
visit::{VisitMut, VisitMutWith, visit_mut_pass},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ use swc_core::{
|
||||
common::{Span, Spanned},
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{fold_pass, Fold},
|
||||
visit::{Fold, fold_pass},
|
||||
},
|
||||
quote,
|
||||
};
|
||||
@@ -52,12 +52,11 @@ fn find_var_init_span(items: &[ModuleItem], local_name: &str) -> Option<Span> {
|
||||
_ => continue,
|
||||
};
|
||||
for d in &decl.decls {
|
||||
if let Pat::Ident(ident) = &d.name {
|
||||
if ident.id.sym == local_name {
|
||||
if let Some(init) = &d.init {
|
||||
return Some(init.span());
|
||||
}
|
||||
}
|
||||
if let Pat::Ident(ident) = &d.name
|
||||
&& ident.id.sym == local_name
|
||||
&& let Some(init) = &d.init
|
||||
{
|
||||
return Some(init.span());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -72,12 +71,11 @@ impl Fold for DebugInstantStack {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
|
||||
if let Decl::Var(var_decl) = &export_decl.decl {
|
||||
for decl in &var_decl.decls {
|
||||
if let Pat::Ident(ident) = &decl.name {
|
||||
if ident.id.sym == "unstable_instant" {
|
||||
if let Some(init) = &decl.init {
|
||||
self.instant_export_span = Some(init.span());
|
||||
}
|
||||
}
|
||||
if let Pat::Ident(ident) = &decl.name
|
||||
&& ident.id.sym == "unstable_instant"
|
||||
&& let Some(init) = &decl.init
|
||||
{
|
||||
self.instant_export_span = Some(init.span());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,17 +5,17 @@ use std::{
|
||||
|
||||
use pathdiff::diff_paths;
|
||||
use swc_core::{
|
||||
atoms::{atom, Atom, Wtf8Atom},
|
||||
common::{errors::HANDLER, FileName, Span, DUMMY_SP},
|
||||
atoms::{Atom, Wtf8Atom, atom},
|
||||
common::{DUMMY_SP, FileName, Span, errors::HANDLER},
|
||||
ecma::{
|
||||
ast::{
|
||||
op, ArrayLit, ArrowExpr, BinExpr, BlockStmt, BlockStmtOrExpr, Bool, CallExpr, Callee,
|
||||
Expr, ExprOrSpread, ExprStmt, Id, Ident, IdentName, ImportDecl, ImportNamedSpecifier,
|
||||
ArrayLit, ArrowExpr, BinExpr, BlockStmt, BlockStmtOrExpr, Bool, CallExpr, Callee, Expr,
|
||||
ExprOrSpread, ExprStmt, Id, Ident, IdentName, ImportDecl, ImportNamedSpecifier,
|
||||
ImportSpecifier, KeyValueProp, Lit, ModuleDecl, ModuleItem, ObjectLit, Pass, Prop,
|
||||
PropName, PropOrSpread, Stmt, Str, Tpl, UnaryExpr, UnaryOp,
|
||||
PropName, PropOrSpread, Stmt, Str, Tpl, UnaryExpr, UnaryOp, op,
|
||||
},
|
||||
utils::{private_ident, quote_ident, ExprFactory},
|
||||
visit::{visit_mut_pass, VisitMut, VisitMutWith},
|
||||
utils::{ExprFactory, private_ident, quote_ident},
|
||||
visit::{VisitMut, VisitMutWith, visit_mut_pass},
|
||||
},
|
||||
quote,
|
||||
};
|
||||
@@ -154,35 +154,33 @@ impl VisitMut for NextDynamicPatcher {
|
||||
|
||||
expr.visit_mut_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() {
|
||||
if let Callee::Expr(i) = &expr.callee
|
||||
&& let Expr::Ident(identifier) = &**i
|
||||
&& 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;
|
||||
} else if expr.args.len() > 2 {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(identifier.span, "next/dynamic only accepts 2 arguments")
|
||||
.emit()
|
||||
});
|
||||
return;
|
||||
}
|
||||
if expr.args.len() == 2 {
|
||||
match &*expr.args[1].expr {
|
||||
Expr::Object(_) => {}
|
||||
_ => {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
identifier.span,
|
||||
"next/dynamic requires at least one argument",
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
return;
|
||||
} else if expr.args.len() > 2 {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
identifier.span,
|
||||
"next/dynamic only accepts 2 arguments",
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
return;
|
||||
}
|
||||
if expr.args.len() == 2 {
|
||||
match &*expr.args[1].expr {
|
||||
Expr::Object(_) => {}
|
||||
_ => {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
identifier.span,
|
||||
@@ -190,228 +188,215 @@ impl VisitMut for NextDynamicPatcher {
|
||||
)
|
||||
.emit();
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.is_next_dynamic_first_arg = true;
|
||||
expr.args[0].expr.visit_mut_with(self);
|
||||
self.is_next_dynamic_first_arg = false;
|
||||
|
||||
let Some((dynamically_imported_specifier, dynamically_imported_specifier_span)) =
|
||||
self.dynamically_imported_specifier.take()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let project_dir = match self.pages_or_app_dir.as_deref() {
|
||||
Some(pages_or_app) => pages_or_app.parent(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let generated = Box::new(Expr::Object(ObjectLit {
|
||||
span: DUMMY_SP,
|
||||
props: match &mut self.state {
|
||||
NextDynamicPatcherState::Webpack => {
|
||||
// dev client or server:
|
||||
// loadableGenerated: {
|
||||
// modules:
|
||||
// ["/project/src/file-being-transformed.js -> " +
|
||||
// '../components/hello'] }
|
||||
//
|
||||
// prod client
|
||||
// loadableGenerated: {
|
||||
// webpack: () => [require.resolveWeak('../components/hello')],
|
||||
if self.is_development || self.is_server_compiler {
|
||||
module_id_options(quote!(
|
||||
"$left + $right" as Expr,
|
||||
left: Expr = format!(
|
||||
"{} -> ",
|
||||
rel_filename(project_dir, &self.filename)
|
||||
)
|
||||
.into(),
|
||||
right: Expr = dynamically_imported_specifier.clone().into(),
|
||||
))
|
||||
} else {
|
||||
webpack_options(quote!(
|
||||
"require.resolveWeak($id)" as Expr,
|
||||
id: Expr = dynamically_imported_specifier.clone().into()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
NextDynamicPatcherState::Turbopack { imports, .. } => {
|
||||
// loadableGenerated: { modules: [
|
||||
// ".../client.js [app-client] (ecmascript, next/dynamic entry)"
|
||||
// ]}
|
||||
let id_ident =
|
||||
private_ident!(dynamically_imported_specifier_span, "id");
|
||||
|
||||
imports.push(TurbopackImport::Import {
|
||||
id_ident: id_ident.clone(),
|
||||
specifier: dynamically_imported_specifier.clone(),
|
||||
});
|
||||
|
||||
module_id_options(Expr::Ident(id_ident))
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
let mut props =
|
||||
vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
|
||||
key: PropName::Ident(IdentName::new(
|
||||
atom!("loadableGenerated"),
|
||||
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(IdentName { sym, span: _ }) = 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());
|
||||
}
|
||||
}
|
||||
|
||||
let should_skip_ssr_compile = has_ssr_false
|
||||
&& self.is_server_compiler
|
||||
&& !self.is_react_server_layer
|
||||
&& self.prefer_esm;
|
||||
|
||||
match &self.state {
|
||||
NextDynamicPatcherState::Webpack => {
|
||||
// Only use `require.resolveWebpack` to decouple modules for webpack,
|
||||
// turbopack doesn't need this
|
||||
|
||||
// When it's not preferring to picking up ESM (in the pages router), we
|
||||
// don't need to do it as it doesn't need to enter the non-ssr module.
|
||||
//
|
||||
// Also transforming it to `require.resolveWeak` doesn't work with ESM
|
||||
// imports ( i.e. require.resolveWeak(esm asset)).
|
||||
if should_skip_ssr_compile {
|
||||
// if it's server components SSR layer
|
||||
// Transform 1st argument `expr.args[0]` aka the module loader from:
|
||||
// dynamic(() => import('./client-mod'), { ssr: false }))`
|
||||
// into:
|
||||
// dynamic(async () => {
|
||||
// require.resolveWeak('./client-mod')
|
||||
// }, { ssr: false }))`
|
||||
|
||||
let require_resolve_weak_expr = Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: quote_ident!("require.resolveWeak").as_callee(),
|
||||
args: vec![ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(Expr::Lit(Lit::Str(Str {
|
||||
span: DUMMY_SP,
|
||||
value: dynamically_imported_specifier.clone(),
|
||||
raw: None,
|
||||
}))),
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let side_effect_free_loader_arg = Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
params: vec![],
|
||||
body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: Box::new(exec_expr_when_resolve_weak_available(
|
||||
&require_resolve_weak_expr,
|
||||
)),
|
||||
})],
|
||||
..Default::default()
|
||||
})),
|
||||
is_async: true,
|
||||
is_generator: false,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
expr.args[0] = side_effect_free_loader_arg.as_arg();
|
||||
}
|
||||
}
|
||||
NextDynamicPatcherState::Turbopack {
|
||||
dynamic_transition_name,
|
||||
..
|
||||
} => {
|
||||
// When `ssr: false`
|
||||
// if it's server components SSR layer
|
||||
// Transform 1st argument `expr.args[0]` aka the module loader from:
|
||||
// dynamic(() => import('./client-mod'), { ssr: false }))`
|
||||
// into:
|
||||
// dynamic(async () => {}, { ssr: false }))`
|
||||
if should_skip_ssr_compile {
|
||||
let side_effect_free_loader_arg = Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
params: vec![],
|
||||
body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![],
|
||||
..Default::default()
|
||||
})),
|
||||
is_async: true,
|
||||
is_generator: false,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
expr.args[0] = side_effect_free_loader_arg.as_arg();
|
||||
} else {
|
||||
// Add `{with:{turbopack-transition: ...}}` to the dynamic import
|
||||
let mut visitor = DynamicImportTransitionAdder {
|
||||
transition_name: dynamic_transition_name,
|
||||
};
|
||||
expr.args[0].visit_mut_with(&mut visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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.is_next_dynamic_first_arg = true;
|
||||
expr.args[0].expr.visit_mut_with(self);
|
||||
self.is_next_dynamic_first_arg = false;
|
||||
|
||||
let Some((dynamically_imported_specifier, dynamically_imported_specifier_span)) =
|
||||
self.dynamically_imported_specifier.take()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
let project_dir = match self.pages_or_app_dir.as_deref() {
|
||||
Some(pages_or_app) => pages_or_app.parent(),
|
||||
_ => None,
|
||||
};
|
||||
|
||||
let generated = Box::new(Expr::Object(ObjectLit {
|
||||
span: DUMMY_SP,
|
||||
props: match &mut self.state {
|
||||
NextDynamicPatcherState::Webpack => {
|
||||
// dev client or server:
|
||||
// loadableGenerated: {
|
||||
// modules:
|
||||
// ["/project/src/file-being-transformed.js -> " +
|
||||
// '../components/hello'] }
|
||||
//
|
||||
// prod client
|
||||
// loadableGenerated: {
|
||||
// webpack: () => [require.resolveWeak('../components/hello')],
|
||||
if self.is_development || self.is_server_compiler {
|
||||
module_id_options(quote!(
|
||||
"$left + $right" as Expr,
|
||||
left: Expr = format!(
|
||||
"{} -> ",
|
||||
rel_filename(project_dir, &self.filename)
|
||||
)
|
||||
.into(),
|
||||
right: Expr = dynamically_imported_specifier.clone().into(),
|
||||
))
|
||||
} else {
|
||||
webpack_options(quote!(
|
||||
"require.resolveWeak($id)" as Expr,
|
||||
id: Expr = dynamically_imported_specifier.clone().into()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
NextDynamicPatcherState::Turbopack { imports, .. } => {
|
||||
// loadableGenerated: { modules: [
|
||||
// ".../client.js [app-client] (ecmascript, next/dynamic entry)"
|
||||
// ]}
|
||||
let id_ident = private_ident!(dynamically_imported_specifier_span, "id");
|
||||
|
||||
imports.push(TurbopackImport::Import {
|
||||
id_ident: id_ident.clone(),
|
||||
specifier: dynamically_imported_specifier.clone(),
|
||||
});
|
||||
|
||||
module_id_options(Expr::Ident(id_ident))
|
||||
}
|
||||
},
|
||||
}));
|
||||
|
||||
let mut props = vec![PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
|
||||
key: PropName::Ident(IdentName::new(atom!("loadableGenerated"), DUMMY_SP)),
|
||||
value: generated,
|
||||
})))];
|
||||
|
||||
let mut has_ssr_false = false;
|
||||
|
||||
if expr.args.len() == 2
|
||||
&& 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,
|
||||
} && let Some(IdentName { sym, span: _ }) = match key {
|
||||
PropName::Ident(ident) => Some(ident),
|
||||
_ => None,
|
||||
} && sym == "ssr"
|
||||
&& let Some(Lit::Bool(Bool {
|
||||
value: false,
|
||||
span: _,
|
||||
})) = value.as_lit()
|
||||
{
|
||||
has_ssr_false = true
|
||||
}
|
||||
}
|
||||
props.extend(options_props.iter().cloned());
|
||||
}
|
||||
|
||||
let should_skip_ssr_compile = has_ssr_false
|
||||
&& self.is_server_compiler
|
||||
&& !self.is_react_server_layer
|
||||
&& self.prefer_esm;
|
||||
|
||||
match &self.state {
|
||||
NextDynamicPatcherState::Webpack => {
|
||||
// Only use `require.resolveWebpack` to decouple modules for webpack,
|
||||
// turbopack doesn't need this
|
||||
|
||||
// When it's not preferring to picking up ESM (in the pages router), we
|
||||
// don't need to do it as it doesn't need to enter the non-ssr module.
|
||||
//
|
||||
// Also transforming it to `require.resolveWeak` doesn't work with ESM
|
||||
// imports ( i.e. require.resolveWeak(esm asset)).
|
||||
if should_skip_ssr_compile {
|
||||
// if it's server components SSR layer
|
||||
// Transform 1st argument `expr.args[0]` aka the module loader from:
|
||||
// dynamic(() => import('./client-mod'), { ssr: false }))`
|
||||
// into:
|
||||
// dynamic(async () => {
|
||||
// require.resolveWeak('./client-mod')
|
||||
// }, { ssr: false }))`
|
||||
|
||||
let require_resolve_weak_expr = Expr::Call(CallExpr {
|
||||
span: DUMMY_SP,
|
||||
callee: quote_ident!("require.resolveWeak").as_callee(),
|
||||
args: vec![ExprOrSpread {
|
||||
spread: None,
|
||||
expr: Box::new(Expr::Lit(Lit::Str(Str {
|
||||
span: DUMMY_SP,
|
||||
value: dynamically_imported_specifier.clone(),
|
||||
raw: None,
|
||||
}))),
|
||||
}],
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let side_effect_free_loader_arg = Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
params: vec![],
|
||||
body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![Stmt::Expr(ExprStmt {
|
||||
span: DUMMY_SP,
|
||||
expr: Box::new(exec_expr_when_resolve_weak_available(
|
||||
&require_resolve_weak_expr,
|
||||
)),
|
||||
})],
|
||||
..Default::default()
|
||||
})),
|
||||
is_async: true,
|
||||
is_generator: false,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
expr.args[0] = side_effect_free_loader_arg.as_arg();
|
||||
}
|
||||
}
|
||||
NextDynamicPatcherState::Turbopack {
|
||||
dynamic_transition_name,
|
||||
..
|
||||
} => {
|
||||
// When `ssr: false`
|
||||
// if it's server components SSR layer
|
||||
// Transform 1st argument `expr.args[0]` aka the module loader from:
|
||||
// dynamic(() => import('./client-mod'), { ssr: false }))`
|
||||
// into:
|
||||
// dynamic(async () => {}, { ssr: false }))`
|
||||
if should_skip_ssr_compile {
|
||||
let side_effect_free_loader_arg = Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
params: vec![],
|
||||
body: Box::new(BlockStmtOrExpr::BlockStmt(BlockStmt {
|
||||
span: DUMMY_SP,
|
||||
stmts: vec![],
|
||||
..Default::default()
|
||||
})),
|
||||
is_async: true,
|
||||
is_generator: false,
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
expr.args[0] = side_effect_free_loader_arg.as_arg();
|
||||
} else {
|
||||
// Add `{with:{turbopack-transition: ...}}` to the dynamic import
|
||||
let mut visitor = DynamicImportTransitionAdder {
|
||||
transition_name: dynamic_transition_name,
|
||||
};
|
||||
expr.args[0].visit_mut_with(&mut visitor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ use swc_core::{
|
||||
common::errors::HANDLER,
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{noop_visit_type, Visit},
|
||||
visit::{Visit, noop_visit_type},
|
||||
},
|
||||
};
|
||||
pub struct FindFunctionsOutsideModuleScope<'a> {
|
||||
|
||||
@@ -3,7 +3,7 @@ use swc_core::{
|
||||
common::errors::HANDLER,
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{noop_visit_type, Visit},
|
||||
visit::{Visit, noop_visit_type},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use serde_json::Value;
|
||||
use swc_core::{
|
||||
atoms::Wtf8Atom,
|
||||
common::{errors::HANDLER, Spanned, DUMMY_SP},
|
||||
common::{DUMMY_SP, Spanned, errors::HANDLER},
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{noop_visit_type, Visit},
|
||||
visit::{Visit, noop_visit_type},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -19,69 +19,67 @@ impl FontImportsGenerator<'_> {
|
||||
call_expr: &CallExpr,
|
||||
variable_name: &Result<Ident, &Pat>,
|
||||
) -> Option<ImportDecl> {
|
||||
if let Callee::Expr(callee_expr) = &call_expr.callee {
|
||||
if let Expr::Ident(ident) = &**callee_expr {
|
||||
if let Some(font_function) = self.state.font_functions.get(&ident.to_id()) {
|
||||
self.state
|
||||
.font_functions_in_allowed_scope
|
||||
.insert(ident.span.lo);
|
||||
if let Callee::Expr(callee_expr) = &call_expr.callee
|
||||
&& let Expr::Ident(ident) = &**callee_expr
|
||||
&& let Some(font_function) = self.state.font_functions.get(&ident.to_id())
|
||||
{
|
||||
self.state
|
||||
.font_functions_in_allowed_scope
|
||||
.insert(ident.span.lo);
|
||||
|
||||
let json: Result<Vec<Value>, ()> = call_expr
|
||||
.args
|
||||
.iter()
|
||||
.map(|expr_or_spread| {
|
||||
if let Some(span) = expr_or_spread.spread {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(span, "Font loaders don't accept spreads")
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
|
||||
expr_to_json(&expr_or_spread.expr)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Ok(json) = json {
|
||||
let function_name = match &font_function.function_name {
|
||||
Some(function) => String::from(&**function),
|
||||
None => String::new(),
|
||||
};
|
||||
let mut query_json_values = serde_json::Map::new();
|
||||
query_json_values.insert(
|
||||
String::from("path"),
|
||||
Value::String(self.relative_path.to_string()),
|
||||
);
|
||||
query_json_values
|
||||
.insert(String::from("import"), Value::String(function_name));
|
||||
query_json_values.insert(String::from("arguments"), Value::Array(json));
|
||||
if let Ok(ident) = variable_name {
|
||||
query_json_values.insert(
|
||||
String::from("variableName"),
|
||||
Value::String(ident.sym.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
let query_json = Value::Object(query_json_values);
|
||||
|
||||
return Some(ImportDecl {
|
||||
src: Box::new(Str {
|
||||
value: Wtf8Atom::from(format!(
|
||||
"{}/target.css?{}",
|
||||
font_function.loader.to_string_lossy(),
|
||||
query_json
|
||||
)),
|
||||
raw: None,
|
||||
span: DUMMY_SP,
|
||||
}),
|
||||
specifiers: vec![],
|
||||
type_only: false,
|
||||
with: None,
|
||||
span: DUMMY_SP,
|
||||
phase: Default::default(),
|
||||
let json: Result<Vec<Value>, ()> = call_expr
|
||||
.args
|
||||
.iter()
|
||||
.map(|expr_or_spread| {
|
||||
if let Some(span) = expr_or_spread.spread {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(span, "Font loaders don't accept spreads")
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
|
||||
expr_to_json(&expr_or_spread.expr)
|
||||
})
|
||||
.collect();
|
||||
|
||||
if let Ok(json) = json {
|
||||
let function_name = match &font_function.function_name {
|
||||
Some(function) => String::from(&**function),
|
||||
None => String::new(),
|
||||
};
|
||||
let mut query_json_values = serde_json::Map::new();
|
||||
query_json_values.insert(
|
||||
String::from("path"),
|
||||
Value::String(self.relative_path.to_string()),
|
||||
);
|
||||
query_json_values.insert(String::from("import"), Value::String(function_name));
|
||||
query_json_values.insert(String::from("arguments"), Value::Array(json));
|
||||
if let Ok(ident) = variable_name {
|
||||
query_json_values.insert(
|
||||
String::from("variableName"),
|
||||
Value::String(ident.sym.to_string()),
|
||||
);
|
||||
}
|
||||
|
||||
let query_json = Value::Object(query_json_values);
|
||||
|
||||
return Some(ImportDecl {
|
||||
src: Box::new(Str {
|
||||
value: Wtf8Atom::from(format!(
|
||||
"{}/target.css?{}",
|
||||
font_function.loader.to_string_lossy(),
|
||||
query_json
|
||||
)),
|
||||
raw: None,
|
||||
span: DUMMY_SP,
|
||||
}),
|
||||
specifiers: vec![],
|
||||
type_only: false,
|
||||
with: None,
|
||||
span: DUMMY_SP,
|
||||
phase: Default::default(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,49 +92,49 @@ impl FontImportsGenerator<'_> {
|
||||
Pat::Ident(ident) => Ok(ident.id.clone()),
|
||||
pattern => Err(pattern),
|
||||
};
|
||||
if let Some(expr) = &decl.init {
|
||||
if let Expr::Call(call_expr) = &**expr {
|
||||
let import_decl = self.check_call_expr(call_expr, &ident);
|
||||
if let Some(expr) = &decl.init
|
||||
&& let Expr::Call(call_expr) = &**expr
|
||||
{
|
||||
let import_decl = self.check_call_expr(call_expr, &ident);
|
||||
|
||||
if let Some(mut import_decl) = import_decl {
|
||||
match var_decl.kind {
|
||||
VarDeclKind::Const => {}
|
||||
_ => {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
var_decl.span,
|
||||
"Font loader calls must be assigned to a const",
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
if let Some(mut import_decl) = import_decl {
|
||||
match var_decl.kind {
|
||||
VarDeclKind::Const => {}
|
||||
_ => {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
var_decl.span,
|
||||
"Font loader calls must be assigned to a const",
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
match ident {
|
||||
Ok(ident) => {
|
||||
import_decl.specifiers =
|
||||
vec![ImportSpecifier::Default(ImportDefaultSpecifier {
|
||||
span: DUMMY_SP,
|
||||
local: ident.clone(),
|
||||
})];
|
||||
match ident {
|
||||
Ok(ident) => {
|
||||
import_decl.specifiers =
|
||||
vec![ImportSpecifier::Default(ImportDefaultSpecifier {
|
||||
span: DUMMY_SP,
|
||||
local: ident.clone(),
|
||||
})];
|
||||
|
||||
self.state
|
||||
.font_imports
|
||||
.push(ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)));
|
||||
self.state
|
||||
.font_imports
|
||||
.push(ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl)));
|
||||
|
||||
return Some(ident);
|
||||
}
|
||||
Err(pattern) => {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
pattern.span(),
|
||||
"Font loader calls must be assigned to an identifier",
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
return Some(ident);
|
||||
}
|
||||
Err(pattern) => {
|
||||
HANDLER.with(|handler| {
|
||||
handler
|
||||
.struct_span_err(
|
||||
pattern.span(),
|
||||
"Font loader calls must be assigned to an identifier",
|
||||
)
|
||||
.emit()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,14 +155,17 @@ impl Visit for FontImportsGenerator<'_> {
|
||||
}
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
|
||||
if let Decl::Var(var_decl) = &export_decl.decl {
|
||||
if let Some(ident) = self.check_var_decl(var_decl) {
|
||||
self.state
|
||||
.removable_module_items
|
||||
.insert(export_decl.span.lo);
|
||||
if let Decl::Var(var_decl) = &export_decl.decl
|
||||
&& let Some(ident) = self.check_var_decl(var_decl)
|
||||
{
|
||||
self.state
|
||||
.removable_module_items
|
||||
.insert(export_decl.span.lo);
|
||||
|
||||
self.state.font_exports.push(ModuleItem::ModuleDecl(
|
||||
ModuleDecl::ExportNamed(NamedExport {
|
||||
self.state
|
||||
.font_exports
|
||||
.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
NamedExport {
|
||||
span: DUMMY_SP,
|
||||
specifiers: vec![ExportSpecifier::Named(ExportNamedSpecifier {
|
||||
orig: ModuleExportName::Ident(ident),
|
||||
@@ -175,9 +176,8 @@ impl Visit for FontImportsGenerator<'_> {
|
||||
src: None,
|
||||
type_only: false,
|
||||
with: None,
|
||||
}),
|
||||
));
|
||||
}
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
|
||||
@@ -6,7 +6,7 @@ use swc_core::{
|
||||
ecma::{
|
||||
ast::{Id, ModuleItem, Pass},
|
||||
atoms::Atom,
|
||||
visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitWith},
|
||||
visit::{VisitMut, VisitWith, noop_visit_mut_type, visit_mut_pass},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use swc_core::{
|
||||
atoms::{atom, Atom, Wtf8Atom},
|
||||
atoms::{Atom, Wtf8Atom, atom},
|
||||
ecma::{
|
||||
ast::{
|
||||
Expr, Id, ImportDecl, ImportNamedSpecifier, ImportSpecifier, MemberExpr, MemberProp,
|
||||
Module,
|
||||
},
|
||||
visit::{noop_visit_type, Visit, VisitWith},
|
||||
visit::{Visit, VisitWith, noop_visit_type},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -37,10 +37,10 @@ impl VisitMut for MiddlewareDynamic {
|
||||
let callee = &call_expr.callee;
|
||||
if let Callee::Expr(callee) = callee {
|
||||
// `eval('some')`, or `Function('some')`
|
||||
if let Expr::Ident(ident) = &**callee {
|
||||
if ident.sym == "eval" || ident.sym == "Function" {
|
||||
should_wrap = Some(WrappedExpr::Eval);
|
||||
}
|
||||
if let Expr::Ident(ident) = &**callee
|
||||
&& (ident.sym == "eval" || ident.sym == "Function")
|
||||
{
|
||||
should_wrap = Some(WrappedExpr::Eval);
|
||||
}
|
||||
|
||||
if let Expr::Member(MemberExpr {
|
||||
@@ -70,16 +70,15 @@ impl VisitMut for MiddlewareDynamic {
|
||||
prop: MemberProp::Ident(member_prop_ident),
|
||||
..
|
||||
}) = &**obj
|
||||
&& let Expr::Ident(ident) = &**obj
|
||||
{
|
||||
if let Expr::Ident(ident) = &**obj {
|
||||
// `global.WebAssembly.compile('some')` &
|
||||
// `global.WebAssembly.instantiate('some')`
|
||||
if ident.sym == "global" && member_prop_ident.sym == "WebAssembly" {
|
||||
if prop_ident.sym == "compile" {
|
||||
should_wrap = Some(WrappedExpr::WasmCompile);
|
||||
} else if prop_ident.sym == "instantiate" {
|
||||
should_wrap = Some(WrappedExpr::WasmInstantiate);
|
||||
}
|
||||
// `global.WebAssembly.compile('some')` &
|
||||
// `global.WebAssembly.instantiate('some')`
|
||||
if ident.sym == "global" && member_prop_ident.sym == "WebAssembly" {
|
||||
if prop_ident.sym == "compile" {
|
||||
should_wrap = Some(WrappedExpr::WasmCompile);
|
||||
} else if prop_ident.sym == "instantiate" {
|
||||
should_wrap = Some(WrappedExpr::WasmInstantiate);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,12 +99,11 @@ impl VisitMut for MiddlewareDynamic {
|
||||
}
|
||||
}
|
||||
|
||||
if let Expr::New(NewExpr { callee, .. }) = &expr {
|
||||
if let Expr::Ident(ident) = &**callee {
|
||||
if ident.sym == "Function" {
|
||||
*expr = quote!("__next_eval__(function() { return $orig_call });" as Expr, orig_call: Expr = expr.clone());
|
||||
}
|
||||
}
|
||||
if let Expr::New(NewExpr { callee, .. }) = &expr
|
||||
&& let Expr::Ident(ident) = &**callee
|
||||
&& ident.sym == "Function"
|
||||
{
|
||||
*expr = quote!("__next_eval__(function() { return $orig_call });" as Expr, orig_call: Expr = expr.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ use swc_core::{
|
||||
common::DUMMY_SP,
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{visit_mut_pass, VisitMut},
|
||||
visit::{VisitMut, visit_mut_pass},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
use std::{cell::RefCell, mem::take, rc::Rc};
|
||||
|
||||
use easy_error::{bail, Error};
|
||||
use easy_error::{Error, bail};
|
||||
use rustc_hash::FxHashSet;
|
||||
use swc_core::{
|
||||
atoms::{atom, Atom},
|
||||
atoms::{Atom, atom},
|
||||
common::{
|
||||
DUMMY_SP,
|
||||
errors::HANDLER,
|
||||
pass::{Repeat, Repeated},
|
||||
DUMMY_SP,
|
||||
},
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith},
|
||||
visit::{VisitMut, VisitMutWith, noop_visit_mut_type, visit_mut_pass},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -131,10 +131,10 @@ impl VisitMut for Analyzer<'_> {
|
||||
}
|
||||
|
||||
fn visit_mut_export_named_specifier(&mut self, s: &mut ExportNamedSpecifier) {
|
||||
if let ModuleExportName::Ident(id) = &s.orig {
|
||||
if !SSG_EXPORTS.contains(&&*id.sym) {
|
||||
self.add_ref(id.to_id());
|
||||
}
|
||||
if let ModuleExportName::Ident(id) = &s.orig
|
||||
&& !SSG_EXPORTS.contains(&&*id.sym)
|
||||
{
|
||||
self.add_ref(id.to_id());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,10 +145,10 @@ impl VisitMut for Analyzer<'_> {
|
||||
}
|
||||
|
||||
for decl in &d.decls {
|
||||
if let Pat::Ident(id) = &decl.name {
|
||||
if !SSG_EXPORTS.contains(&&*id.id.sym) {
|
||||
self.add_ref(id.to_id());
|
||||
}
|
||||
if let Pat::Ident(id) = &decl.name
|
||||
&& !SSG_EXPORTS.contains(&&*id.id.sym)
|
||||
{
|
||||
self.add_ref(id.to_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -240,10 +240,10 @@ impl VisitMut for Analyzer<'_> {
|
||||
match &e.decl {
|
||||
Decl::Fn(f) => {
|
||||
// Drop getStaticProps.
|
||||
if let Ok(is_data_identifier) = self.state.is_data_identifier(&f.ident) {
|
||||
if is_data_identifier {
|
||||
*s = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
||||
}
|
||||
if let Ok(is_data_identifier) = self.state.is_data_identifier(&f.ident)
|
||||
&& is_data_identifier
|
||||
{
|
||||
*s = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -468,18 +468,17 @@ impl VisitMut for NextSsg {
|
||||
| ModuleDecl::ExportDefaultDecl(..)
|
||||
| ModuleDecl::ExportDefaultExpr(..),
|
||||
) = &item
|
||||
&& let Some(var) = var.take()
|
||||
{
|
||||
if let Some(var) = var.take() {
|
||||
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
|
||||
span: DUMMY_SP,
|
||||
decl: Decl::Var(Box::new(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
decl: Decl::Var(Box::new(VarDecl {
|
||||
span: DUMMY_SP,
|
||||
kind: VarDeclKind::Var,
|
||||
decls: vec![var],
|
||||
..Default::default()
|
||||
})),
|
||||
})))
|
||||
}
|
||||
kind: VarDeclKind::Var,
|
||||
decls: vec![var],
|
||||
..Default::default()
|
||||
})),
|
||||
})))
|
||||
}
|
||||
|
||||
new.push(item);
|
||||
@@ -599,12 +598,12 @@ impl VisitMut for NextSsg {
|
||||
|
||||
#[allow(clippy::single_match)]
|
||||
fn visit_mut_stmt(&mut self, s: &mut Stmt) {
|
||||
if let Stmt::Decl(Decl::Fn(f)) = s {
|
||||
if self.should_remove(f.ident.to_id()) {
|
||||
self.mark_as_candidate(&mut f.function);
|
||||
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
||||
return;
|
||||
}
|
||||
if let Stmt::Decl(Decl::Fn(f)) = s
|
||||
&& self.should_remove(f.ident.to_id())
|
||||
{
|
||||
self.mark_as_candidate(&mut f.function);
|
||||
*s = Stmt::Empty(EmptyStmt { span: DUMMY_SP });
|
||||
return;
|
||||
}
|
||||
|
||||
s.visit_mut_children_with(self);
|
||||
|
||||
@@ -2,12 +2,12 @@ use std::collections::HashMap;
|
||||
|
||||
use serde::Deserialize;
|
||||
use swc_core::{
|
||||
atoms::{atom, Atom, Wtf8Atom},
|
||||
atoms::{Atom, Wtf8Atom, atom},
|
||||
common::DUMMY_SP,
|
||||
ecma::{
|
||||
ast::*,
|
||||
utils::private_ident,
|
||||
visit::{fold_pass, Fold},
|
||||
visit::{Fold, fold_pass},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use swc_core::{
|
||||
common::DUMMY_SP,
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{fold_pass, Fold, FoldWith},
|
||||
visit::{Fold, FoldWith, fold_pass},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -139,31 +139,30 @@ impl Fold for OptimizeServerReact {
|
||||
if let Expr::Call(call) = &expr {
|
||||
if let Callee::Expr(box Expr::Ident(f)) = &call.callee {
|
||||
// Mark `useEffect` as DCE'able
|
||||
if let Some(use_effect_ident) = &self.use_effect_ident {
|
||||
if &f.to_id() == use_effect_ident && !effect_has_side_effect_deps(call) {
|
||||
// return Expr::Lit(Lit::Null(Null { span: DUMMY_SP }));
|
||||
return wrap_expr_with_env_prod_condition(call.clone());
|
||||
}
|
||||
if let Some(use_effect_ident) = &self.use_effect_ident
|
||||
&& &f.to_id() == use_effect_ident
|
||||
&& !effect_has_side_effect_deps(call)
|
||||
{
|
||||
// return Expr::Lit(Lit::Null(Null { span: DUMMY_SP }));
|
||||
return wrap_expr_with_env_prod_condition(call.clone());
|
||||
}
|
||||
// Mark `useLayoutEffect` as DCE'able
|
||||
if let Some(use_layout_effect_ident) = &self.use_layout_effect_ident {
|
||||
if &f.to_id() == use_layout_effect_ident && !effect_has_side_effect_deps(call) {
|
||||
return wrap_expr_with_env_prod_condition(call.clone());
|
||||
}
|
||||
if let Some(use_layout_effect_ident) = &self.use_layout_effect_ident
|
||||
&& &f.to_id() == use_layout_effect_ident
|
||||
&& !effect_has_side_effect_deps(call)
|
||||
{
|
||||
return wrap_expr_with_env_prod_condition(call.clone());
|
||||
}
|
||||
} else if let Some(react_ident) = &self.react_ident {
|
||||
if let Callee::Expr(box Expr::Member(member)) = &call.callee {
|
||||
if let box Expr::Ident(f) = &member.obj {
|
||||
if &f.to_id() == react_ident {
|
||||
if let MemberProp::Ident(i) = &member.prop {
|
||||
// Mark `React.useEffect` and `React.useLayoutEffect` as DCE'able
|
||||
// calls in production
|
||||
if i.sym == "useEffect" || i.sym == "useLayoutEffect" {
|
||||
return wrap_expr_with_env_prod_condition(call.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if let Some(react_ident) = &self.react_ident
|
||||
&& let Callee::Expr(box Expr::Member(member)) = &call.callee
|
||||
&& let box Expr::Ident(f) = &member.obj
|
||||
&& &f.to_id() == react_ident
|
||||
&& let MemberProp::Ident(i) = &member.prop
|
||||
{
|
||||
// Mark `React.useEffect` and `React.useLayoutEffect` as DCE'able
|
||||
// calls in production
|
||||
if i.sym == "useEffect" || i.sym == "useLayoutEffect" {
|
||||
return wrap_expr_with_env_prod_condition(call.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,53 +177,48 @@ impl Fold for OptimizeServerReact {
|
||||
return decl;
|
||||
}
|
||||
|
||||
if let Pat::Array(array_pat) = &decl.name {
|
||||
if array_pat.elems.len() == 2 {
|
||||
if let Some(box Expr::Call(call)) = &decl.init {
|
||||
if let Callee::Expr(box Expr::Ident(f)) = &call.callee {
|
||||
if let Some(use_state_ident) = &self.use_state_ident {
|
||||
if &f.to_id() == use_state_ident && call.args.len() == 1 {
|
||||
// We do the optimization only if the arg is a literal or a
|
||||
// type that we can
|
||||
// be sure is not a function (e.g. {} or [] lit).
|
||||
// This is because useState allows a function as the
|
||||
// initialiser.
|
||||
match &call.args[0].expr {
|
||||
box Expr::Lit(_) | box Expr::Object(_) | box Expr::Array(_) => {
|
||||
// const [state, setState] = [x, () => {}];
|
||||
return VarDeclarator {
|
||||
definite: false,
|
||||
name: decl.name.clone(),
|
||||
init: Some(Box::new(Expr::Array(ArrayLit {
|
||||
elems: vec![
|
||||
Some(call.args[0].expr.clone().into()),
|
||||
Some(
|
||||
Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
body: Box::new(BlockStmtOrExpr::Expr(
|
||||
Box::new(Expr::Lit(Lit::Null(
|
||||
Null { span: DUMMY_SP },
|
||||
))),
|
||||
)),
|
||||
is_async: false,
|
||||
is_generator: false,
|
||||
params: vec![],
|
||||
..Default::default()
|
||||
})
|
||||
.into(),
|
||||
),
|
||||
],
|
||||
span: DUMMY_SP,
|
||||
}))),
|
||||
span: DUMMY_SP,
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Pat::Array(array_pat) = &decl.name
|
||||
&& array_pat.elems.len() == 2
|
||||
&& let Some(box Expr::Call(call)) = &decl.init
|
||||
&& let Callee::Expr(box Expr::Ident(f)) = &call.callee
|
||||
&& let Some(use_state_ident) = &self.use_state_ident
|
||||
&& &f.to_id() == use_state_ident
|
||||
&& call.args.len() == 1
|
||||
{
|
||||
// We do the optimization only if the arg is a literal or a
|
||||
// type that we can
|
||||
// be sure is not a function (e.g. {} or [] lit).
|
||||
// This is because useState allows a function as the
|
||||
// initialiser.
|
||||
match &call.args[0].expr {
|
||||
box Expr::Lit(_) | box Expr::Object(_) | box Expr::Array(_) => {
|
||||
// const [state, setState] = [x, () => {}];
|
||||
return VarDeclarator {
|
||||
definite: false,
|
||||
name: decl.name.clone(),
|
||||
init: Some(Box::new(Expr::Array(ArrayLit {
|
||||
elems: vec![
|
||||
Some(call.args[0].expr.clone().into()),
|
||||
Some(
|
||||
Expr::Arrow(ArrowExpr {
|
||||
span: DUMMY_SP,
|
||||
body: Box::new(BlockStmtOrExpr::Expr(Box::new(Expr::Lit(
|
||||
Lit::Null(Null { span: DUMMY_SP }),
|
||||
)))),
|
||||
is_async: false,
|
||||
is_generator: false,
|
||||
params: vec![],
|
||||
..Default::default()
|
||||
})
|
||||
.into(),
|
||||
),
|
||||
],
|
||||
span: DUMMY_SP,
|
||||
}))),
|
||||
span: DUMMY_SP,
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use chrono::Utc;
|
||||
use swc_core::{
|
||||
common::{errors::HANDLER, Span, DUMMY_SP},
|
||||
common::{DUMMY_SP, Span, errors::HANDLER},
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{fold_pass, Fold, FoldWith},
|
||||
visit::{Fold, FoldWith, fold_pass},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -68,10 +68,10 @@ impl Fold for PageConfig {
|
||||
if let Decl::Var(var_decl) = &export.decl {
|
||||
for decl in &var_decl.decls {
|
||||
let mut is_config = false;
|
||||
if let Pat::Ident(ident) = &decl.name {
|
||||
if ident.id.sym == CONFIG_KEY {
|
||||
is_config = true;
|
||||
}
|
||||
if let Pat::Ident(ident) = &decl.name
|
||||
&& ident.id.sym == CONFIG_KEY
|
||||
{
|
||||
is_config = true;
|
||||
}
|
||||
|
||||
if is_config {
|
||||
@@ -120,17 +120,17 @@ impl Fold for PageConfig {
|
||||
) -> ExportNamedSpecifier {
|
||||
match &specifier.exported {
|
||||
Some(ident) => {
|
||||
if let ModuleExportName::Ident(ident) = ident {
|
||||
if ident.sym == CONFIG_KEY {
|
||||
self.handle_error("Config cannot be re-exported.", specifier.span)
|
||||
}
|
||||
if let ModuleExportName::Ident(ident) = ident
|
||||
&& ident.sym == CONFIG_KEY
|
||||
{
|
||||
self.handle_error("Config cannot be re-exported.", specifier.span)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
if let ModuleExportName::Ident(ident) = &specifier.orig {
|
||||
if ident.sym == CONFIG_KEY {
|
||||
self.handle_error("Config cannot be re-exported.", specifier.span)
|
||||
}
|
||||
if let ModuleExportName::Ident(ident) = &specifier.orig
|
||||
&& ident.sym == CONFIG_KEY
|
||||
{
|
||||
self.handle_error("Config cannot be re-exported.", specifier.span)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use swc_core::{
|
||||
common::{comments::Comments, errors::HANDLER, util::take::Take, Span, Spanned, DUMMY_SP},
|
||||
common::{DUMMY_SP, Span, Spanned, comments::Comments, errors::HANDLER, util::take::Take},
|
||||
ecma::{
|
||||
ast::{CallExpr, Callee, EmptyStmt, Expr, Module, ModuleDecl, ModuleItem, Stmt},
|
||||
visit::{noop_visit_mut_type, VisitMut, VisitMutWith},
|
||||
visit::{VisitMut, VisitMutWith, noop_visit_mut_type},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -74,11 +74,11 @@ where
|
||||
}
|
||||
|
||||
fn visit_mut_module_item(&mut self, m: &mut ModuleItem) {
|
||||
if let ModuleItem::ModuleDecl(ModuleDecl::Import(import)) = m {
|
||||
if import.src.value == MODULE {
|
||||
*m = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
||||
return;
|
||||
}
|
||||
if let ModuleItem::ModuleDecl(ModuleDecl::Import(import)) = m
|
||||
&& import.src.value == MODULE
|
||||
{
|
||||
*m = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
||||
return;
|
||||
}
|
||||
|
||||
m.visit_mut_children_with(self);
|
||||
|
||||
@@ -11,19 +11,19 @@ use regex::Regex;
|
||||
use rustc_hash::FxHashMap;
|
||||
use serde::Deserialize;
|
||||
use swc_core::{
|
||||
atoms::{atom, Atom, Wtf8Atom},
|
||||
atoms::{Atom, Wtf8Atom, atom},
|
||||
common::{
|
||||
DUMMY_SP, FileName, Span, Spanned,
|
||||
comments::{Comment, CommentKind, Comments},
|
||||
errors::HANDLER,
|
||||
util::take::Take,
|
||||
FileName, Span, Spanned, DUMMY_SP,
|
||||
},
|
||||
ecma::{
|
||||
ast::*,
|
||||
utils::{prepend_stmts, quote_ident, quote_str, ExprFactory},
|
||||
utils::{ExprFactory, prepend_stmts, quote_ident, quote_str},
|
||||
visit::{
|
||||
noop_visit_mut_type, noop_visit_type, visit_mut_pass, Visit, VisitMut, VisitMutWith,
|
||||
VisitWith,
|
||||
Visit, VisitMut, VisitMutWith, VisitWith, noop_visit_mut_type, noop_visit_type,
|
||||
visit_mut_pass,
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -162,15 +162,13 @@ impl<C: Comments> ReactServerComponents<C> {
|
||||
/// removes specific directive from the AST.
|
||||
fn remove_top_level_directive(&mut self, module: &mut Module) {
|
||||
module.body.retain(|item| {
|
||||
if let ModuleItem::Stmt(stmt) = item {
|
||||
if let Some(expr_stmt) = stmt.as_expr() {
|
||||
if let Expr::Lit(Lit::Str(Str { value, .. })) = &*expr_stmt.expr {
|
||||
if &**value == "use client" {
|
||||
// Remove the directive.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let ModuleItem::Stmt(stmt) = item
|
||||
&& let Some(expr_stmt) = stmt.as_expr()
|
||||
&& let Expr::Lit(Lit::Str(Str { value, .. })) = &*expr_stmt.expr
|
||||
&& &**value == "use client"
|
||||
{
|
||||
// Remove the directive.
|
||||
return false;
|
||||
}
|
||||
true
|
||||
});
|
||||
@@ -454,14 +452,14 @@ fn collect_module_info(
|
||||
// an exception because they are not valid directives.
|
||||
Expr::Paren(ParenExpr { expr, .. }) => {
|
||||
finished_directives = true;
|
||||
if let Expr::Lit(Lit::Str(Str { value, .. })) = &**expr {
|
||||
if &**value == "use client" {
|
||||
report_error(
|
||||
app_dir,
|
||||
filepath,
|
||||
RSCErrorKind::NextRscErrClientDirective(expr_stmt.span),
|
||||
);
|
||||
}
|
||||
if let Expr::Lit(Lit::Str(Str { value, .. })) = &**expr
|
||||
&& &**value == "use client"
|
||||
{
|
||||
report_error(
|
||||
app_dir,
|
||||
filepath,
|
||||
RSCErrorKind::NextRscErrClientDirective(expr_stmt.span),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
@@ -825,24 +823,22 @@ impl ReactServerComponentValidator {
|
||||
|
||||
let is_error_file = RE.is_match(&self.filepath);
|
||||
|
||||
if is_error_file {
|
||||
if let Some(app_dir) = &self.app_dir {
|
||||
if let Some(app_dir) = app_dir.to_str() {
|
||||
if self.filepath.starts_with(app_dir) {
|
||||
let span = if let Some(first_item) = module.body.first() {
|
||||
first_item.span()
|
||||
} else {
|
||||
module.span
|
||||
};
|
||||
if is_error_file
|
||||
&& let Some(app_dir) = &self.app_dir
|
||||
&& let Some(app_dir) = app_dir.to_str()
|
||||
&& self.filepath.starts_with(app_dir)
|
||||
{
|
||||
let span = if let Some(first_item) = module.body.first() {
|
||||
first_item.span()
|
||||
} else {
|
||||
module.span
|
||||
};
|
||||
|
||||
report_error(
|
||||
&self.app_dir,
|
||||
&self.filepath,
|
||||
RSCErrorKind::NextRscErrErrorFileServerComponent(span),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
report_error(
|
||||
&self.app_dir,
|
||||
&self.filepath,
|
||||
RSCErrorKind::NextRscErrErrorFileServerComponent(span),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::{hash_map, BTreeMap},
|
||||
collections::{BTreeMap, hash_map},
|
||||
convert::{TryFrom, TryInto},
|
||||
mem::{replace, take},
|
||||
path::{Path, PathBuf},
|
||||
@@ -16,23 +16,23 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use serde::Deserialize;
|
||||
use sha1::{Digest, Sha1};
|
||||
use swc_core::{
|
||||
atoms::{atom, Atom, Wtf8Atom},
|
||||
atoms::{Atom, Wtf8Atom, atom},
|
||||
common::{
|
||||
BytePos, DUMMY_SP, FileName, Mark, SourceMap, Span, SyntaxContext,
|
||||
comments::{Comment, CommentKind, Comments, SingleThreadedComments},
|
||||
errors::HANDLER,
|
||||
source_map::{SourceMapGenConfig, PURE_SP},
|
||||
source_map::{PURE_SP, SourceMapGenConfig},
|
||||
util::take::Take,
|
||||
BytePos, FileName, Mark, SourceMap, Span, SyntaxContext, DUMMY_SP,
|
||||
},
|
||||
ecma::{
|
||||
ast::*,
|
||||
codegen::{self, text_writer::JsWriter, Emitter},
|
||||
utils::{private_ident, quote_ident, ExprFactory},
|
||||
visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith},
|
||||
codegen::{self, Emitter, text_writer::JsWriter},
|
||||
utils::{ExprFactory, private_ident, quote_ident},
|
||||
visit::{VisitMut, VisitMutWith, noop_visit_mut_type, visit_mut_pass},
|
||||
},
|
||||
quote,
|
||||
};
|
||||
use turbo_rcstr::{rcstr, RcStr};
|
||||
use turbo_rcstr::{RcStr, rcstr};
|
||||
|
||||
use crate::FxIndexMap;
|
||||
|
||||
@@ -155,7 +155,7 @@ pub fn server_actions<C: Comments>(
|
||||
cm: Arc<SourceMap>,
|
||||
use_cache_telemetry_tracker: Rc<RefCell<FxHashMap<String, usize>>>,
|
||||
mode: ServerActionsMode,
|
||||
) -> impl Pass {
|
||||
) -> impl Pass + use<C> {
|
||||
visit_mut_pass(ServerActions {
|
||||
config,
|
||||
mode,
|
||||
@@ -510,11 +510,11 @@ impl<C: Comments> ServerActions<C> {
|
||||
|
||||
// If this is an exported arrow, remove it from export_name_by_local_id so the
|
||||
// post-pass doesn't register it again (it's already registered above).
|
||||
if self.current_export_name.is_some() {
|
||||
if let Some(arrow_ident) = &self.arrow_or_fn_expr_ident {
|
||||
self.export_name_by_local_id
|
||||
.swap_remove(&arrow_ident.to_id());
|
||||
}
|
||||
if self.current_export_name.is_some()
|
||||
&& let Some(arrow_ident) = &self.arrow_or_fn_expr_ident
|
||||
{
|
||||
self.export_name_by_local_id
|
||||
.swap_remove(&arrow_ident.to_id());
|
||||
}
|
||||
|
||||
if let BlockStmtOrExpr::BlockStmt(block) = &mut *arrow.body {
|
||||
@@ -677,10 +677,10 @@ impl<C: Comments> ServerActions<C> {
|
||||
|
||||
// If this is an exported function, remove it from export_name_by_local_id so the
|
||||
// post-pass doesn't register it again (it's already registered above).
|
||||
if self.current_export_name.is_some() {
|
||||
if let Some(ref fn_name) = fn_name {
|
||||
self.export_name_by_local_id.swap_remove(&fn_name.to_id());
|
||||
}
|
||||
if self.current_export_name.is_some()
|
||||
&& let Some(ref fn_name) = fn_name
|
||||
{
|
||||
self.export_name_by_local_id.swap_remove(&fn_name.to_id());
|
||||
}
|
||||
|
||||
function.body.visit_mut_with(&mut ClosureReplacer {
|
||||
@@ -821,11 +821,11 @@ impl<C: Comments> ServerActions<C> {
|
||||
|
||||
// If this is an exported arrow, remove it from export_name_by_local_id so the
|
||||
// post-pass doesn't register it again (it's already registered above).
|
||||
if self.current_export_name.is_some() {
|
||||
if let Some(arrow_ident) = &self.arrow_or_fn_expr_ident {
|
||||
self.export_name_by_local_id
|
||||
.swap_remove(&arrow_ident.to_id());
|
||||
}
|
||||
if self.current_export_name.is_some()
|
||||
&& let Some(arrow_ident) = &self.arrow_or_fn_expr_ident
|
||||
{
|
||||
self.export_name_by_local_id
|
||||
.swap_remove(&arrow_ident.to_id());
|
||||
}
|
||||
|
||||
if let BlockStmtOrExpr::BlockStmt(block) = &mut *arrow.body {
|
||||
@@ -926,10 +926,10 @@ impl<C: Comments> ServerActions<C> {
|
||||
|
||||
// If this is an exported function, remove it from export_name_by_local_id so the
|
||||
// post-pass doesn't register it again (it's already registered above).
|
||||
if self.current_export_name.is_some() {
|
||||
if let Some(ref fn_name) = fn_name {
|
||||
self.export_name_by_local_id.swap_remove(&fn_name.to_id());
|
||||
}
|
||||
if self.current_export_name.is_some()
|
||||
&& let Some(ref fn_name) = fn_name
|
||||
{
|
||||
self.export_name_by_local_id.swap_remove(&fn_name.to_id());
|
||||
}
|
||||
|
||||
function.body.visit_mut_with(&mut ClosureReplacer {
|
||||
@@ -1247,10 +1247,10 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
if !self.validate_async_function(f.is_async, f.span, fn_name.as_ref(), &directive) {
|
||||
// If this is an exported function that failed validation, remove it from
|
||||
// export_name_by_local_id so the post-pass doesn't register it.
|
||||
if self.current_export_name.is_some() {
|
||||
if let Some(fn_name) = fn_name {
|
||||
self.export_name_by_local_id.swap_remove(&fn_name.to_id());
|
||||
}
|
||||
if self.current_export_name.is_some()
|
||||
&& let Some(fn_name) = fn_name
|
||||
{
|
||||
self.export_name_by_local_id.swap_remove(&fn_name.to_id());
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1266,39 +1266,38 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
// client layers).
|
||||
if matches!(self.file_directive, Some(Directive::UseServer))
|
||||
&& matches!(directive, Directive::UseServer)
|
||||
&& let Some(export_name) = self.current_export_name.clone()
|
||||
{
|
||||
if let Some(export_name) = self.current_export_name.clone() {
|
||||
let params = f.params.clone();
|
||||
let span = f.span;
|
||||
let params = f.params.clone();
|
||||
let span = f.span;
|
||||
|
||||
self.register_server_action_export(
|
||||
&export_name,
|
||||
fn_name.as_ref(),
|
||||
Some(¶ms),
|
||||
span,
|
||||
&mut || {
|
||||
Box::new(Expr::Fn(FnExpr {
|
||||
ident: fn_name.clone(),
|
||||
function: Box::new(f.take()),
|
||||
}))
|
||||
},
|
||||
);
|
||||
self.register_server_action_export(
|
||||
&export_name,
|
||||
fn_name.as_ref(),
|
||||
Some(¶ms),
|
||||
span,
|
||||
&mut || {
|
||||
Box::new(Expr::Fn(FnExpr {
|
||||
ident: fn_name.clone(),
|
||||
function: Box::new(f.take()),
|
||||
}))
|
||||
},
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For the client layer, register cache exports without hoisting.
|
||||
if !self.config.is_react_server_layer {
|
||||
if matches!(directive, Directive::UseCache { .. }) {
|
||||
if let Some(export_name) = self.current_export_name.clone() {
|
||||
self.register_cache_export_on_client(
|
||||
&export_name,
|
||||
fn_name.as_ref(),
|
||||
Some(&f.params),
|
||||
f.span,
|
||||
);
|
||||
}
|
||||
if matches!(directive, Directive::UseCache { .. })
|
||||
&& let Some(export_name) = self.current_export_name.clone()
|
||||
{
|
||||
self.register_cache_export_on_client(
|
||||
&export_name,
|
||||
fn_name.as_ref(),
|
||||
Some(&f.params),
|
||||
f.span,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1399,10 +1398,10 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
fn visit_mut_fn_decl(&mut self, f: &mut FnDecl) {
|
||||
let old_this_status = replace(&mut self.this_status, ThisStatus::Allowed);
|
||||
let old_current_export_name = self.current_export_name.take();
|
||||
if self.in_module_level {
|
||||
if let Some(export_name) = self.export_name_by_local_id.get(&f.ident.to_id()) {
|
||||
self.current_export_name = Some(export_name.clone());
|
||||
}
|
||||
if self.in_module_level
|
||||
&& let Some(export_name) = self.export_name_by_local_id.get(&f.ident.to_id())
|
||||
{
|
||||
self.current_export_name = Some(export_name.clone());
|
||||
}
|
||||
let old_fn_decl_ident = self.fn_decl_ident.replace(f.ident.clone());
|
||||
f.visit_mut_children_with(self);
|
||||
@@ -1460,11 +1459,11 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
if !self.validate_async_function(a.is_async, a.span, arrow_ident.as_ref(), &directive) {
|
||||
// If this is an exported arrow function that failed validation, remove it from
|
||||
// export_name_by_local_id so the post-pass doesn't register it.
|
||||
if self.current_export_name.is_some() {
|
||||
if let Some(arrow_ident) = arrow_ident {
|
||||
self.export_name_by_local_id
|
||||
.swap_remove(&arrow_ident.to_id());
|
||||
}
|
||||
if self.current_export_name.is_some()
|
||||
&& let Some(arrow_ident) = arrow_ident
|
||||
{
|
||||
self.export_name_by_local_id
|
||||
.swap_remove(&arrow_ident.to_id());
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1480,37 +1479,35 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
// client layers).
|
||||
if matches!(self.file_directive, Some(Directive::UseServer))
|
||||
&& matches!(directive, Directive::UseServer)
|
||||
&& let Some(export_name) = self.current_export_name.clone()
|
||||
{
|
||||
if let Some(export_name) = self.current_export_name.clone() {
|
||||
let params: Vec<Param> =
|
||||
a.params.iter().map(|p| Param::from(p.clone())).collect();
|
||||
let params: Vec<Param> = a.params.iter().map(|p| Param::from(p.clone())).collect();
|
||||
|
||||
self.register_server_action_export(
|
||||
&export_name,
|
||||
arrow_ident.as_ref(),
|
||||
Some(¶ms),
|
||||
a.span,
|
||||
&mut || Box::new(Expr::Arrow(a.take())),
|
||||
);
|
||||
self.register_server_action_export(
|
||||
&export_name,
|
||||
arrow_ident.as_ref(),
|
||||
Some(¶ms),
|
||||
a.span,
|
||||
&mut || Box::new(Expr::Arrow(a.take())),
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// For the client layer, register cache exports without hoisting.
|
||||
if !self.config.is_react_server_layer {
|
||||
if matches!(directive, Directive::UseCache { .. }) {
|
||||
if let Some(export_name) = self.current_export_name.clone() {
|
||||
let params: Vec<Param> =
|
||||
a.params.iter().map(|p| Param::from(p.clone())).collect();
|
||||
if matches!(directive, Directive::UseCache { .. })
|
||||
&& let Some(export_name) = self.current_export_name.clone()
|
||||
{
|
||||
let params: Vec<Param> =
|
||||
a.params.iter().map(|p| Param::from(p.clone())).collect();
|
||||
|
||||
self.register_cache_export_on_client(
|
||||
&export_name,
|
||||
arrow_ident.as_ref(),
|
||||
Some(¶ms),
|
||||
a.span,
|
||||
);
|
||||
}
|
||||
self.register_cache_export_on_client(
|
||||
&export_name,
|
||||
arrow_ident.as_ref(),
|
||||
Some(¶ms),
|
||||
a.span,
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1604,14 +1601,15 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if !self.in_module_level && self.should_track_names {
|
||||
if let PropOrSpread::Prop(box Prop::Shorthand(i)) = n {
|
||||
self.names.push(Name::from(&*i));
|
||||
self.should_track_names = false;
|
||||
n.visit_mut_children_with(self);
|
||||
self.should_track_names = true;
|
||||
return;
|
||||
}
|
||||
if !self.in_module_level
|
||||
&& self.should_track_names
|
||||
&& let PropOrSpread::Prop(box Prop::Shorthand(i)) = n
|
||||
{
|
||||
self.names.push(Name::from(&*i));
|
||||
self.should_track_names = false;
|
||||
n.visit_mut_children_with(self);
|
||||
self.should_track_names = true;
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_mut_children_with(self);
|
||||
@@ -1688,17 +1686,17 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
}
|
||||
|
||||
fn visit_mut_call_expr(&mut self, n: &mut CallExpr) {
|
||||
if let Callee::Expr(box Expr::Ident(Ident { sym, .. })) = &mut n.callee {
|
||||
if sym == "jsxDEV" || sym == "_jsxDEV" {
|
||||
// Do not visit the 6th arg in a generated jsxDEV call, which is a `this`
|
||||
// expression, to avoid emitting an error for using `this` if it's
|
||||
// inside of a server function. https://github.com/facebook/react/blob/9106107/packages/react/src/jsx/ReactJSXElement.js#L429
|
||||
if n.args.len() > 4 {
|
||||
for arg in &mut n.args[0..4] {
|
||||
arg.visit_mut_with(self);
|
||||
}
|
||||
return;
|
||||
if let Callee::Expr(box Expr::Ident(Ident { sym, .. })) = &mut n.callee
|
||||
&& (sym == "jsxDEV" || sym == "_jsxDEV")
|
||||
{
|
||||
// Do not visit the 6th arg in a generated jsxDEV call, which is a `this`
|
||||
// expression, to avoid emitting an error for using `this` if it's
|
||||
// inside of a server function. https://github.com/facebook/react/blob/9106107/packages/react/src/jsx/ReactJSXElement.js#L429
|
||||
if n.args.len() > 4 {
|
||||
for arg in &mut n.args[0..4] {
|
||||
arg.visit_mut_with(self);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1714,22 +1712,23 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
}
|
||||
|
||||
fn visit_mut_expr(&mut self, n: &mut Expr) {
|
||||
if !self.in_module_level && self.should_track_names {
|
||||
if let Ok(mut name) = Name::try_from(&*n) {
|
||||
if self.in_callee {
|
||||
// This is a callee i.e. `foo.bar()`,
|
||||
// we need to track the actual value instead of the method name.
|
||||
if !name.1.is_empty() {
|
||||
name.1.pop();
|
||||
}
|
||||
if !self.in_module_level
|
||||
&& self.should_track_names
|
||||
&& let Ok(mut name) = Name::try_from(&*n)
|
||||
{
|
||||
if self.in_callee {
|
||||
// This is a callee i.e. `foo.bar()`,
|
||||
// we need to track the actual value instead of the method name.
|
||||
if !name.1.is_empty() {
|
||||
name.1.pop();
|
||||
}
|
||||
|
||||
self.names.push(name);
|
||||
self.should_track_names = false;
|
||||
n.visit_mut_children_with(self);
|
||||
self.should_track_names = true;
|
||||
return;
|
||||
}
|
||||
|
||||
self.names.push(name);
|
||||
self.should_track_names = false;
|
||||
n.visit_mut_children_with(self);
|
||||
self.should_track_names = true;
|
||||
return;
|
||||
}
|
||||
|
||||
self.rewrite_expr_to_proxy_expr = None;
|
||||
@@ -1766,13 +1765,13 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultDecl(export_default_decl)) => {
|
||||
// export default function foo() {}
|
||||
if let DefaultDecl::Fn(f) = &export_default_decl.decl {
|
||||
if let Some(ident) = &f.ident {
|
||||
self.export_name_by_local_id.insert(
|
||||
ident.to_id(),
|
||||
ModuleExportName::Ident(atom!("default").into()),
|
||||
);
|
||||
}
|
||||
if let DefaultDecl::Fn(f) = &export_default_decl.decl
|
||||
&& let Some(ident) = &f.ident
|
||||
{
|
||||
self.export_name_by_local_id.insert(
|
||||
ident.to_id(),
|
||||
ModuleExportName::Ident(atom!("default").into()),
|
||||
);
|
||||
}
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(export_decl)) => {
|
||||
@@ -1853,13 +1852,12 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
ModuleItem::Stmt(Stmt::Decl(Decl::Var(var_decl))) => {
|
||||
// Track which declarations need cache runtime wrappers if exported.
|
||||
for decl in &var_decl.decls {
|
||||
if let Pat::Ident(ident_pat) = &decl.name {
|
||||
if let Some(init) = &decl.init {
|
||||
if may_need_cache_runtime_wrapper(init) {
|
||||
self.local_ids_that_need_cache_runtime_wrapper_if_exported
|
||||
.insert(ident_pat.id.to_id());
|
||||
}
|
||||
}
|
||||
if let Pat::Ident(ident_pat) = &decl.name
|
||||
&& let Some(init) = &decl.init
|
||||
&& may_need_cache_runtime_wrapper(init)
|
||||
{
|
||||
self.local_ids_that_need_cache_runtime_wrapper_if_exported
|
||||
.insert(ident_pat.id.to_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1910,17 +1908,17 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
let mut has_export_needing_wrapper = false;
|
||||
|
||||
for decl in &var.decls {
|
||||
if let Pat::Ident(_) = &decl.name {
|
||||
if let Some(init) = &decl.init {
|
||||
// Disallow exporting literals. Admittedly, this is
|
||||
// pretty arbitrary. We don't disallow exporting object
|
||||
// and array literals, as that would be too restrictive,
|
||||
// especially for page and layout files with
|
||||
// 'use cache', that may want to export metadata or
|
||||
// viewport objects.
|
||||
if let Expr::Lit(_) = &**init {
|
||||
disallowed_export_span = *span;
|
||||
}
|
||||
if let Pat::Ident(_) = &decl.name
|
||||
&& let Some(init) = &decl.init
|
||||
{
|
||||
// Disallow exporting literals. Admittedly, this is
|
||||
// pretty arbitrary. We don't disallow exporting object
|
||||
// and array literals, as that would be too restrictive,
|
||||
// especially for page and layout files with
|
||||
// 'use cache', that may want to export metadata or
|
||||
// viewport objects.
|
||||
if let Expr::Lit(_) = &**init {
|
||||
disallowed_export_span = *span;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2857,10 +2855,10 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
if let (Pat::Ident(ident), Some(box Expr::Arrow(_) | box Expr::Fn(_))) =
|
||||
(&var_declarator.name, &var_declarator.init)
|
||||
{
|
||||
if self.in_module_level {
|
||||
if let Some(export_name) = self.export_name_by_local_id.get(&ident.to_id()) {
|
||||
self.current_export_name = Some(export_name.clone());
|
||||
}
|
||||
if self.in_module_level
|
||||
&& let Some(export_name) = self.export_name_by_local_id.get(&ident.to_id())
|
||||
{
|
||||
self.current_export_name = Some(export_name.clone());
|
||||
}
|
||||
|
||||
self.arrow_or_fn_expr_ident = Some(ident.id.clone());
|
||||
@@ -2908,14 +2906,14 @@ impl<C: Comments> VisitMut for ServerActions<C> {
|
||||
}
|
||||
|
||||
fn visit_mut_ident(&mut self, n: &mut Ident) {
|
||||
if n.sym == *"arguments" {
|
||||
if let ThisStatus::Forbidden { directive } = &self.this_status {
|
||||
emit_error(ServerActionsErrorKind::ForbiddenExpression {
|
||||
span: n.span,
|
||||
expr: "arguments".into(),
|
||||
directive: directive.clone(),
|
||||
});
|
||||
}
|
||||
if n.sym == *"arguments"
|
||||
&& let ThisStatus::Forbidden { directive } = &self.this_status
|
||||
{
|
||||
emit_error(ServerActionsErrorKind::ForbiddenExpression {
|
||||
span: n.span,
|
||||
expr: "arguments".into(),
|
||||
directive: directive.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,9 @@ use swc_core::{
|
||||
common::Mark,
|
||||
ecma::{
|
||||
ast::*,
|
||||
atoms::{atom, Atom},
|
||||
transforms::optimization::simplify::dce::{dce, Config as DCEConfig},
|
||||
visit::{fold_pass, Fold, FoldWith, VisitMutWith},
|
||||
atoms::{Atom, atom},
|
||||
transforms::optimization::simplify::dce::{Config as DCEConfig, dce},
|
||||
visit::{Fold, FoldWith, VisitMutWith, fold_pass},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -63,10 +63,10 @@ impl Fold for ExportShaker {
|
||||
.decls
|
||||
.iter()
|
||||
.filter_map(|var_decl| {
|
||||
if let Pat::Ident(BindingIdent { id, .. }) = &var_decl.name {
|
||||
if self.ignore.contains(&id.sym) {
|
||||
return Some(var_decl.to_owned());
|
||||
}
|
||||
if let Pat::Ident(BindingIdent { id, .. }) = &var_decl.name
|
||||
&& self.ignore.contains(&id.sym)
|
||||
{
|
||||
return Some(var_decl.to_owned());
|
||||
}
|
||||
None
|
||||
})
|
||||
@@ -87,15 +87,15 @@ impl Fold for ExportShaker {
|
||||
.filter_map(|spec| {
|
||||
if let ExportSpecifier::Named(named_spec) = spec {
|
||||
if let Some(ident) = &named_spec.exported {
|
||||
if let ModuleExportName::Ident(ident) = ident {
|
||||
if self.ignore.contains(&ident.sym) {
|
||||
return Some(ExportSpecifier::Named(named_spec));
|
||||
}
|
||||
}
|
||||
} else if let ModuleExportName::Ident(ident) = &named_spec.orig {
|
||||
if self.ignore.contains(&ident.sym) {
|
||||
if let ModuleExportName::Ident(ident) = ident
|
||||
&& self.ignore.contains(&ident.sym)
|
||||
{
|
||||
return Some(ExportSpecifier::Named(named_spec));
|
||||
}
|
||||
} else if let ModuleExportName::Ident(ident) = &named_spec.orig
|
||||
&& self.ignore.contains(&ident.sym)
|
||||
{
|
||||
return Some(ExportSpecifier::Named(named_spec));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
||||
@@ -9,13 +9,13 @@ use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use swc_core::{
|
||||
atoms::Atom,
|
||||
common::{
|
||||
DUMMY_SP,
|
||||
errors::HANDLER,
|
||||
pass::{Repeat, Repeated},
|
||||
DUMMY_SP,
|
||||
},
|
||||
ecma::{
|
||||
ast::*,
|
||||
visit::{fold_pass, noop_fold_type, noop_visit_type, Fold, FoldWith, Visit, VisitWith},
|
||||
visit::{Fold, FoldWith, Visit, VisitWith, fold_pass, noop_fold_type, noop_visit_type},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -347,10 +347,10 @@ impl Visit for Analyzer<'_> {
|
||||
self.state
|
||||
.encounter_export(exported_ident, local_ident, export_type);
|
||||
|
||||
if let Some(local_ident) = local_ident {
|
||||
if self.state.should_retain_export_type(export_type) {
|
||||
self.add_ref(local_ident.to_id());
|
||||
}
|
||||
if let Some(local_ident) = local_ident
|
||||
&& self.state.should_retain_export_type(export_type)
|
||||
{
|
||||
self.add_ref(local_ident.to_id());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -793,13 +793,13 @@ impl Fold for NextSsg {
|
||||
}
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(e)) => match &e.decl {
|
||||
Decl::Fn(f) => {
|
||||
if let Some(export_type) = self.state.export_type(&f.ident.to_id()) {
|
||||
if self.state.dropping_export(export_type) {
|
||||
tracing::trace!(
|
||||
"Dropping an export specifier because it's an SSR/SSG function"
|
||||
);
|
||||
return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
||||
}
|
||||
if let Some(export_type) = self.state.export_type(&f.ident.to_id())
|
||||
&& self.state.dropping_export(export_type)
|
||||
{
|
||||
tracing::trace!(
|
||||
"Dropping an export specifier because it's an SSR/SSG function"
|
||||
);
|
||||
return ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -950,20 +950,19 @@ impl Fold for NextSsg {
|
||||
}
|
||||
}
|
||||
Pat::Expr(expr) => {
|
||||
if let Expr::Member(member_expr) = &**expr {
|
||||
if let Some(id) = find_member_root_id(member_expr) {
|
||||
if self.should_remove(&id) {
|
||||
self.state.should_run_again = true;
|
||||
tracing::trace!(
|
||||
"Dropping member expression object `{}{:?}` because it should \
|
||||
be removed",
|
||||
id.0,
|
||||
id.1
|
||||
);
|
||||
if let Expr::Member(member_expr) = &**expr
|
||||
&& let Some(id) = find_member_root_id(member_expr)
|
||||
&& self.should_remove(&id)
|
||||
{
|
||||
self.state.should_run_again = true;
|
||||
tracing::trace!(
|
||||
"Dropping member expression object `{}{:?}` because it should be \
|
||||
removed",
|
||||
id.0,
|
||||
id.1
|
||||
);
|
||||
|
||||
return Pat::Invalid(Invalid { span: DUMMY_SP });
|
||||
}
|
||||
}
|
||||
return Pat::Invalid(Invalid { span: DUMMY_SP });
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
@@ -976,32 +975,31 @@ impl Fold for NextSsg {
|
||||
fn fold_simple_assign_target(&mut self, mut n: SimpleAssignTarget) -> SimpleAssignTarget {
|
||||
n = n.fold_children_with(self);
|
||||
|
||||
if let SimpleAssignTarget::Ident(name) = &n {
|
||||
if self.should_remove(&name.id.to_id()) {
|
||||
self.state.should_run_again = true;
|
||||
tracing::trace!(
|
||||
"Dropping var `{}{:?}` because it should be removed",
|
||||
name.id.sym,
|
||||
name.id.ctxt
|
||||
);
|
||||
if let SimpleAssignTarget::Ident(name) = &n
|
||||
&& self.should_remove(&name.id.to_id())
|
||||
{
|
||||
self.state.should_run_again = true;
|
||||
tracing::trace!(
|
||||
"Dropping var `{}{:?}` because it should be removed",
|
||||
name.id.sym,
|
||||
name.id.ctxt
|
||||
);
|
||||
|
||||
return SimpleAssignTarget::Invalid(Invalid { span: DUMMY_SP });
|
||||
}
|
||||
return SimpleAssignTarget::Invalid(Invalid { span: DUMMY_SP });
|
||||
}
|
||||
|
||||
if let SimpleAssignTarget::Member(member_expr) = &n {
|
||||
if let Some(id) = find_member_root_id(member_expr) {
|
||||
if self.should_remove(&id) {
|
||||
self.state.should_run_again = true;
|
||||
tracing::trace!(
|
||||
"Dropping member expression object `{}{:?}` because it should be removed",
|
||||
id.0,
|
||||
id.1
|
||||
);
|
||||
if let SimpleAssignTarget::Member(member_expr) = &n
|
||||
&& let Some(id) = find_member_root_id(member_expr)
|
||||
&& self.should_remove(&id)
|
||||
{
|
||||
self.state.should_run_again = true;
|
||||
tracing::trace!(
|
||||
"Dropping member expression object `{}{:?}` because it should be removed",
|
||||
id.0,
|
||||
id.1
|
||||
);
|
||||
|
||||
return SimpleAssignTarget::Invalid(Invalid { span: DUMMY_SP });
|
||||
}
|
||||
}
|
||||
return SimpleAssignTarget::Invalid(Invalid { span: DUMMY_SP });
|
||||
}
|
||||
|
||||
n
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_core::{
|
||||
common::{
|
||||
BytePos, DUMMY_SP, Mark, Span, Spanned, SyntaxContext,
|
||||
comments::{Comment, CommentKind, Comments},
|
||||
source_map::PURE_SP,
|
||||
util::take::Take,
|
||||
BytePos, Mark, Span, Spanned, SyntaxContext, DUMMY_SP,
|
||||
},
|
||||
ecma::{
|
||||
ast::*,
|
||||
utils::{prepend_stmt, private_ident, quote_ident, quote_str},
|
||||
visit::{noop_visit_mut_type, visit_mut_pass, VisitMut, VisitMutWith},
|
||||
visit::{VisitMut, VisitMutWith, noop_visit_mut_type, visit_mut_pass},
|
||||
},
|
||||
quote,
|
||||
};
|
||||
@@ -129,14 +129,12 @@ impl<C: Comments> VisitMut for ImportReplacer<C> {
|
||||
//
|
||||
// Only extract names when `await` is present — without await, the
|
||||
// destructuring targets the Promise, not the module namespace.
|
||||
if let Some(init) = &decl.init {
|
||||
if let Some(import_span) = find_awaited_import_call_span(init) {
|
||||
if let Pat::Object(obj_pat) = &decl.name {
|
||||
if let Some(names) = extract_export_names_from_pat(obj_pat) {
|
||||
self.import_export_names.insert(import_span.lo, names);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(init) = &decl.init
|
||||
&& let Some(import_span) = find_awaited_import_call_span(init)
|
||||
&& let Pat::Object(obj_pat) = &decl.name
|
||||
&& let Some(names) = extract_export_names_from_pat(obj_pat)
|
||||
{
|
||||
self.import_export_names.insert(import_span.lo, names);
|
||||
}
|
||||
|
||||
decl.visit_mut_children_with(self);
|
||||
@@ -158,24 +156,24 @@ impl<C: Comments> VisitMut for ImportReplacer<C> {
|
||||
self.has_dynamic_import = true;
|
||||
|
||||
// Add /* webpackExports: [...] */ comment if we detected destructuring
|
||||
if let Some(names) = self.import_export_names.remove(&call_expr.span.lo) {
|
||||
if let Some(first_arg) = call_expr.args.first() {
|
||||
let comment_text = if names.is_empty() {
|
||||
" webpackExports: [] ".to_string()
|
||||
} else {
|
||||
let names_json: Vec<String> =
|
||||
names.iter().map(|n| format!("\"{}\"", n)).collect();
|
||||
format!(" webpackExports: [{}] ", names_json.join(", "))
|
||||
};
|
||||
self.comments.add_leading(
|
||||
first_arg.span_lo(),
|
||||
Comment {
|
||||
span: DUMMY_SP,
|
||||
kind: CommentKind::Block,
|
||||
text: comment_text.into(),
|
||||
},
|
||||
);
|
||||
}
|
||||
if let Some(names) = self.import_export_names.remove(&call_expr.span.lo)
|
||||
&& let Some(first_arg) = call_expr.args.first()
|
||||
{
|
||||
let comment_text = if names.is_empty() {
|
||||
" webpackExports: [] ".to_string()
|
||||
} else {
|
||||
let names_json: Vec<String> =
|
||||
names.iter().map(|n| format!("\"{}\"", n)).collect();
|
||||
format!(" webpackExports: [{}] ", names_json.join(", "))
|
||||
};
|
||||
self.comments.add_leading(
|
||||
first_arg.span_lo(),
|
||||
Comment {
|
||||
span: DUMMY_SP,
|
||||
kind: CommentKind::Block,
|
||||
text: comment_text.into(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
let replacement_expr = quote!(
|
||||
|
||||
@@ -2,11 +2,11 @@ use std::sync::Arc;
|
||||
|
||||
use swc_core::{
|
||||
atoms::{Atom, Wtf8Atom},
|
||||
common::{errors::HANDLER, SourceMap, Span},
|
||||
common::{SourceMap, Span, errors::HANDLER},
|
||||
ecma::{
|
||||
ast::{
|
||||
op, BinExpr, CallExpr, Callee, CondExpr, Expr, IdentName, IfStmt, ImportDecl, Lit,
|
||||
MemberExpr, MemberProp, NamedExport, UnaryExpr,
|
||||
BinExpr, CallExpr, Callee, CondExpr, Expr, IdentName, IfStmt, ImportDecl, Lit,
|
||||
MemberExpr, MemberProp, NamedExport, UnaryExpr, op,
|
||||
},
|
||||
utils::{ExprCtx, ExprExt},
|
||||
visit::{Visit, VisitWith},
|
||||
@@ -272,19 +272,17 @@ Learn more: https://nextjs.org/docs/api-reference/edge-runtime",
|
||||
self.guarded_symbols.push(ident.sym.clone());
|
||||
}
|
||||
Expr::Member(member) => {
|
||||
if member.prop.is_ident_with("NEXT_RUNTIME") {
|
||||
if let Expr::Member(obj_member) = &*member.obj {
|
||||
if obj_member.obj.is_global_ref_to(self.ctx, "process")
|
||||
&& obj_member.prop.is_ident_with("env")
|
||||
{
|
||||
self.guarded_runtime = true;
|
||||
}
|
||||
}
|
||||
if member.prop.is_ident_with("NEXT_RUNTIME")
|
||||
&& let Expr::Member(obj_member) = &*member.obj
|
||||
&& obj_member.obj.is_global_ref_to(self.ctx, "process")
|
||||
&& obj_member.prop.is_ident_with("env")
|
||||
{
|
||||
self.guarded_runtime = true;
|
||||
}
|
||||
if member.obj.is_global_ref_to(self.ctx, "process") {
|
||||
if let MemberProp::Ident(prop) = &member.prop {
|
||||
self.guarded_process_props.push(prop.sym.clone());
|
||||
}
|
||||
if member.obj.is_global_ref_to(self.ctx, "process")
|
||||
&& let MemberProp::Ident(prop) = &member.prop
|
||||
{
|
||||
self.guarded_process_props.push(prop.sym.clone());
|
||||
}
|
||||
}
|
||||
Expr::Bin(BinExpr {
|
||||
@@ -330,10 +328,10 @@ where
|
||||
fn visit_call_expr(&mut self, n: &CallExpr) {
|
||||
n.visit_children_with(self);
|
||||
|
||||
if let Callee::Import(_) = &n.callee {
|
||||
if let Some(Expr::Lit(Lit::Str(s))) = n.args.first().map(|e| &*e.expr) {
|
||||
self.warn_if_nodejs_module(n.span, &s.value);
|
||||
}
|
||||
if let Callee::Import(_) = &n.callee
|
||||
&& let Some(Expr::Lit(Lit::Str(s))) = n.args.first().map(|e| &*e.expr)
|
||||
{
|
||||
self.warn_if_nodejs_module(n.span, &s.value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,18 +369,18 @@ where
|
||||
}
|
||||
|
||||
fn visit_expr(&mut self, n: &Expr) {
|
||||
if let Expr::Ident(ident) = n {
|
||||
if ident.ctxt == self.ctx.unresolved_ctxt {
|
||||
if ident.sym == "eval" {
|
||||
self.emit_dynamic_not_allowed_error(ident.span);
|
||||
return;
|
||||
}
|
||||
if let Expr::Ident(ident) = n
|
||||
&& ident.ctxt == self.ctx.unresolved_ctxt
|
||||
{
|
||||
if ident.sym == "eval" {
|
||||
self.emit_dynamic_not_allowed_error(ident.span);
|
||||
return;
|
||||
}
|
||||
|
||||
for api in EDGE_UNSUPPORTED_NODE_APIS {
|
||||
if self.is_in_middleware_layer() && ident.sym == *api {
|
||||
self.emit_unsupported_api_error(ident.span, api);
|
||||
return;
|
||||
}
|
||||
for api in EDGE_UNSUPPORTED_NODE_APIS {
|
||||
if self.is_in_middleware_layer() && ident.sym == *api {
|
||||
self.emit_unsupported_api_error(ident.span, api);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -406,11 +404,11 @@ where
|
||||
}
|
||||
|
||||
fn visit_member_expr(&mut self, n: &MemberExpr) {
|
||||
if n.obj.is_global_ref_to(self.ctx, "process") {
|
||||
if let MemberProp::Ident(prop) = &n.prop {
|
||||
self.warn_for_unsupported_process_api(n.span, prop);
|
||||
return;
|
||||
}
|
||||
if n.obj.is_global_ref_to(self.ctx, "process")
|
||||
&& let MemberProp::Ident(prop) = &n.prop
|
||||
{
|
||||
self.warn_for_unsupported_process_api(n.span, prop);
|
||||
return;
|
||||
}
|
||||
|
||||
n.visit_children_with(self);
|
||||
|
||||
@@ -2,12 +2,12 @@ use std::{iter::FromIterator, path::PathBuf};
|
||||
|
||||
use next_custom_transforms::transforms::{
|
||||
disallow_re_export_all_in_page::disallow_re_export_all_in_page,
|
||||
dynamic::{next_dynamic, NextDynamicMode},
|
||||
fonts::{next_font_loaders, Config as FontLoaderConfig},
|
||||
dynamic::{NextDynamicMode, next_dynamic},
|
||||
fonts::{Config as FontLoaderConfig, next_font_loaders},
|
||||
next_ssg::next_ssg,
|
||||
react_server_components::server_components,
|
||||
server_actions::{self, server_actions, ServerActionsMode},
|
||||
strip_page_exports::{next_transform_strip_page_exports, ExportFilter},
|
||||
server_actions::{self, ServerActionsMode, server_actions},
|
||||
strip_page_exports::{ExportFilter, next_transform_strip_page_exports},
|
||||
};
|
||||
use rustc_hash::FxHashSet;
|
||||
use swc_core::{
|
||||
@@ -17,7 +17,7 @@ use swc_core::{
|
||||
parser::{EsSyntax, Syntax},
|
||||
transforms::{
|
||||
base::resolver,
|
||||
testing::{test_fixture, FixtureTestConfig},
|
||||
testing::{FixtureTestConfig, test_fixture},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -9,17 +9,17 @@ use next_custom_transforms::transforms::{
|
||||
cjs_optimizer::cjs_optimizer,
|
||||
debug_fn_name::debug_fn_name,
|
||||
debug_instant_stack::debug_instant_stack,
|
||||
dynamic::{next_dynamic, NextDynamicMode},
|
||||
fonts::{next_font_loaders, Config as FontLoaderConfig},
|
||||
dynamic::{NextDynamicMode, next_dynamic},
|
||||
fonts::{Config as FontLoaderConfig, next_font_loaders},
|
||||
named_import_transform::named_import_transform,
|
||||
next_ssg::next_ssg,
|
||||
optimize_barrel::optimize_barrel,
|
||||
optimize_server_react::{self, optimize_server_react},
|
||||
pure::pure_magic,
|
||||
react_server_components::server_components,
|
||||
server_actions::{self, server_actions, ServerActionsMode},
|
||||
shake_exports::{shake_exports, Config as ShakeExportsConfig},
|
||||
strip_page_exports::{next_transform_strip_page_exports, ExportFilter},
|
||||
server_actions::{self, ServerActionsMode, server_actions},
|
||||
shake_exports::{Config as ShakeExportsConfig, shake_exports},
|
||||
strip_page_exports::{ExportFilter, next_transform_strip_page_exports},
|
||||
track_dynamic_imports::track_dynamic_imports,
|
||||
warn_for_edge_runtime::warn_for_edge_runtime,
|
||||
};
|
||||
@@ -27,20 +27,20 @@ use rustc_hash::FxHashSet;
|
||||
use serde::de::DeserializeOwned;
|
||||
use swc_core::{
|
||||
atoms::atom,
|
||||
common::{comments::SingleThreadedComments, FileName, Mark, SyntaxContext},
|
||||
common::{FileName, Mark, SyntaxContext, comments::SingleThreadedComments},
|
||||
ecma::{
|
||||
ast::Pass,
|
||||
parser::{EsSyntax, Syntax, TsSyntax},
|
||||
transforms::{
|
||||
base::resolver,
|
||||
react::jsx,
|
||||
testing::{test_fixture, FixtureTestConfig},
|
||||
testing::{FixtureTestConfig, test_fixture},
|
||||
},
|
||||
utils::ExprCtx,
|
||||
visit::{visit_mut_pass, visit_pass, Visit},
|
||||
visit::{Visit, visit_mut_pass, visit_pass},
|
||||
},
|
||||
};
|
||||
use swc_relay::{relay, RelayLanguageConfig};
|
||||
use swc_relay::{RelayLanguageConfig, relay};
|
||||
use testing::fixture;
|
||||
|
||||
fn syntax() -> Syntax {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use next_custom_transforms::chain_transforms::{custom_before_pass, TransformOptions};
|
||||
use next_custom_transforms::chain_transforms::{TransformOptions, custom_before_pass};
|
||||
use serde::de::DeserializeOwned;
|
||||
use swc_core::{
|
||||
base::Compiler,
|
||||
common::{comments::SingleThreadedComments, Mark},
|
||||
common::{Mark, comments::SingleThreadedComments},
|
||||
ecma::{
|
||||
ast::noop_pass,
|
||||
parser::{Syntax, TsSyntax},
|
||||
|
||||
@@ -5,8 +5,8 @@ use once_cell::sync::Lazy;
|
||||
use rustc_hash::FxHashSet;
|
||||
use swc_core::{
|
||||
atoms::Atom,
|
||||
base::{try_with_handler, Compiler},
|
||||
common::{comments::SingleThreadedComments, FileName, FilePathMapping, SourceMap, GLOBALS},
|
||||
base::{Compiler, try_with_handler},
|
||||
common::{FileName, FilePathMapping, GLOBALS, SourceMap, comments::SingleThreadedComments},
|
||||
ecma::ast::noop_pass,
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[package]
|
||||
edition = "2018"
|
||||
edition = "2024"
|
||||
name = "wasm"
|
||||
publish = false
|
||||
version = "0.0.0"
|
||||
|
||||
@@ -2,17 +2,18 @@ use std::{fmt::Debug, sync::Arc};
|
||||
|
||||
use anyhow::Context;
|
||||
use js_sys::JsString;
|
||||
use next_custom_transforms::chain_transforms::{custom_before_pass, TransformOptions};
|
||||
use next_custom_transforms::chain_transforms::{TransformOptions, custom_before_pass};
|
||||
use rustc_hash::FxHashMap;
|
||||
use swc_core::{
|
||||
base::{
|
||||
Compiler,
|
||||
config::{JsMinifyOptions, ParseOptions},
|
||||
try_with_handler, Compiler,
|
||||
try_with_handler,
|
||||
},
|
||||
common::{
|
||||
FileName, FilePathMapping, GLOBALS, Mark, SourceMap,
|
||||
comments::{Comments, SingleThreadedComments},
|
||||
errors::ColorConfig,
|
||||
FileName, FilePathMapping, Mark, SourceMap, GLOBALS,
|
||||
},
|
||||
ecma::ast::noop_pass,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use js_sys::JsString;
|
||||
use mdxjs::{compile, Options};
|
||||
use mdxjs::{Options, compile};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen_futures::future_to_promise;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user