mirror of
https://github.com/swc-project/swc.git
synced 2024-10-05 04:39:06 +03:00
bundler: Handle swc helpers (#1199)
swc_bundler: - Handle helpers from `swc_ecma_transforms`. swc_ecma_transforms: - dce: Remove unused self-referential functions.
This commit is contained in:
parent
64942b5006
commit
0a5e23f97c
@ -8,7 +8,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_bundler"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.15.0"
|
||||
version = "0.16.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
@ -33,7 +33,7 @@ swc_common = {version = "0.10.0", path = "../common"}
|
||||
swc_ecma_ast = {version = "0.34.0", path = "../ecmascript/ast"}
|
||||
swc_ecma_codegen = {version = "0.40.0", path = "../ecmascript/codegen"}
|
||||
swc_ecma_parser = {version = "0.42.0", path = "../ecmascript/parser"}
|
||||
swc_ecma_transforms = {version = "0.29.1", path = "../ecmascript/transforms"}
|
||||
swc_ecma_transforms = {version = "0.29.3", path = "../ecmascript/transforms"}
|
||||
swc_ecma_utils = {version = "0.24.0", path = "../ecmascript/utils"}
|
||||
swc_ecma_visit = {version = "0.20.0", path = "../ecmascript/visit"}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use anyhow::Error;
|
||||
use std::{collections::HashMap, io::stdout};
|
||||
use swc_bundler::{BundleKind, Bundler, Config, Hook, Load, ModuleRecord, Resolve};
|
||||
use swc_bundler::{BundleKind, Bundler, Config, Hook, Load, ModuleData, ModuleRecord, Resolve};
|
||||
use swc_common::{sync::Lrc, FileName, FilePathMapping, Globals, SourceMap, Span};
|
||||
use swc_ecma_ast::KeyValueProp;
|
||||
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};
|
||||
@ -59,10 +59,7 @@ struct PathLoader {
|
||||
}
|
||||
|
||||
impl Load for PathLoader {
|
||||
fn load(
|
||||
&self,
|
||||
file: &FileName,
|
||||
) -> Result<(Lrc<swc_common::SourceFile>, swc_ecma_ast::Module), Error> {
|
||||
fn load(&self, file: &FileName) -> Result<ModuleData, Error> {
|
||||
let file = match file {
|
||||
FileName::Real(v) => v,
|
||||
_ => unreachable!(),
|
||||
@ -81,7 +78,11 @@ impl Load for PathLoader {
|
||||
let mut parser = Parser::new_from(lexer);
|
||||
let module = parser.parse_module().expect("This should not happen");
|
||||
|
||||
Ok((fm, module))
|
||||
Ok(ModuleData {
|
||||
fm,
|
||||
module,
|
||||
helpers: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
struct PathResolver;
|
||||
|
@ -151,17 +151,18 @@ where
|
||||
let deps = reexports
|
||||
.into_par_iter()
|
||||
.map(|(src, specifiers)| -> Result<_, Error> {
|
||||
let imported = self.scope.get_module(src.module_id).unwrap();
|
||||
assert!(imported.is_es6, "Reexports are es6 only");
|
||||
|
||||
info.helpers.extend(&imported.helpers);
|
||||
info.swc_helpers.extend_from(&imported.swc_helpers);
|
||||
|
||||
if !merged.insert(src.module_id) {
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
log::debug!("Merging exports: {} <- {}", info.fm.name, src.src.value);
|
||||
|
||||
let imported = self.scope.get_module(src.module_id).unwrap();
|
||||
assert!(imported.is_es6, "Reexports are es6 only");
|
||||
|
||||
info.helpers.extend(&imported.helpers);
|
||||
|
||||
let mut dep = self
|
||||
.merge_modules(plan, src.module_id, false, false, merged)
|
||||
.with_context(|| {
|
||||
|
@ -138,6 +138,10 @@ where
|
||||
.into_par_iter()
|
||||
.map(|(src, specifiers)| -> Result<Option<_>, Error> {
|
||||
self.run(|| {
|
||||
let dep_info = self.scope.get_module(src.module_id).unwrap();
|
||||
info.helpers.extend(&dep_info.helpers);
|
||||
info.swc_helpers.extend_from(&dep_info.swc_helpers);
|
||||
|
||||
if !merged.insert(src.module_id) {
|
||||
log::debug!("Skipping: {} <= {}", info.fm.name, src.src.value);
|
||||
return Ok(None);
|
||||
@ -145,8 +149,6 @@ where
|
||||
|
||||
log::debug!("Merging: {} <= {}", info.fm.name, src.src.value);
|
||||
|
||||
let dep_info = self.scope.get_module(src.module_id).unwrap();
|
||||
info.helpers.extend(&dep_info.helpers);
|
||||
// In the case of
|
||||
//
|
||||
// a <- b
|
||||
|
@ -8,7 +8,11 @@ use std::{
|
||||
use swc_atoms::js_word;
|
||||
use swc_common::{util::move_map::MoveMap, FileName, DUMMY_SP};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_transforms::{fixer, hygiene};
|
||||
use swc_ecma_transforms::{
|
||||
fixer,
|
||||
helpers::{inject_helpers, HELPERS},
|
||||
hygiene,
|
||||
};
|
||||
use swc_ecma_utils::{find_ids, private_ident, ExprFactory};
|
||||
use swc_ecma_visit::{noop_fold_type, noop_visit_type, Fold, FoldWith, Node, Visit, VisitWith};
|
||||
|
||||
@ -29,12 +33,27 @@ where
|
||||
|
||||
for mut bundle in bundles {
|
||||
bundle.module = self.optimize(bundle.module);
|
||||
bundle.module = self.may_wrap_with_iife(bundle.module);
|
||||
|
||||
bundle.module = bundle.module.fold_with(&mut hygiene());
|
||||
|
||||
bundle.module = bundle.module.fold_with(&mut fixer(None));
|
||||
|
||||
{
|
||||
// Inject swc helpers
|
||||
let swc_helpers = self
|
||||
.scope
|
||||
.get_module(bundle.id)
|
||||
.expect("module should exist at this point")
|
||||
.swc_helpers;
|
||||
|
||||
let module = bundle.module;
|
||||
|
||||
bundle.module =
|
||||
HELPERS.set(&swc_helpers, || module.fold_with(&mut inject_helpers()));
|
||||
}
|
||||
|
||||
bundle.module = self.may_wrap_with_iife(bundle.module);
|
||||
|
||||
match bundle.kind {
|
||||
BundleKind::Named { .. } => {
|
||||
// Inject helpers
|
||||
@ -44,7 +63,7 @@ where
|
||||
.expect("module should exist at this point")
|
||||
.helpers;
|
||||
|
||||
helpers.append_to(&mut bundle.module.body);
|
||||
helpers.add_to(&mut bundle.module.body);
|
||||
|
||||
new.push(Bundle { ..bundle });
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ impl Helpers {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn append_to(&self, to: &mut Vec<ModuleItem>) {
|
||||
pub fn add_to(&self, to: &mut Vec<ModuleItem>) {
|
||||
let mut buf = vec![];
|
||||
|
||||
if self.require.load(SeqCst) {
|
||||
|
@ -2,6 +2,7 @@ use super::{export::Exports, helpers::Helpers, Bundler};
|
||||
use crate::{
|
||||
bundler::{export::RawExports, import::RawImports},
|
||||
id::{Id, ModuleId},
|
||||
load::ModuleData,
|
||||
util,
|
||||
util::IntoParallelIterator,
|
||||
Load, Resolve,
|
||||
@ -33,6 +34,8 @@ pub(super) struct TransformedModule {
|
||||
/// Used helpers
|
||||
pub helpers: Lrc<Helpers>,
|
||||
|
||||
pub swc_helpers: Lrc<swc_ecma_transforms::helpers::Helpers>,
|
||||
|
||||
mark: Mark,
|
||||
}
|
||||
|
||||
@ -69,9 +72,9 @@ where
|
||||
return Ok(Some(cached));
|
||||
}
|
||||
|
||||
let (_, fm, module) = self.load(&file_name).context("Bundler.load() failed")?;
|
||||
let (_, data) = self.load(&file_name).context("Bundler.load() failed")?;
|
||||
let (v, mut files) = self
|
||||
.analyze(&file_name, fm.clone(), module)
|
||||
.analyze(&file_name, data)
|
||||
.context("failed to analyze module")?;
|
||||
files.dedup_by_key(|v| v.1.clone());
|
||||
|
||||
@ -96,16 +99,16 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
fn load(&self, file_name: &FileName) -> Result<(ModuleId, Lrc<SourceFile>, Module), Error> {
|
||||
fn load(&self, file_name: &FileName) -> Result<(ModuleId, ModuleData), Error> {
|
||||
self.run(|| {
|
||||
let (module_id, _) = self.scope.module_id_gen.gen(file_name);
|
||||
|
||||
let (fm, module) = self
|
||||
let data = self
|
||||
.loader
|
||||
.load(&file_name)
|
||||
.with_context(|| format!("Bundler.loader.load({}) failed", file_name))?;
|
||||
self.scope.mark_as_loaded(module_id);
|
||||
Ok((module_id, fm, module))
|
||||
Ok((module_id, data))
|
||||
})
|
||||
}
|
||||
|
||||
@ -113,14 +116,13 @@ where
|
||||
fn analyze(
|
||||
&self,
|
||||
file_name: &FileName,
|
||||
fm: Lrc<SourceFile>,
|
||||
mut module: Module,
|
||||
data: ModuleData,
|
||||
) -> Result<(TransformedModule, Vec<(Source, Lrc<FileName>)>), Error> {
|
||||
self.run(|| {
|
||||
log::trace!("transform_module({})", fm.name);
|
||||
log::trace!("transform_module({})", data.fm.name);
|
||||
let (id, mark) = self.scope.module_id_gen.gen(file_name);
|
||||
|
||||
module = module.fold_with(&mut resolver_with_mark(mark));
|
||||
let mut module = data.module.fold_with(&mut resolver_with_mark(mark));
|
||||
|
||||
// {
|
||||
// let code = self
|
||||
@ -180,13 +182,14 @@ where
|
||||
Ok((
|
||||
TransformedModule {
|
||||
id,
|
||||
fm,
|
||||
fm: data.fm,
|
||||
module,
|
||||
imports: Lrc::new(imports),
|
||||
exports: Lrc::new(exports),
|
||||
is_es6,
|
||||
helpers: Default::default(),
|
||||
mark,
|
||||
swc_helpers: Lrc::new(data.helpers),
|
||||
},
|
||||
import_files,
|
||||
))
|
||||
|
@ -1,9 +1,9 @@
|
||||
//! Utilities for testing.
|
||||
use super::{load::TransformedModule, Bundler, Config};
|
||||
use crate::{util::HygieneRemover, Load, ModuleId, ModuleRecord, Resolve};
|
||||
use crate::{load::ModuleData, util::HygieneRemover, Load, ModuleId, ModuleRecord, Resolve};
|
||||
use anyhow::Error;
|
||||
use std::{collections::HashMap, path::PathBuf};
|
||||
use swc_common::{sync::Lrc, FileName, SourceFile, SourceMap, Span, GLOBALS};
|
||||
use swc_common::{sync::Lrc, FileName, SourceMap, Span, GLOBALS};
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_parser::{lexer::Lexer, JscTarget, Parser, StringInput};
|
||||
use swc_ecma_utils::drop_span;
|
||||
@ -20,7 +20,7 @@ pub struct Loader {
|
||||
}
|
||||
|
||||
impl Load for Loader {
|
||||
fn load(&self, f: &FileName) -> Result<(Lrc<SourceFile>, Module), Error> {
|
||||
fn load(&self, f: &FileName) -> Result<ModuleData, Error> {
|
||||
eprintln!("load: {}", f);
|
||||
let v = self.files.get(&f.to_string());
|
||||
let v = v.unwrap();
|
||||
@ -37,7 +37,11 @@ impl Load for Loader {
|
||||
let mut parser = Parser::new_from(lexer);
|
||||
let module = parser.parse_module().unwrap();
|
||||
|
||||
Ok((fm, module))
|
||||
Ok(ModuleData {
|
||||
fm,
|
||||
module,
|
||||
helpers: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@ pub use self::{
|
||||
bundler::{Bundle, BundleKind, Bundler, Config, ModuleType},
|
||||
hook::{Hook, ModuleRecord},
|
||||
id::ModuleId,
|
||||
load::Load,
|
||||
load::{Load, ModuleData},
|
||||
resolve::Resolve,
|
||||
};
|
||||
|
||||
|
@ -1,6 +1,35 @@
|
||||
use anyhow::Error;
|
||||
use swc_common::{sync::Lrc, FileName, SourceFile};
|
||||
use swc_ecma_ast::Module;
|
||||
use swc_ecma_transforms::helpers::Helpers;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ModuleData {
|
||||
pub fm: Lrc<SourceFile>,
|
||||
pub module: Module,
|
||||
/// Used helpers
|
||||
///
|
||||
/// # Exmaple
|
||||
///
|
||||
/// ```rust,ignore
|
||||
///
|
||||
/// impl Load for Loader {
|
||||
/// fn load(&self, name: &FileName) -> Result<ModuleData, Error> {
|
||||
/// let helpers = Helpers::new(false);
|
||||
/// let fm = self.load_file(name)?;
|
||||
/// let module = self.parse(fm.clone())?;
|
||||
///
|
||||
/// let module = helpers::HELPERS.set(&helpers, || {
|
||||
/// // Apply transforms (like decorators pass)
|
||||
/// module
|
||||
/// });
|
||||
///
|
||||
/// Ok(ModuleData { fm, module, helpers })
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
pub helpers: Helpers,
|
||||
}
|
||||
|
||||
/// Responsible for providing files to the bundler.
|
||||
///
|
||||
@ -11,17 +40,17 @@ use swc_ecma_ast::Module;
|
||||
///
|
||||
/// This trait is designed to allow passing pre-parsed module.
|
||||
pub trait Load: swc_common::sync::Send + swc_common::sync::Sync {
|
||||
fn load(&self, file: &FileName) -> Result<(Lrc<SourceFile>, Module), Error>;
|
||||
fn load(&self, file: &FileName) -> Result<ModuleData, Error>;
|
||||
}
|
||||
|
||||
impl<T: ?Sized + Load> Load for Box<T> {
|
||||
fn load(&self, file: &FileName) -> Result<(Lrc<SourceFile>, Module), Error> {
|
||||
fn load(&self, file: &FileName) -> Result<ModuleData, Error> {
|
||||
(**self).load(file)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized + Load> Load for &'a T {
|
||||
fn load(&self, file: &FileName) -> Result<(Lrc<SourceFile>, Module), Error> {
|
||||
fn load(&self, file: &FileName) -> Result<ModuleData, Error> {
|
||||
(**self).load(file)
|
||||
}
|
||||
}
|
||||
|
@ -12,11 +12,10 @@ use std::{
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
use swc_atoms::js_word;
|
||||
use swc_bundler::{Bundler, Load, ModuleRecord, Resolve};
|
||||
use swc_common::{sync::Lrc, FileName, SourceFile, SourceMap, Span, GLOBALS};
|
||||
use swc_bundler::{Bundler, Load, ModuleData, ModuleRecord, Resolve};
|
||||
use swc_common::{sync::Lrc, FileName, SourceMap, Span, GLOBALS};
|
||||
use swc_ecma_ast::{
|
||||
Bool, Expr, ExprOrSuper, Ident, KeyValueProp, Lit, MemberExpr, MetaPropExpr, Module, PropName,
|
||||
Str,
|
||||
Bool, Expr, ExprOrSuper, Ident, KeyValueProp, Lit, MemberExpr, MetaPropExpr, PropName, Str,
|
||||
};
|
||||
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};
|
||||
use swc_ecma_parser::{lexer::Lexer, JscTarget, Parser, StringInput, Syntax, TsConfig};
|
||||
@ -185,7 +184,7 @@ fn load_url(url: Url) -> Result<String, Error> {
|
||||
}
|
||||
|
||||
impl Load for Loader {
|
||||
fn load(&self, file: &FileName) -> Result<(Lrc<SourceFile>, Module), Error> {
|
||||
fn load(&self, file: &FileName) -> Result<ModuleData, Error> {
|
||||
eprintln!("{}", file);
|
||||
|
||||
let url = match file {
|
||||
@ -218,7 +217,11 @@ impl Load for Loader {
|
||||
}));
|
||||
let module = module.fold_with(&mut strip());
|
||||
|
||||
Ok((fm, module))
|
||||
Ok(ModuleData {
|
||||
fm,
|
||||
module,
|
||||
helpers: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,11 +12,10 @@ use std::{
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
use swc_atoms::js_word;
|
||||
use swc_bundler::{BundleKind, Bundler, Config, Load, ModuleRecord, Resolve};
|
||||
use swc_common::{sync::Lrc, FileName, Globals, SourceFile, SourceMap, Span};
|
||||
use swc_bundler::{BundleKind, Bundler, Config, Load, ModuleData, ModuleRecord, Resolve};
|
||||
use swc_common::{sync::Lrc, FileName, Globals, SourceMap, Span};
|
||||
use swc_ecma_ast::{
|
||||
Bool, Expr, ExprOrSuper, Ident, KeyValueProp, Lit, MemberExpr, MetaPropExpr, Module, PropName,
|
||||
Str,
|
||||
Bool, Expr, ExprOrSuper, Ident, KeyValueProp, Lit, MemberExpr, MetaPropExpr, PropName, Str,
|
||||
};
|
||||
use swc_ecma_codegen::{text_writer::JsWriter, Emitter};
|
||||
use swc_ecma_parser::{lexer::Lexer, JscTarget, Parser, StringInput, Syntax, TsConfig};
|
||||
@ -291,7 +290,7 @@ pub struct Loader {
|
||||
}
|
||||
|
||||
impl Load for Loader {
|
||||
fn load(&self, f: &FileName) -> Result<(Lrc<SourceFile>, Module), Error> {
|
||||
fn load(&self, f: &FileName) -> Result<ModuleData, Error> {
|
||||
eprintln!("load: {}", f);
|
||||
|
||||
let fm = self.cm.load_file(match f {
|
||||
@ -314,7 +313,11 @@ impl Load for Loader {
|
||||
|
||||
let module = module.fold_with(&mut strip());
|
||||
|
||||
Ok((fm, module))
|
||||
Ok(ModuleData {
|
||||
fm,
|
||||
module,
|
||||
helpers: Default::default(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecmascript"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.13.2"
|
||||
version = "0.13.3"
|
||||
|
||||
[features]
|
||||
codegen = ["swc_ecma_codegen"]
|
||||
@ -24,7 +24,7 @@ swc_ecma_ast = {version = "0.34.0", path = "./ast"}
|
||||
swc_ecma_codegen = {version = "0.40.0", path = "./codegen", optional = true}
|
||||
swc_ecma_dep_graph = {version = "0.8.0", path = "./dep-graph", optional = true}
|
||||
swc_ecma_parser = {version = "0.42.0", path = "./parser", optional = true}
|
||||
swc_ecma_transforms = {version = "0.29.1", path = "./transforms", optional = true}
|
||||
swc_ecma_transforms = {version = "0.29.3", path = "./transforms", optional = true}
|
||||
swc_ecma_utils = {version = "0.24.0", path = "./utils", optional = true}
|
||||
swc_ecma_visit = {version = "0.20.0", path = "./visit", optional = true}
|
||||
|
||||
|
@ -6,7 +6,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_ecma_transforms"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.29.2"
|
||||
version = "0.29.3"
|
||||
|
||||
[features]
|
||||
const-modules = ["dashmap"]
|
||||
|
@ -63,7 +63,7 @@ macro_rules! add_to {
|
||||
scoped_thread_local!(pub static HELPERS: Helpers);
|
||||
|
||||
/// Tracks used helper methods. (e.g. __extends)
|
||||
#[derive(Default)]
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Helpers {
|
||||
external: bool,
|
||||
mark: HelperMark,
|
||||
@ -78,6 +78,7 @@ impl Helpers {
|
||||
inner: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) const fn mark(&self) -> Mark {
|
||||
self.mark.0
|
||||
}
|
||||
@ -86,7 +87,7 @@ impl Helpers {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct HelperMark(Mark);
|
||||
impl Default for HelperMark {
|
||||
fn default() -> Self {
|
||||
@ -100,7 +101,7 @@ macro_rules! define_helpers {
|
||||
$( $name:ident : ( $( $dep:ident ),* ), )*
|
||||
}
|
||||
) => {
|
||||
#[derive(Default)]
|
||||
#[derive(Debug,Default)]
|
||||
struct Inner {
|
||||
$( $name: AtomicBool, )*
|
||||
}
|
||||
@ -117,6 +118,16 @@ macro_rules! define_helpers {
|
||||
)*
|
||||
}
|
||||
|
||||
impl Helpers {
|
||||
pub fn extend_from(&self, other: &Self) {
|
||||
$(
|
||||
if other.inner.$name.load(Ordering::SeqCst) {
|
||||
self.inner.$name.store(true, Ordering::Relaxed);
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
impl InjectHelpers {
|
||||
fn is_helper_used(&self) -> bool{
|
||||
let mut value = false;
|
||||
|
@ -61,6 +61,7 @@ pub fn dce<'a>(config: Config<'a>) -> impl RepeatedJsPass + 'a {
|
||||
changed: false,
|
||||
marking_phase: false,
|
||||
decl_dropping_phase: false,
|
||||
cur_defining: Default::default()
|
||||
}),
|
||||
as_folder(UsedMarkRemover { used_mark })
|
||||
)
|
||||
@ -112,6 +113,12 @@ struct Dce<'a> {
|
||||
decl_dropping_phase: bool,
|
||||
|
||||
dropped: bool,
|
||||
|
||||
/// Functions that we are currently defining.
|
||||
///
|
||||
/// Reference to function itself in a function should not make function
|
||||
/// preserved.
|
||||
cur_defining: FxHashSet<Id>,
|
||||
}
|
||||
|
||||
impl CompilerPass for Dce<'_> {
|
||||
@ -288,7 +295,12 @@ impl VisitMut for Dce<'_> {
|
||||
return;
|
||||
}
|
||||
|
||||
f.visit_mut_children_with(self)
|
||||
let id = f.ident.to_id();
|
||||
self.cur_defining.insert(id.clone());
|
||||
|
||||
f.visit_mut_children_with(self);
|
||||
|
||||
self.cur_defining.remove(&id);
|
||||
}
|
||||
|
||||
fn visit_mut_for_in_stmt(&mut self, node: &mut ForInStmt) {
|
||||
@ -361,7 +373,13 @@ impl VisitMut for Dce<'_> {
|
||||
}
|
||||
|
||||
if self.marking_phase {
|
||||
if self.included.insert(i.to_id()) {
|
||||
let id = i.to_id();
|
||||
// This is required to drop recursive functions.
|
||||
if self.cur_defining.contains(&id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.included.insert(id) {
|
||||
log::debug!("{} is used", i.sym);
|
||||
self.changed = true;
|
||||
}
|
||||
|
@ -8,6 +8,9 @@ macro_rules! external_name {
|
||||
("throw") => {
|
||||
"_throw"
|
||||
};
|
||||
("extends") => {
|
||||
"_extends"
|
||||
};
|
||||
($s:literal) => {
|
||||
$s
|
||||
};
|
||||
|
@ -775,3 +775,23 @@ test!(
|
||||
new A();
|
||||
"
|
||||
);
|
||||
|
||||
optimized_out!(
|
||||
self_referential_function_01,
|
||||
"
|
||||
function foo() {
|
||||
if (Math.random() > 0.5) {
|
||||
foo()
|
||||
}
|
||||
}
|
||||
"
|
||||
);
|
||||
|
||||
optimized_out!(
|
||||
pr_1199_01,
|
||||
"
|
||||
function _nonIterableSpread() {
|
||||
throw new TypeError('Invalid attempt to spread non-iterable instance');
|
||||
}
|
||||
"
|
||||
);
|
||||
|
@ -3,9 +3,9 @@ use helpers::Helpers;
|
||||
use std::{collections::HashMap, env, sync::Arc};
|
||||
use swc::config::{InputSourceMap, JscConfig, TransformConfig};
|
||||
use swc_atoms::JsWord;
|
||||
use swc_bundler::Load;
|
||||
use swc_common::{FileName, SourceFile, DUMMY_SP};
|
||||
use swc_ecma_ast::{Expr, Lit, Module, Program, Str};
|
||||
use swc_bundler::{Load, ModuleData};
|
||||
use swc_common::{FileName, DUMMY_SP};
|
||||
use swc_ecma_ast::{Expr, Lit, Program, Str};
|
||||
use swc_ecma_parser::JscTarget;
|
||||
use swc_ecma_transforms::{
|
||||
helpers,
|
||||
@ -33,8 +33,9 @@ impl SwcLoader {
|
||||
}
|
||||
|
||||
impl Load for SwcLoader {
|
||||
fn load(&self, name: &FileName) -> Result<(Arc<SourceFile>, Module), Error> {
|
||||
fn load(&self, name: &FileName) -> Result<ModuleData, Error> {
|
||||
log::debug!("JsLoader.load({})", name);
|
||||
let helpers = Helpers::new(false);
|
||||
|
||||
let fm = self
|
||||
.compiler
|
||||
@ -55,7 +56,7 @@ impl Load for SwcLoader {
|
||||
true,
|
||||
true,
|
||||
)?;
|
||||
let program = helpers::HELPERS.set(&Helpers::new(true), || {
|
||||
let program = helpers::HELPERS.set(&helpers, || {
|
||||
swc_ecma_utils::HANDLER.set(&self.compiler.handler, || {
|
||||
let program =
|
||||
program.fold_with(&mut inline_globals(env_map(), Default::default()));
|
||||
@ -99,6 +100,7 @@ impl Load for SwcLoader {
|
||||
None
|
||||
}
|
||||
},
|
||||
skip_helper_injection: true,
|
||||
disable_hygiene: false,
|
||||
disable_fixer: true,
|
||||
global_mark: self.options.global_mark,
|
||||
@ -135,7 +137,7 @@ impl Load for SwcLoader {
|
||||
log::trace!("JsLoader.load: parsed");
|
||||
|
||||
// Fold module
|
||||
let program = helpers::HELPERS.set(&Helpers::new(true), || {
|
||||
let program = helpers::HELPERS.set(&helpers, || {
|
||||
swc_ecma_utils::HANDLER.set(&self.compiler.handler, || {
|
||||
let program =
|
||||
program.fold_with(&mut inline_globals(env_map(), Default::default()));
|
||||
@ -154,7 +156,11 @@ impl Load for SwcLoader {
|
||||
};
|
||||
|
||||
match program {
|
||||
Program::Module(module) => Ok((fm, module)),
|
||||
Program::Module(module) => Ok(ModuleData {
|
||||
fm,
|
||||
module,
|
||||
helpers,
|
||||
}),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
8
spack/tests/pass/helpers/simple/input/.swcrc
Normal file
8
spack/tests/pass/helpers/simple/input/.swcrc
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"jsc": {
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"decorators": true
|
||||
}
|
||||
}
|
||||
}
|
2
spack/tests/pass/helpers/simple/input/entry.js
Normal file
2
spack/tests/pass/helpers/simple/input/entry.js
Normal file
@ -0,0 +1,2 @@
|
||||
@isDecorator
|
||||
class Foo { }
|
10
spack/tests/pass/helpers/simple/output/entry.js
Normal file
10
spack/tests/pass/helpers/simple/output/entry.js
Normal file
@ -0,0 +1,10 @@
|
||||
function _classCallCheck(instance, Constructor) {
|
||||
if (!(instance instanceof Constructor)) {
|
||||
throw new TypeError("Cannot call a class as a function");
|
||||
}
|
||||
}
|
||||
var _class;
|
||||
var Foo = _class = isDecorator((_class = function Foo() {
|
||||
"use strict";
|
||||
_classCallCheck(this, Foo);
|
||||
}) || _class) || _class;
|
@ -20,6 +20,7 @@ pub struct PassBuilder<'a, 'b, P: swc_ecma_visit::Fold> {
|
||||
loose: bool,
|
||||
hygiene: bool,
|
||||
fixer: bool,
|
||||
inject_helpers: bool,
|
||||
}
|
||||
|
||||
impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
@ -40,6 +41,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
hygiene: true,
|
||||
env: None,
|
||||
fixer: true,
|
||||
inject_helpers: true,
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,9 +60,15 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
env: self.env,
|
||||
global_mark: self.global_mark,
|
||||
fixer: self.fixer,
|
||||
inject_helpers: self.inject_helpers,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_helper_injection(mut self, skip: bool) -> Self {
|
||||
self.inject_helpers = !skip;
|
||||
self
|
||||
}
|
||||
|
||||
/// Note: fixer is enabled by default.
|
||||
pub fn fixer(mut self, enable: bool) -> Self {
|
||||
self.fixer = enable;
|
||||
@ -173,7 +181,7 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
|
||||
modules::import_analysis::import_analyzer(),
|
||||
need_interop_analysis
|
||||
),
|
||||
helpers::inject_helpers(),
|
||||
Optional::new(helpers::inject_helpers(), self.inject_helpers),
|
||||
ModuleConfig::build(self.cm.clone(), self.global_mark, module),
|
||||
Optional::new(hygiene(), self.hygiene),
|
||||
Optional::new(fixer(comments), self.fixer),
|
||||
|
@ -58,6 +58,9 @@ pub struct Options {
|
||||
#[serde(flatten, default)]
|
||||
pub config: Option<Config>,
|
||||
|
||||
#[serde(skip_deserializing, default)]
|
||||
pub skip_helper_injection: bool,
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[serde(skip_deserializing, default)]
|
||||
pub disable_hygiene: bool,
|
||||
@ -248,6 +251,7 @@ impl Options {
|
||||
|
||||
let pass = PassBuilder::new(&cm, &handler, loose, root_mark, pass)
|
||||
.target(target)
|
||||
.skip_helper_injection(self.skip_helper_injection)
|
||||
.hygiene(!self.disable_hygiene)
|
||||
.fixer(!self.disable_fixer)
|
||||
.preset_env(config.env)
|
||||
|
Loading…
Reference in New Issue
Block a user