Skip to content

Commit

Permalink
Support default export expression for variables (#46896)
Browse files Browse the repository at this point in the history
Similar to #46888, this PR adds support for the case:

```js
async function foo () {}
export default foo
```

...where you export an ident as a default export expression.

Closes NEXT-770

~Should be landed after #46881.~
  • Loading branch information
shuding authored Mar 8, 2023
1 parent 37b0349 commit 8ca0233
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 13 deletions.
64 changes: 51 additions & 13 deletions packages/next-swc/crates/core/src/server_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,24 @@ struct ServerActions<C: Comments> {
closure_idents: Vec<Id>,
action_idents: Vec<Name>,
async_fn_idents: Vec<Id>,
exported_idents: Vec<Id>,

// (ident, is default export)
exported_idents: Vec<(Id, bool)>,

annotations: Vec<Stmt>,
extra_items: Vec<ModuleItem>,
export_actions: Vec<String>,
}

impl<C: Comments> ServerActions<C> {
fn get_action_info(&mut self, ident: &mut Ident, function: &mut Box<Function>) -> (bool, bool) {
fn get_action_info(
&mut self,
ident: &mut Ident,
function: &mut Box<Function>,
) -> (bool, bool, bool) {
let mut is_action_fn = false;
let mut is_exported = false;
let mut is_exported = self.in_export_decl;
let mut is_default_export = self.in_default_export_decl;

if self.in_action_file && self.in_export_decl {
// All export functions in a server file are actions
Expand All @@ -103,20 +110,26 @@ impl<C: Comments> ServerActions<C> {
}

// If it's exported via named export, it's a valid action.
if !is_action_fn && self.exported_idents.contains(&ident.to_id()) {
let exported_ident = self
.exported_idents
.iter()
.find(|(id, _)| id == &ident.to_id());
if let Some((_, is_default)) = exported_ident {
is_action_fn = true;
is_exported = true;
is_default_export = *is_default;
}
}

(is_action_fn, is_exported)
(is_action_fn, is_exported, is_default_export)
}

fn add_action_annotations(
&mut self,
ident: &mut Ident,
function: &mut Box<Function>,
is_exported: bool,
is_default_export: bool,
) -> Option<Box<Function>> {
if !function.is_async {
HANDLER.with(|handler| {
Expand All @@ -134,7 +147,7 @@ impl<C: Comments> ServerActions<C> {
};
let action_ident = private_ident!(action_name.clone());

let export_name: JsWord = if self.in_default_export_decl {
let export_name: JsWord = if is_default_export {
"default".into()
} else {
action_name
Expand Down Expand Up @@ -315,7 +328,7 @@ impl<C: Comments> VisitMut for ServerActions<C> {
}
}

let (is_action_fn, is_exported) =
let (is_action_fn, is_exported, is_default_export) =
self.get_action_info(f.ident.as_mut().unwrap(), &mut f.function);

{
Expand All @@ -336,8 +349,12 @@ impl<C: Comments> VisitMut for ServerActions<C> {
return;
}

let maybe_new_fn =
self.add_action_annotations(f.ident.as_mut().unwrap(), &mut f.function, is_exported);
let maybe_new_fn = self.add_action_annotations(
f.ident.as_mut().unwrap(),
&mut f.function,
is_exported,
is_default_export,
);

if let Some(new_fn) = maybe_new_fn {
f.function = new_fn;
Expand All @@ -354,7 +371,8 @@ impl<C: Comments> VisitMut for ServerActions<C> {
return;
}

let (is_action_fn, is_exported) = self.get_action_info(&mut f.ident, &mut f.function);
let (is_action_fn, is_exported, is_default_export) =
self.get_action_info(&mut f.ident, &mut f.function);

{
// Visit children
Expand All @@ -374,7 +392,12 @@ impl<C: Comments> VisitMut for ServerActions<C> {
return;
}

let maybe_new_fn = self.add_action_annotations(&mut f.ident, &mut f.function, is_exported);
let maybe_new_fn = self.add_action_annotations(
&mut f.ident,
&mut f.function,
is_exported,
is_default_export,
);

if let Some(new_fn) = maybe_new_fn {
f.function = new_fn;
Expand Down Expand Up @@ -468,7 +491,8 @@ impl<C: Comments> VisitMut for ServerActions<C> {
..
})) => {
let ids: Vec<Id> = collect_idents_in_var_decls(&var.decls);
self.exported_idents.extend(ids);
self.exported_idents
.extend(ids.into_iter().map(|id| (id, false)));
}
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named)) => {
for spec in &named.specifiers {
Expand All @@ -478,10 +502,19 @@ impl<C: Comments> VisitMut for ServerActions<C> {
}) = spec
{
// export { foo, foo as bar }
self.exported_idents.push(ident.to_id());
self.exported_idents.push((ident.to_id(), false));
}
}
}
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(ExportDefaultExpr {
expr,
..
})) => {
if let Expr::Ident(ident) = &**expr {
// export default foo
self.exported_idents.push((ident.to_id(), true));
}
}
_ => {}
}

Expand Down Expand Up @@ -555,6 +588,11 @@ impl<C: Comments> VisitMut for ServerActions<C> {
..
})) => match &**expr {
Expr::Fn(_f) => {}
Expr::Ident(ident) => {
if !self.async_fn_idents.contains(&ident.to_id()) {
disallowed_export_span = *span;
}
}
_ => {
disallowed_export_span = *span;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
'use server'
async function foo () {}
export default foo
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/* __next_internal_action_entry_do_not_use__ default */ async function foo() {}
foo.$$typeof = Symbol.for("react.server.reference");
foo.$$id = "c18c215a6b7cdc64bf709f3a714ffdef1bf9651d";
foo.$$bound = [];
export default foo;

0 comments on commit 8ca0233

Please sign in to comment.