mirror of
https://github.com/swc-project/swc.git
synced 2024-11-23 00:32:15 +03:00
Improve spack (#972)
swd_bundler: - Handle reexports spack: - Do not transform files from node_modules
This commit is contained in:
parent
73878728aa
commit
28398280f7
@ -47,7 +47,7 @@ name = "usage"
|
||||
codegen-units = 1
|
||||
lto = true
|
||||
# debug = true
|
||||
opt-level = 'z'
|
||||
# opt-level = 'z'
|
||||
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
|
@ -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"
|
||||
|
@ -116,6 +116,7 @@ where
|
||||
mark: circular_module.mark(),
|
||||
specifiers: &specifiers,
|
||||
excluded: vec![],
|
||||
is_export: false,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
365
bundler/src/bundler/chunk/export.rs
Normal file
365
bundler/src/bundler/chunk/export.rs
Normal 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) {}
|
||||
}
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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 },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 => {}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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" }
|
||||
|
@ -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)),
|
||||
|
10
spack/tests/pass/reexport/.namespace/input/.swcrc
Normal file
10
spack/tests/pass/reexport/.namespace/input/.swcrc
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"jsc": {
|
||||
"target": "es2016",
|
||||
"parser": {
|
||||
"syntax": "ecmascript",
|
||||
"dynamicImport": true,
|
||||
"exportNamespaceFrom": true
|
||||
}
|
||||
}
|
||||
}
|
3
spack/tests/pass/reexport/.namespace/input/a.js
Normal file
3
spack/tests/pass/reexport/.namespace/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export * as b from './b'
|
||||
|
||||
console.log('a');
|
3
spack/tests/pass/reexport/.namespace/input/b.js
Normal file
3
spack/tests/pass/reexport/.namespace/input/b.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const b = 1;
|
||||
|
||||
console.log('b');
|
1
spack/tests/pass/reexport/.namespace/input/entry.js
Normal file
1
spack/tests/pass/reexport/.namespace/input/entry.js
Normal file
@ -0,0 +1 @@
|
||||
export { b } from './a'
|
3
spack/tests/pass/reexport/default-1-simple/input/a.js
Normal file
3
spack/tests/pass/reexport/default-1-simple/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as a } from './b';
|
||||
|
||||
console.log('a.js');
|
5
spack/tests/pass/reexport/default-1-simple/input/b.js
Normal file
5
spack/tests/pass/reexport/default-1-simple/input/b.js
Normal file
@ -0,0 +1,5 @@
|
||||
const b = 1;
|
||||
|
||||
export default b;
|
||||
|
||||
console.log('b')
|
@ -0,0 +1,3 @@
|
||||
export { a } from './a';
|
||||
|
||||
console.log('entry');
|
@ -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');
|
3
spack/tests/pass/reexport/named-1-alias/input/a.js
Normal file
3
spack/tests/pass/reexport/named-1-alias/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b as a } from './b'
|
||||
|
||||
console.log('a');
|
3
spack/tests/pass/reexport/named-1-alias/input/b.js
Normal file
3
spack/tests/pass/reexport/named-1-alias/input/b.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const b = 1;
|
||||
|
||||
console.log('b', b);
|
1
spack/tests/pass/reexport/named-1-alias/input/entry.js
Normal file
1
spack/tests/pass/reexport/named-1-alias/input/entry.js
Normal file
@ -0,0 +1 @@
|
||||
export { a } from './a'
|
6
spack/tests/pass/reexport/named-1-alias/output/entry.js
Normal file
6
spack/tests/pass/reexport/named-1-alias/output/entry.js
Normal file
@ -0,0 +1,6 @@
|
||||
const b = 1;
|
||||
console.log('b', b);
|
||||
const b1 = b;
|
||||
const a = b1;
|
||||
console.log('a');
|
||||
export { a };
|
3
spack/tests/pass/reexport/named-1-orig/input/a.js
Normal file
3
spack/tests/pass/reexport/named-1-orig/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b } from './b'
|
||||
|
||||
console.log('a');
|
3
spack/tests/pass/reexport/named-1-orig/input/b.js
Normal file
3
spack/tests/pass/reexport/named-1-orig/input/b.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const b = 1;
|
||||
|
||||
console.log('b', b);
|
1
spack/tests/pass/reexport/named-1-orig/input/entry.js
Normal file
1
spack/tests/pass/reexport/named-1-orig/input/entry.js
Normal file
@ -0,0 +1 @@
|
||||
export { b as a } from './a'
|
6
spack/tests/pass/reexport/named-1-orig/output/entry.js
Normal file
6
spack/tests/pass/reexport/named-1-orig/output/entry.js
Normal 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 };
|
3
spack/tests/pass/reexport/named-2-nested/input/a.js
Normal file
3
spack/tests/pass/reexport/named-2-nested/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b } from './b'
|
||||
|
||||
console.log('a');
|
3
spack/tests/pass/reexport/named-2-nested/input/b.js
Normal file
3
spack/tests/pass/reexport/named-2-nested/input/b.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { c as b } from './c'
|
||||
|
||||
console.log('b');
|
3
spack/tests/pass/reexport/named-2-nested/input/c.js
Normal file
3
spack/tests/pass/reexport/named-2-nested/input/c.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const c = 1;
|
||||
|
||||
console.log('c', c);
|
3
spack/tests/pass/reexport/named-2-nested/input/entry.js
Normal file
3
spack/tests/pass/reexport/named-2-nested/input/entry.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b as a } from './a'
|
||||
|
||||
console.log('entry')
|
9
spack/tests/pass/reexport/named-2-nested/output/entry.js
Normal file
9
spack/tests/pass/reexport/named-2-nested/output/entry.js
Normal 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');
|
3
spack/tests/pass/reexport/named-3-var/input/a.js
Normal file
3
spack/tests/pass/reexport/named-3-var/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b as a } from './b'
|
||||
|
||||
console.log('a');
|
3
spack/tests/pass/reexport/named-3-var/input/b.js
Normal file
3
spack/tests/pass/reexport/named-3-var/input/b.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { c as b } from './c'
|
||||
|
||||
console.log('b');
|
3
spack/tests/pass/reexport/named-3-var/input/c.js
Normal file
3
spack/tests/pass/reexport/named-3-var/input/c.js
Normal file
@ -0,0 +1,3 @@
|
||||
export const c = 1;
|
||||
|
||||
console.log('c', c);
|
3
spack/tests/pass/reexport/named-3-var/input/entry.js
Normal file
3
spack/tests/pass/reexport/named-3-var/input/entry.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { a } from './a'
|
||||
|
||||
console.log('entry')
|
9
spack/tests/pass/reexport/named-3-var/output/entry.js
Normal file
9
spack/tests/pass/reexport/named-3-var/output/entry.js
Normal 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');
|
3
spack/tests/pass/reexport/named-4-fn/input/a.js
Normal file
3
spack/tests/pass/reexport/named-4-fn/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b } from './b'
|
||||
|
||||
console.log('a');
|
5
spack/tests/pass/reexport/named-4-fn/input/b.js
Normal file
5
spack/tests/pass/reexport/named-4-fn/input/b.js
Normal file
@ -0,0 +1,5 @@
|
||||
export function b() {
|
||||
console.log(b);
|
||||
}
|
||||
|
||||
console.log('b', b);
|
1
spack/tests/pass/reexport/named-4-fn/input/entry.js
Normal file
1
spack/tests/pass/reexport/named-4-fn/input/entry.js
Normal file
@ -0,0 +1 @@
|
||||
export { b as a } from './a'
|
8
spack/tests/pass/reexport/named-4-fn/output/entry.js
Normal file
8
spack/tests/pass/reexport/named-4-fn/output/entry.js
Normal 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 };
|
3
spack/tests/pass/reexport/named-5-class/input/a.js
Normal file
3
spack/tests/pass/reexport/named-5-class/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b } from './b'
|
||||
|
||||
console.log('a');
|
3
spack/tests/pass/reexport/named-5-class/input/b.js
Normal file
3
spack/tests/pass/reexport/named-5-class/input/b.js
Normal file
@ -0,0 +1,3 @@
|
||||
export class b { }
|
||||
|
||||
console.log('b', b);
|
1
spack/tests/pass/reexport/named-5-class/input/entry.js
Normal file
1
spack/tests/pass/reexport/named-5-class/input/entry.js
Normal file
@ -0,0 +1 @@
|
||||
export { b as a } from './a'
|
7
spack/tests/pass/reexport/named-5-class/output/entry.js
Normal file
7
spack/tests/pass/reexport/named-5-class/output/entry.js
Normal file
@ -0,0 +1,7 @@
|
||||
class b {
|
||||
}
|
||||
console.log('b', b);
|
||||
const b1 = b;
|
||||
const b2 = b1;
|
||||
console.log('a');
|
||||
export { b2 as a };
|
3
spack/tests/pass/reexport/recursive/input/a.js
Normal file
3
spack/tests/pass/reexport/recursive/input/a.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { default as b } from './b';
|
||||
|
||||
console.log('a.js');
|
4
spack/tests/pass/reexport/recursive/input/b.js
Normal file
4
spack/tests/pass/reexport/recursive/input/b.js
Normal file
@ -0,0 +1,4 @@
|
||||
import { c as b } from './c';
|
||||
export default b;
|
||||
|
||||
console.log('b')
|
3
spack/tests/pass/reexport/recursive/input/c.js
Normal file
3
spack/tests/pass/reexport/recursive/input/c.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { d as c } from './d'
|
||||
|
||||
console.log('c')
|
5
spack/tests/pass/reexport/recursive/input/d.js
Normal file
5
spack/tests/pass/reexport/recursive/input/d.js
Normal file
@ -0,0 +1,5 @@
|
||||
import { e as d } from './e';
|
||||
|
||||
export { d }
|
||||
|
||||
console.log('d')
|
2
spack/tests/pass/reexport/recursive/input/e.js
Normal file
2
spack/tests/pass/reexport/recursive/input/e.js
Normal file
@ -0,0 +1,2 @@
|
||||
export const e = 'e';
|
||||
console.log('e')
|
3
spack/tests/pass/reexport/recursive/input/entry.js
Normal file
3
spack/tests/pass/reexport/recursive/input/entry.js
Normal file
@ -0,0 +1,3 @@
|
||||
export { b } from './a'
|
||||
|
||||
console.log('entry');
|
12
spack/tests/pass/reexport/recursive/output/entry.js
Normal file
12
spack/tests/pass/reexport/recursive/output/entry.js
Normal 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');
|
Loading…
Reference in New Issue
Block a user