Skip to content

Commit

Permalink
Fix bundler (#1246)
Browse files Browse the repository at this point in the history
swc_bundler:
 - Reduce level of logging.
 - Handle export specifiers without alias. (denoland/deno#8573)
 - Handle normal initialization while reordering statements. (denoland/deno#8574)
 - Handle top level `await`s in wrapped modules. (denoland/deno#8584)
 - Add benchmark for the bundler.
  • Loading branch information
kdy1 authored Dec 2, 2020
1 parent 19cbdc3 commit 5478463
Show file tree
Hide file tree
Showing 19 changed files with 1,397 additions and 399 deletions.
2 changes: 1 addition & 1 deletion bundler/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ edition = "2018"
license = "Apache-2.0/MIT"
name = "swc_bundler"
repository = "https://github.com/swc-project/swc.git"
version = "0.17.4"
version = "0.17.5"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
Expand Down
2 changes: 1 addition & 1 deletion bundler/src/bundler/chunk/circular.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ where
.body
.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
span: DUMMY_SP,
span: DUMMY_SP.with_ctxt(self.synthesized_ctxt),
specifiers: exports,
src: None,
type_only: false,
Expand Down
212 changes: 115 additions & 97 deletions bundler/src/bundler/chunk/computed_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use swc_atoms::js_word;
use swc_common::{SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{find_ids, private_ident, ExprFactory};
use swc_ecma_visit::{noop_fold_type, Fold, FoldWith};
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};

impl<L, R> Bundler<'_, L, R>
where
Expand Down Expand Up @@ -40,6 +40,12 @@ where
None => bail!("{:?} should not be wrapped with a function", id),
};

let is_async = {
let mut v = TopLevelAwaitFinder { found: false };
module.visit_with(&Invalid { span: DUMMY_SP }, &mut v);
v.found
};

let mut module_items = vec![];

let stmts = {
Expand Down Expand Up @@ -77,20 +83,27 @@ where
stmts,
}),
is_generator: false,
is_async: false,
is_async,
type_params: Default::default(),
return_type: Default::default(),
},
ident: None,
});

let module_expr = Expr::Call(CallExpr {
let mut module_expr = Expr::Call(CallExpr {
span: DUMMY_SP,
callee: module_fn.as_callee(),
type_args: Default::default(),
args: Default::default(),
});

if is_async {
module_expr = Expr::Await(AwaitExpr {
span: DUMMY_SP,
arg: Box::new(module_expr),
});
}

let var_decl = VarDecl {
span,
declare: false,
Expand All @@ -113,6 +126,22 @@ where
}
}

struct TopLevelAwaitFinder {
found: bool,
}

impl Visit for TopLevelAwaitFinder {
noop_visit_type!();

fn visit_function(&mut self, _: &Function, _: &dyn Node) {}
fn visit_arrow_expr(&mut self, _: &ArrowExpr, _: &dyn Node) {}
fn visit_class_member(&mut self, _: &ClassMember, _: &dyn Node) {}

fn visit_await_expr(&mut self, _: &AwaitExpr, _: &dyn Node) {
self.found = true;
}
}

struct ExportToReturn {
exports: Vec<PropOrSpread>,
synthesized_ctxt: SyntaxContext,
Expand All @@ -131,111 +160,100 @@ impl Fold for ExportToReturn {
ModuleItem::Stmt(_) => return item,
};

let stmt = match decl {
ModuleDecl::Import(_) => return ModuleItem::ModuleDecl(decl),
ModuleDecl::ExportDecl(export) => {
match &export.decl {
Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => {
self.exports
.push(PropOrSpread::Prop(Box::new(Prop::Shorthand(ident.clone()))));
let stmt =
match decl {
ModuleDecl::Import(_) => return ModuleItem::ModuleDecl(decl),
ModuleDecl::ExportDecl(export) => {
match &export.decl {
Decl::Class(ClassDecl { ident, .. }) | Decl::Fn(FnDecl { ident, .. }) => {
self.exports
.push(PropOrSpread::Prop(Box::new(Prop::Shorthand(ident.clone()))));
}
Decl::Var(decl) => {
let ids: Vec<Ident> = find_ids(decl);
self.exports.extend(
ids.into_iter()
.map(Prop::Shorthand)
.map(Box::new)
.map(PropOrSpread::Prop),
);
}
_ => unreachable!(),
}
Decl::Var(decl) => {
let ids: Vec<Ident> = find_ids(decl);
self.exports.extend(
ids.into_iter()
.map(Prop::Shorthand)
.map(Box::new)
.map(PropOrSpread::Prop),
);
}
_ => unreachable!(),

Some(Stmt::Decl(export.decl))
}

Some(Stmt::Decl(export.decl))
}

// Ignore export {} specified by user.
ModuleDecl::ExportNamed(NamedExport {
span,
src: None,
specifiers,
..
}) if span.ctxt != self.synthesized_ctxt => {
for s in specifiers {
match s {
ExportSpecifier::Namespace(_s) => {}
ExportSpecifier::Default(_s) => {}
ExportSpecifier::Named(_s) => {}
// Ignore export {} specified by user.
ModuleDecl::ExportNamed(NamedExport {
span, src: None, ..
}) if span.ctxt != self.synthesized_ctxt => None,
ModuleDecl::ExportDefaultDecl(export) => match export.decl {
DefaultDecl::Class(expr) => {
let ident = expr.ident;
let ident = ident.unwrap_or_else(|| private_ident!("_default_decl"));

self.exports
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new(js_word!("default"), export.span)),
value: Box::new(Expr::Ident(ident.clone())),
}))));

Some(Stmt::Decl(Decl::Class(ClassDecl {
ident,
class: expr.class,
declare: false,
})))
}
}
DefaultDecl::Fn(expr) => {
let ident = expr.ident;
let ident = ident.unwrap_or_else(|| private_ident!("_default_decl"));

None
}
ModuleDecl::ExportDefaultDecl(export) => match export.decl {
DefaultDecl::Class(expr) => {
let ident = expr.ident;
let ident = ident.unwrap_or_else(|| private_ident!("_default_decl"));

self.exports
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new(js_word!("default"), export.span)),
value: Box::new(Expr::Ident(ident.clone())),
}))));

Some(Stmt::Decl(Decl::Class(ClassDecl {
ident,
class: expr.class,
declare: false,
})))
}
DefaultDecl::Fn(expr) => {
let ident = expr.ident;
let ident = ident.unwrap_or_else(|| private_ident!("_default_decl"));

self.exports
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new(js_word!("default"), export.span)),
value: Box::new(Expr::Ident(ident.clone())),
}))));

Some(Stmt::Decl(Decl::Fn(FnDecl {
ident,
function: expr.function,
declare: false,
})))
self.exports
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(Ident::new(js_word!("default"), export.span)),
value: Box::new(Expr::Ident(ident.clone())),
}))));

Some(Stmt::Decl(Decl::Fn(FnDecl {
ident,
function: expr.function,
declare: false,
})))
}
DefaultDecl::TsInterfaceDecl(_) => None,
},
ModuleDecl::ExportDefaultExpr(_) => None,
ModuleDecl::ExportAll(export) => {
return ModuleItem::ModuleDecl(ModuleDecl::ExportAll(export))
}
DefaultDecl::TsInterfaceDecl(_) => None,
},
ModuleDecl::ExportDefaultExpr(_) => None,
ModuleDecl::ExportAll(export) => {
return ModuleItem::ModuleDecl(ModuleDecl::ExportAll(export))
}
ModuleDecl::ExportNamed(named) => {
for specifier in &named.specifiers {
match specifier {
ExportSpecifier::Namespace(_) => {}
ExportSpecifier::Default(_) => {}
ExportSpecifier::Named(named) => match &named.exported {
Some(exported) => {
self.exports
.push(PropOrSpread::Prop(Box::new(Prop::KeyValue(
KeyValueProp {
ModuleDecl::ExportNamed(named) => {
for specifier in &named.specifiers {
match specifier {
ExportSpecifier::Namespace(_) => {}
ExportSpecifier::Default(_) => {}
ExportSpecifier::Named(named) => {
match &named.exported {
Some(exported) => self.exports.push(PropOrSpread::Prop(
Box::new(Prop::KeyValue(KeyValueProp {
key: PropName::Ident(exported.clone()),
value: Box::new(Expr::Ident(named.orig.clone())),
},
))))
})),
)),
None => self.exports.push(PropOrSpread::Prop(Box::new(
Prop::Shorthand(named.orig.clone()),
))),
}
}
None => {}
},
}
}
}

return ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named));
}
ModuleDecl::TsImportEquals(_) => None,
ModuleDecl::TsExportAssignment(_) => None,
ModuleDecl::TsNamespaceExport(_) => None,
};
return ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named));
}
ModuleDecl::TsImportEquals(_) => None,
ModuleDecl::TsExportAssignment(_) => None,
ModuleDecl::TsNamespaceExport(_) => None,
};

if let Some(stmt) = stmt {
ModuleItem::Stmt(stmt)
Expand Down
2 changes: 1 addition & 1 deletion bundler/src/bundler/chunk/plan/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,7 +398,7 @@ where

let t = &mut normal_entry.chunks;
if t.iter().all(|dependancy| dependancy.id != dep) {
log::info!("Normal, esm: {:?} => {:?}", entry, dep);
log::debug!("Normal, esm: {:?} => {:?}", entry, dep);
done.insert(dep);
t.push(Dependancy {
id: dep,
Expand Down
12 changes: 12 additions & 0 deletions bundler/src/bundler/chunk/sort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,18 @@ struct InitializerFinder {
impl Visit for InitializerFinder {
noop_visit_type!();

fn visit_pat(&mut self, pat: &Pat, _: &dyn Node) {
match pat {
Pat::Ident(i) if self.ident == *i => {
self.found = true;
}

_ => {
pat.visit_children_with(self);
}
}
}

fn visit_ident(&mut self, i: &Ident, _: &dyn Node) {
if self.in_complex && self.ident == *i {
self.found = true;
Expand Down
Loading

0 comments on commit 5478463

Please sign in to comment.