Improve spack (#972)

swd_bundler:
 - Handle reexports

spack:
 - Do not transform files from node_modules
This commit is contained in:
강동윤 2020-08-17 15:04:08 +09:00 committed by GitHub
parent 73878728aa
commit 28398280f7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
53 changed files with 759 additions and 158 deletions

View File

@ -47,7 +47,7 @@ name = "usage"
codegen-units = 1
lto = true
# debug = true
opt-level = 'z'
# opt-level = 'z'
[profile.bench]
codegen-units = 1

View File

@ -1,6 +1,6 @@
[package]
name = "swc_bundler"
version = "0.2.2"
version = "0.2.3"
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
license = "Apache-2.0/MIT"
repository = "https://github.com/swc-project/swc.git"

View File

@ -116,6 +116,7 @@ where
mark: circular_module.mark(),
specifiers: &specifiers,
excluded: vec![],
is_export: false,
});
break;
}

View File

@ -0,0 +1,365 @@
use super::merge::{LocalMarker, Unexporter};
use crate::{bundler::load::TransformedModule, Bundler, Load, ModuleId, Resolve};
use anyhow::{Context, Error};
use std::mem::{replace, take};
use swc_atoms::js_word;
use swc_common::{Spanned, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::find_ids;
use swc_ecma_visit::{FoldWith, VisitMut, VisitMutWith};
impl<L, R> Bundler<'_, L, R>
where
L: Load,
R: Resolve,
{
pub(super) fn merge_reexports(
&self,
mut entry: Module,
info: &TransformedModule,
targets: &mut Vec<ModuleId>,
) -> Result<Module, Error> {
entry.visit_mut_with(&mut DefaultRenamer);
for (src, specifiers) in &info.exports.reexports {
let imported = self.scope.get_module(src.module_id).unwrap();
assert!(imported.is_es6, "Reexports are es6 only");
info.helpers.extend(&imported.helpers);
if let Some(pos) = targets.iter().position(|x| *x == src.module_id) {
log::debug!("Reexport: targets.remove({})", imported.fm.name);
targets.remove(pos);
}
let mut dep = self
.merge_modules(src.module_id, false, targets)
.with_context(|| {
format!(
"failed to merge for reexport: ({}):{} <= ({}):{}",
info.id, info.fm.name, src.module_id, src.src.value
)
})?;
dep = self.drop_unused(dep, Some(&specifiers));
// print_hygiene("entry:init", &self.cm, &entry);
// print_hygiene("dep:init", &self.cm, &dep);
entry = entry.fold_with(&mut LocalMarker {
mark: imported.mark(),
specifiers,
excluded: vec![],
is_export: false,
});
// print_hygiene(&format!("entry:local-marker"), &self.cm, &entry);
entry.visit_mut_with(&mut NamedExportOrigMarker {
top_level_ctxt: SyntaxContext::empty().apply_mark(self.top_level_mark),
target_ctxt: SyntaxContext::empty().apply_mark(info.mark()),
});
// print_hygiene(&format!("entry:named-export-orig"), &self.cm, &entry);
dep.visit_mut_with(&mut UnexportAsVar {
target_ctxt: SyntaxContext::empty().apply_mark(info.mark()),
});
// print_hygiene("dep:unexport-as-var", &self.cm, &dep);
dep.visit_mut_with(&mut AliasExports {
importer_ctxt: SyntaxContext::empty().apply_mark(info.mark()),
decls: Default::default(),
});
// print_hygiene("dep:alias-exports", &self.cm, &dep);
dep = dep.fold_with(&mut Unexporter);
entry.visit_mut_with(&mut ExportRenamer {
from: SyntaxContext::empty().apply_mark(imported.mark()),
to: SyntaxContext::empty().apply_mark(info.mark()),
});
// print_hygiene("entry:before-injection", &self.cm, &entry);
// print_hygiene("dep:before-injection", &self.cm, &dep);
// Replace import statement / require with module body
let mut injector = ExportInjector {
imported: dep.body.clone(),
src: src.src.clone(),
};
entry.body.visit_mut_with(&mut injector);
// print_hygiene(
// &format!(
// "entry:injection {:?} <- {:?}",
// SyntaxContext::empty().apply_mark(info.mark()),
// SyntaxContext::empty().apply_mark(imported.mark()),
// ),
// &self.cm,
// &entry,
// );
assert_eq!(injector.imported, vec![]);
}
Ok(entry)
}
}
struct ExportInjector {
imported: Vec<ModuleItem>,
src: Str,
}
impl VisitMut for ExportInjector {
fn visit_mut_module_items(&mut self, orig: &mut Vec<ModuleItem>) {
let items = take(orig);
let mut buf = Vec::with_capacity(self.imported.len() + items.len());
for item in items {
//
match item {
ModuleItem::Stmt(Stmt::Empty(..)) => continue,
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ref export))
if export.src.value == self.src.value =>
{
buf.extend(take(&mut self.imported));
buf.push(item);
}
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
export @ NamedExport { src: Some(..), .. },
)) if export.src.as_ref().unwrap().value == self.src.value => {
buf.extend(take(&mut self.imported));
buf.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
NamedExport {
src: None,
..export
},
)));
}
_ => buf.push(item),
}
}
*orig = buf;
}
}
struct ExportRenamer {
/// Syntax context for the top level.
from: SyntaxContext,
/// Syntax context for the top level nodes of dependency module.
to: SyntaxContext,
}
impl VisitMut for ExportRenamer {
fn visit_mut_named_export(&mut self, export: &mut NamedExport) {
// if export.src.is_none() {
// return;
// }
export.specifiers.visit_mut_children_with(self);
}
fn visit_mut_export_named_specifier(&mut self, s: &mut ExportNamedSpecifier) {
match &mut s.exported {
Some(v) => {
if v.span.ctxt == self.from {
v.span = v.span.with_ctxt(self.to);
}
}
None => {}
}
if s.orig.span.ctxt == self.from {
s.orig.span = s.orig.span.with_ctxt(self.to);
}
}
fn visit_mut_stmt(&mut self, _: &mut Stmt) {}
}
/// Converts
///
/// ```js
/// export { l1 as e2 };
/// ```
///
/// to
///
/// ```js
/// const e3 = l1;
/// ```
struct UnexportAsVar {
/// Syntax context for the generated variables.
target_ctxt: SyntaxContext,
}
impl VisitMut for UnexportAsVar {
fn visit_mut_module_item(&mut self, n: &mut ModuleItem) {
n.visit_mut_children_with(self);
match n {
ModuleItem::ModuleDecl(ModuleDecl::ExportDefaultExpr(export)) => {
let expr = replace(
&mut export.expr,
Box::new(Expr::Invalid(Invalid { span: DUMMY_SP })),
);
*n = ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
span: export.span,
kind: VarDeclKind::Const,
declare: false,
decls: vec![VarDeclarator {
span: DUMMY_SP,
name: Pat::Ident(Ident::new(
"__default".into(),
expr.span().with_ctxt(self.target_ctxt),
)),
init: Some(expr),
definite: false,
}],
})));
}
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(ref export)) => {
let mut decls = vec![];
for s in &export.specifiers {
match s {
ExportSpecifier::Namespace(_) => {}
ExportSpecifier::Default(_) => {}
ExportSpecifier::Named(n) => match &n.exported {
Some(exported) => {
// TODO: (maybe) Check previous context
let mut exported = exported.clone();
exported.span = exported.span.with_ctxt(self.target_ctxt);
decls.push(VarDeclarator {
span: n.span,
name: Pat::Ident(exported),
init: Some(Box::new(Expr::Ident(n.orig.clone()))),
definite: true,
})
}
None => decls.push(VarDeclarator {
span: n.span,
name: Pat::Ident(Ident::new(
n.orig.sym.clone(),
n.orig.span.with_ctxt(self.target_ctxt),
)),
init: Some(Box::new(Expr::Ident(n.orig.clone()))),
definite: false,
}),
},
}
}
if decls.is_empty() {
*n = ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
} else {
*n = ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
span: export.span,
decls,
declare: false,
kind: VarDeclKind::Const,
})))
}
}
_ => {}
}
}
fn visit_mut_stmt(&mut self, _: &mut Stmt) {}
}
pub(super) struct NamedExportOrigMarker {
pub top_level_ctxt: SyntaxContext,
pub target_ctxt: SyntaxContext,
}
impl VisitMut for NamedExportOrigMarker {
fn visit_mut_export_named_specifier(&mut self, s: &mut ExportNamedSpecifier) {
if s.orig.span.ctxt == self.top_level_ctxt {
s.orig.span = s.orig.span.with_ctxt(self.target_ctxt);
}
}
fn visit_mut_stmt(&mut self, _: &mut Stmt) {}
}
struct AliasExports {
/// Syntax context of the importer.
importer_ctxt: SyntaxContext,
decls: Vec<VarDeclarator>,
}
impl VisitMut for AliasExports {
fn visit_mut_module_items(&mut self, items: &mut Vec<ModuleItem>) {
for item in items.iter_mut() {
item.visit_mut_with(self);
}
if !self.decls.is_empty() {
items.push(ModuleItem::Stmt(Stmt::Decl(Decl::Var(VarDecl {
span: DUMMY_SP,
kind: VarDeclKind::Const,
decls: take(&mut self.decls),
declare: false,
}))))
}
}
fn visit_mut_module_decl(&mut self, decl: &mut ModuleDecl) {
match decl {
ModuleDecl::ExportDecl(ref export) => match &export.decl {
Decl::Class(c) => self.decls.push(VarDeclarator {
span: c.class.span,
name: Pat::Ident(Ident::new(
c.ident.sym.clone(),
c.ident.span.with_ctxt(self.importer_ctxt),
)),
init: Some(Box::new(Expr::Ident(c.ident.clone()))),
definite: false,
}),
Decl::Fn(f) => self.decls.push(VarDeclarator {
span: f.function.span,
name: Pat::Ident(Ident::new(
f.ident.sym.clone(),
f.ident.span.with_ctxt(self.importer_ctxt),
)),
init: Some(Box::new(Expr::Ident(f.ident.clone()))),
definite: false,
}),
Decl::Var(var) => {
let ids = find_ids::<_, Ident>(&var.decls);
for ident in ids {
self.decls.push(VarDeclarator {
span: ident.span,
name: Pat::Ident(Ident::new(
ident.sym.clone(),
ident.span.with_ctxt(self.importer_ctxt),
)),
init: Some(Box::new(Expr::Ident(ident))),
definite: false,
})
}
}
_ => {}
},
_ => {}
}
}
fn visit_mut_stmt(&mut self, _: &mut Stmt) {}
}
struct DefaultRenamer;
impl VisitMut for DefaultRenamer {
fn visit_mut_export_named_specifier(&mut self, n: &mut ExportNamedSpecifier) {
if n.orig.sym == js_word!("default") {
n.orig.sym = "__default".into()
}
}
fn visit_mut_stmt(&mut self, _: &mut Stmt) {}
}

View File

@ -12,7 +12,7 @@ use std::{
ops::{Deref, DerefMut},
};
use swc_atoms::{js_word, JsWord};
use swc_common::{Mark, Span, Spanned, SyntaxContext, DUMMY_SP};
use swc_common::{Mark, Spanned, SyntaxContext, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{find_ids, DestructuringFinder, StmtLike};
use swc_ecma_visit::{Fold, FoldWith, VisitMut, VisitMutWith, VisitWith};
@ -54,7 +54,9 @@ where
log::info!("Merge: ({}){} <= {:?}", info.id, info.fm.name, targets);
// print_hygiene("before:merge", &self.cm, &entry);
entry = self
.merge_reexports(entry, &info, targets)
.context("failed to merge reepxorts")?;
for (src, specifiers) in &info.imports.specifiers {
if !targets.contains(&src.module_id) {
@ -73,6 +75,7 @@ where
mark: imported.mark(),
specifiers: &specifiers,
excluded: vec![],
is_export: false,
});
}
@ -178,6 +181,7 @@ where
mark: imported.mark(),
specifiers: &specifiers,
excluded: vec![],
is_export: false,
});
// // Note: this does not handle `export default
@ -190,28 +194,6 @@ where
// print_hygiene("dep:before:global-mark", &self.cm, &dep);
dep = dep.fold_with(&mut GlobalMarker {
used_mark: self.used_mark,
module_mark: imported.mark(),
});
// print_hygiene("dep:after:global-mark", &self.cm, &dep);
// {
// let code = self
// .swc
// .print(
// &dep.clone().fold_with(&mut HygieneVisualizer),
// SourceMapsConfig::Bool(false),
// None,
// false,
// )
// .unwrap()
// .code;
//
// println!("Dep:\n{}\n\n\n", code);
// }
// Replace import statement / require with module body
let mut injector = Es6ModuleInjector {
imported: dep.body.clone(),
@ -296,10 +278,9 @@ impl Fold for Unexporter {
},
// Empty statement
ModuleDecl::ExportAll(..) | ModuleDecl::ExportDefaultExpr(..) => {
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
}
ModuleDecl::ExportNamed(ref n) if n.src.is_none() => {
ModuleDecl::ExportAll(..)
| ModuleDecl::ExportDefaultExpr(..)
| ModuleDecl::ExportNamed(..) => {
ModuleItem::Stmt(Stmt::Empty(EmptyStmt { span: DUMMY_SP }))
}
ModuleDecl::Import(..) => ModuleItem::ModuleDecl(decl),
@ -535,6 +516,7 @@ pub(super) struct LocalMarker<'a> {
/// Mark applied to imported idents.
pub mark: Mark,
pub specifiers: &'a [Specifier],
pub is_export: bool,
pub excluded: Vec<Id>,
}
@ -636,10 +618,24 @@ impl Fold for LocalMarker<'_> {
}
// TODO: sym() => correct span
if self.specifiers.iter().any(|id| *id.local() == node) {
node.span = node
.span
.with_ctxt(SyntaxContext::empty().apply_mark(self.mark));
if self.is_export {
if self.specifiers.iter().any(|id| match id {
Specifier::Specific { local, alias } => match alias {
Some(v) => *v == node,
None => *local == node,
},
Specifier::Namespace { local } => *local == node,
}) {
node.span = node
.span
.with_ctxt(SyntaxContext::empty().apply_mark(self.mark));
}
} else {
if self.specifiers.iter().any(|id| *id.local() == node) {
node.span = node
.span
.with_ctxt(SyntaxContext::empty().apply_mark(self.mark));
}
}
node
@ -695,33 +691,3 @@ impl VisitMut for Es6ModuleInjector {
*orig = buf;
}
}
pub(super) struct GlobalMarker {
pub used_mark: Mark,
pub module_mark: Mark,
}
impl GlobalMarker {
fn is_marked_as_used(&self, span: Span) -> bool {
let mut ctxt = span.ctxt();
loop {
let m = ctxt.remove_mark();
if m == Mark::root() {
return false;
}
if m == self.used_mark {
return true;
}
}
}
}
impl Fold for GlobalMarker {
fn fold_span(&mut self, span: Span) -> Span {
if self.is_marked_as_used(span) {
return span.apply_mark(self.module_mark);
}
span
}
}

View File

@ -12,6 +12,7 @@ use swc_ecma_visit::FoldWith;
mod circular;
mod cjs;
mod export;
mod merge;
pub(super) type ModuleGraph = DiGraphMap<ModuleId, usize>;
@ -176,6 +177,15 @@ where
if src.is_unconditional { 2 } else { 1 },
);
}
for (src, _) in &m.exports.reexports {
self.add_to_graph(graph, src.module_id);
graph.add_edge(
module_id,
src.module_id,
if src.is_unconditional { 2 } else { 1 },
);
}
}
}

View File

@ -5,10 +5,10 @@ use super::{
use crate::{id::Id, load::Load, resolve::Resolve};
use std::collections::HashMap;
use swc_atoms::js_word;
use swc_common::{SyntaxContext, DUMMY_SP};
use swc_common::{FileName, SyntaxContext};
use swc_ecma_ast::*;
use swc_ecma_utils::find_ids;
use swc_ecma_visit::{Node, Visit, VisitWith};
use swc_ecma_visit::{VisitMut, VisitMutWith};
impl<L, R> Bundler<'_, L, R>
where
@ -22,11 +22,19 @@ where
///
/// TODO: Support pattern like
/// export const [a, b] = [1, 2]
pub(super) fn extract_export_info(&self, module: &Module) -> RawExports {
pub(super) fn extract_export_info(
&self,
file_name: &FileName,
module: &mut Module,
) -> RawExports {
self.run(|| {
let mut v = ExportFinder::default();
let mut v = ExportFinder {
info: Default::default(),
file_name,
bundler: self,
};
module.visit_with(&Invalid { span: DUMMY_SP } as _, &mut v);
module.visit_mut_with(&mut v);
v.info
})
@ -45,13 +53,46 @@ pub(super) struct Exports {
pub reexports: HashMap<Source, Vec<Specifier>>,
}
#[derive(Debug, Default)]
struct ExportFinder {
struct ExportFinder<'a, 'b, L, R>
where
L: Load,
R: Resolve,
{
info: RawExports,
file_name: &'a FileName,
bundler: &'a Bundler<'b, L, R>,
}
impl Visit for ExportFinder {
fn visit_module_item(&mut self, item: &ModuleItem, _: &dyn Node) {
impl<L, R> ExportFinder<'_, '_, L, R>
where
L: Load,
R: Resolve,
{
fn ctxt_for(&self, src: &str) -> Option<SyntaxContext> {
// Don't apply mark if it's a core module.
if self
.bundler
.config
.external_modules
.iter()
.any(|v| v == src)
{
return None;
}
let path = self.bundler.resolve(self.file_name, src).ok()?;
let (_, mark) = self.bundler.scope.module_id_gen.gen(&path);
let ctxt = SyntaxContext::empty();
Some(ctxt.apply_mark(mark))
}
}
impl<L, R> VisitMut for ExportFinder<'_, '_, L, R>
where
L: Load,
R: Resolve,
{
fn visit_mut_module_item(&mut self, item: &mut ModuleItem) {
match item {
// TODO: Optimize pure constants
// ModuleItem::ModuleDecl(ModuleDecl::ExportDecl(ExportDecl {
@ -137,6 +178,18 @@ impl Visit for ExportFinder {
}
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(named)) => {
match &named.src {
Some(v) => {
let ctxt = self.ctxt_for(&v.value);
match ctxt {
Some(ctxt) => {
named.span = named.span.with_ctxt(ctxt);
}
None => {}
}
}
None => {}
};
let v = self.info.items.entry(named.src.clone()).or_default();
for s in &named.specifiers {
match s {
@ -150,17 +203,31 @@ impl Visit for ExportFinder {
});
}
ExportSpecifier::Named(n) => {
v.push(Specifier::Specific {
local: n.orig.clone().into(),
alias: n.exported.clone().map(From::from),
});
if let Some(exported) = &n.exported {
v.push(Specifier::Specific {
local: exported.clone().into(),
alias: Some(n.orig.clone().into()),
});
} else {
v.push(Specifier::Specific {
local: n.orig.clone().into(),
alias: None,
});
}
}
}
}
return;
}
// TODO
// ModuleItem::ModuleDecl(ModuleDecl::ExportAll(all)) => {}
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(all)) => {
match self.ctxt_for(&all.src.value) {
Some(ctxt) => {
all.span = all.span.with_ctxt(ctxt);
}
None => {}
}
}
_ => {}
}
}

View File

@ -150,7 +150,7 @@ where
// println!("After imports:\n{}\n", code,);
// }
let exports = self.extract_export_info(&module);
let exports = self.extract_export_info(file_name, &mut module);
let is_es6 = if !self.config.require {
true

View File

@ -1,6 +1,6 @@
[package]
name = "swc_ecma_transforms"
version = "0.19.7"
version = "0.19.8"
authors = ["강동윤 <kdy1997.dev@gmail.com>"]
license = "Apache-2.0/MIT"
repository = "https://github.com/swc-project/swc.git"

View File

@ -194,12 +194,12 @@ impl Fold for Dce<'_> {
node
}
fn fold_export_all(&mut self, node: ExportAll) -> ExportAll {
fn fold_export_all(&mut self, mut node: ExportAll) -> ExportAll {
if self.is_marked(node.span) {
return node;
}
unimplemented!("dce: `export * from 'foo'`")
node.span = node.span.apply_mark(self.config.used_mark);
node
}
fn fold_export_decl(&mut self, mut node: ExportDecl) -> ExportDecl {

View File

@ -12,7 +12,7 @@ edition = "2018"
[dependencies]
swc_atoms = { path = "../atoms" }
swc_bundler = { path = "../bundler", features = ["concurrent"] }
swc_bundler = { path = "../bundler" }
swc_common = { path = "../common" }
swc_ecma_ast = { path = "../ecmascript/ast" }
swc_ecma_codegen = { path = "../ecmascript/codegen" }

View File

@ -47,88 +47,114 @@ impl Load for SwcLoader {
log::trace!("JsLoader.load: loaded");
let mut config = self.compiler.config_for_file(
&swc::config::Options {
config: {
if let Some(c) = &self.options.config {
Some(swc::config::Config {
jsc: JscConfig {
transform: {
if let Some(c) = &c.jsc.transform {
Some(TransformConfig {
react: c.react.clone(),
const_modules: c.const_modules.clone(),
optimizer: None,
legacy_decorator: c.legacy_decorator,
decorator_metadata: c.decorator_metadata,
})
} else {
None
}
let program = if fm.name.to_string().contains("node_modules") {
let program = self.compiler.parse_js(
fm.clone(),
JscTarget::Es2020,
Default::default(),
true,
true,
)?;
let program = helpers::HELPERS.set(&Helpers::new(true), || {
swc_ecma_utils::HANDLER.set(&self.compiler.handler, || {
let program = program.fold_with(&mut InlineGlobals {
envs: env_map(),
globals: Default::default(),
});
let program = program.fold_with(&mut expr_simplifier());
let program = program.fold_with(&mut dead_branch_remover());
program
})
});
program
} else {
let mut config = self.compiler.config_for_file(
&swc::config::Options {
config: {
if let Some(c) = &self.options.config {
Some(swc::config::Config {
jsc: JscConfig {
transform: {
if let Some(c) = &c.jsc.transform {
Some(TransformConfig {
react: c.react.clone(),
const_modules: c.const_modules.clone(),
optimizer: None,
legacy_decorator: c.legacy_decorator,
decorator_metadata: c.decorator_metadata,
})
} else {
None
}
},
external_helpers: true,
..c.jsc
},
external_helpers: true,
..c.jsc
},
module: None,
minify: Some(false),
..c.clone()
})
} else {
None
}
module: None,
minify: Some(false),
..c.clone()
})
} else {
None
}
},
disable_hygiene: false,
disable_fixer: true,
global_mark: self.options.global_mark,
cwd: self.options.cwd.clone(),
caller: None,
filename: String::new(),
config_file: None,
root: None,
root_mode: Default::default(),
swcrc: true,
swcrc_roots: Default::default(),
env_name: {
let s = env::var("NODE_ENV").unwrap_or_else(|_| "development".into());
s
},
input_source_map: InputSourceMap::Bool(false),
source_maps: None,
source_file_name: None,
source_root: None,
is_module: true,
},
disable_hygiene: false,
disable_fixer: true,
global_mark: self.options.global_mark,
cwd: self.options.cwd.clone(),
caller: None,
filename: String::new(),
config_file: None,
root: None,
root_mode: Default::default(),
swcrc: true,
swcrc_roots: Default::default(),
env_name: {
let s = env::var("NODE_ENV").unwrap_or_else(|_| "development".into());
s
},
input_source_map: InputSourceMap::Bool(false),
source_maps: None,
source_file_name: None,
source_root: None,
is_module: true,
},
&fm.name,
)?;
&fm.name,
)?;
log::trace!("JsLoader.load: loaded config");
log::trace!("JsLoader.load: loaded config");
// We run transform at this phase to strip out unused dependencies.
//
// Note that we don't apply compat transform at loading phase.
let program =
self.compiler
.parse_js(fm.clone(), JscTarget::Es2020, config.syntax, true, true)?;
// We run transform at this phase to strip out unused dependencies.
//
// Note that we don't apply compat transform at loading phase.
let program =
self.compiler
.parse_js(fm.clone(), JscTarget::Es2020, config.syntax, true, true)?;
log::trace!("JsLoader.load: parsed");
log::trace!("JsLoader.load: parsed");
// Fold module
let program = helpers::HELPERS.set(&Helpers::new(true), || {
swc_ecma_utils::HANDLER.set(&self.compiler.handler, || {
let program = program.fold_with(&mut InlineGlobals {
envs: env_map(),
globals: Default::default(),
});
let program = program.fold_with(&mut expr_simplifier());
let program = program.fold_with(&mut dead_branch_remover());
// Fold module
let program = helpers::HELPERS.set(&Helpers::new(true), || {
swc_ecma_utils::HANDLER.set(&self.compiler.handler, || {
let program = program.fold_with(&mut InlineGlobals {
envs: env_map(),
globals: Default::default(),
});
let program = program.fold_with(&mut expr_simplifier());
let program = program.fold_with(&mut dead_branch_remover());
let program = program.fold_with(&mut config.pass);
let program = program.fold_with(&mut config.pass);
program
})
});
program
})
});
log::trace!("JsLoader.load: applied transforms");
log::trace!("JsLoader.load: applied transforms");
program
};
match program {
Program::Module(module) => Ok((fm, module)),

View File

@ -0,0 +1,10 @@
{
"jsc": {
"target": "es2016",
"parser": {
"syntax": "ecmascript",
"dynamicImport": true,
"exportNamespaceFrom": true
}
}
}

View File

@ -0,0 +1,3 @@
export * as b from './b'
console.log('a');

View File

@ -0,0 +1,3 @@
export const b = 1;
console.log('b');

View File

@ -0,0 +1 @@
export { b } from './a'

View File

@ -0,0 +1,3 @@
export { default as a } from './b';
console.log('a.js');

View File

@ -0,0 +1,5 @@
const b = 1;
export default b;
console.log('b')

View File

@ -0,0 +1,3 @@
export { a } from './a';
console.log('entry');

View File

@ -0,0 +1,7 @@
const b = 1;
const __default = b;
console.log('b');
const a = __default;
console.log('a.js');
export { a };
console.log('entry');

View File

@ -0,0 +1,3 @@
export { b as a } from './b'
console.log('a');

View File

@ -0,0 +1,3 @@
export const b = 1;
console.log('b', b);

View File

@ -0,0 +1 @@
export { a } from './a'

View File

@ -0,0 +1,6 @@
const b = 1;
console.log('b', b);
const b1 = b;
const a = b1;
console.log('a');
export { a };

View File

@ -0,0 +1,3 @@
export { b } from './b'
console.log('a');

View File

@ -0,0 +1,3 @@
export const b = 1;
console.log('b', b);

View File

@ -0,0 +1 @@
export { b as a } from './a'

View File

@ -0,0 +1,6 @@
const b = 1;
console.log('b', b);
const b1 = b;
const b2 = b1;
console.log('a');
export { b2 as a };

View File

@ -0,0 +1,3 @@
export { b } from './b'
console.log('a');

View File

@ -0,0 +1,3 @@
export { c as b } from './c'
console.log('b');

View File

@ -0,0 +1,3 @@
export const c = 1;
console.log('c', c);

View File

@ -0,0 +1,3 @@
export { b as a } from './a'
console.log('entry')

View File

@ -0,0 +1,9 @@
const c = 1;
console.log('c', c);
const c1 = c;
const b = c1;
console.log('b');
const b1 = b;
console.log('a');
export { b1 as a };
console.log('entry');

View File

@ -0,0 +1,3 @@
export { b as a } from './b'
console.log('a');

View File

@ -0,0 +1,3 @@
export { c as b } from './c'
console.log('b');

View File

@ -0,0 +1,3 @@
export const c = 1;
console.log('c', c);

View File

@ -0,0 +1,3 @@
export { a } from './a'
console.log('entry')

View File

@ -0,0 +1,9 @@
const c = 1;
console.log('c', c);
const c1 = c;
const b = c1;
console.log('b');
const a = b;
console.log('a');
export { a };
console.log('entry');

View File

@ -0,0 +1,3 @@
export { b } from './b'
console.log('a');

View File

@ -0,0 +1,5 @@
export function b() {
console.log(b);
}
console.log('b', b);

View File

@ -0,0 +1 @@
export { b as a } from './a'

View File

@ -0,0 +1,8 @@
function b() {
console.log(b);
}
console.log('b', b);
const b1 = b;
const b2 = b1;
console.log('a');
export { b2 as a };

View File

@ -0,0 +1,3 @@
export { b } from './b'
console.log('a');

View File

@ -0,0 +1,3 @@
export class b { }
console.log('b', b);

View File

@ -0,0 +1 @@
export { b as a } from './a'

View File

@ -0,0 +1,7 @@
class b {
}
console.log('b', b);
const b1 = b;
const b2 = b1;
console.log('a');
export { b2 as a };

View File

@ -0,0 +1,3 @@
export { default as b } from './b';
console.log('a.js');

View File

@ -0,0 +1,4 @@
import { c as b } from './c';
export default b;
console.log('b')

View File

@ -0,0 +1,3 @@
export { d as c } from './d'
console.log('c')

View File

@ -0,0 +1,5 @@
import { e as d } from './e';
export { d }
console.log('d')

View File

@ -0,0 +1,2 @@
export const e = 'e';
console.log('e')

View File

@ -0,0 +1,3 @@
export { b } from './a'
console.log('entry');

View File

@ -0,0 +1,12 @@
const d = 'e';
console.log('e');
const d1 = d;
console.log('d');
const b = d1;
console.log('c');
const __default = b;
console.log('b');
const b1 = __default;
console.log('a.js');
export { b1 as b };
console.log('entry');