mirror of
https://github.com/swc-project/swc.git
synced 2024-12-24 06:05:02 +03:00
fix(bundler): Improve performance (#1599)
swc_bundler: - Skip sorting of statements if a module does not import anything.
This commit is contained in:
parent
8222cc075d
commit
9a07869c21
@ -9,7 +9,7 @@ include = ["Cargo.toml", "build.rs", "src/**/*.rs", "src/**/*.js"]
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_bundler"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.32.4"
|
||||
version = "0.32.5"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
@ -21,6 +21,7 @@ ahash = "0.7"
|
||||
anyhow = "1"
|
||||
crc = "1.8"
|
||||
dashmap = {version = "3", optional = true}
|
||||
fxhash = "0.2"
|
||||
indexmap = "1.6"
|
||||
is-macro = "0.1"
|
||||
log = "0.4"
|
||||
|
@ -15,10 +15,9 @@ use crate::{
|
||||
util::{self, CloneMap, ExprExt, IntoParallelIterator, MapWithMut, VarDeclaratorExt},
|
||||
Bundler, Hook, ModuleRecord,
|
||||
};
|
||||
use ahash::AHashMap;
|
||||
use ahash::AHashSet;
|
||||
use ahash::RandomState;
|
||||
use anyhow::{Context, Error};
|
||||
use fxhash::FxHashMap;
|
||||
use fxhash::FxHashSet;
|
||||
use petgraph::graphmap::DiGraphMap;
|
||||
#[cfg(feature = "concurrent")]
|
||||
use rayon::iter::ParallelIterator;
|
||||
@ -33,7 +32,7 @@ pub(super) struct Ctx {
|
||||
pub graph: DiGraphMap<ModuleId, ()>,
|
||||
pub merged: CHashSet<ModuleId>,
|
||||
pub transitive_remap: CloneMap<SyntaxContext, SyntaxContext>,
|
||||
pub export_stars_in_wrapped: Lock<AHashMap<ModuleId, Vec<SyntaxContext>>>,
|
||||
pub export_stars_in_wrapped: Lock<FxHashMap<ModuleId, Vec<SyntaxContext>>>,
|
||||
}
|
||||
|
||||
impl<L, R> Bundler<'_, L, R>
|
||||
@ -541,7 +540,7 @@ where
|
||||
fn add_var(
|
||||
injected_ctxt: SyntaxContext,
|
||||
vars: &mut Vec<(ModuleId, ModuleItem)>,
|
||||
declared: &mut AHashSet<Id>,
|
||||
declared: &mut FxHashSet<Id>,
|
||||
map: &CloneMap<SyntaxContext, SyntaxContext>,
|
||||
module_id: ModuleId,
|
||||
id: Id,
|
||||
@ -579,7 +578,7 @@ where
|
||||
// If an user import and export from D, the transitive syntax context map
|
||||
// contains a entry from D to foo because it's reexported and
|
||||
// the variable (reexported from D) exist because it's imported.
|
||||
let mut declared_ids = AHashSet::<_, RandomState>::default();
|
||||
let mut declared_ids = FxHashSet::<_>::default();
|
||||
|
||||
for (_, stmt) in entry.iter() {
|
||||
match stmt {
|
||||
@ -653,7 +652,7 @@ where
|
||||
|
||||
{
|
||||
let mut map = ctx.export_stars_in_wrapped.lock();
|
||||
let mut additional_props = AHashMap::<_, Vec<_>>::new();
|
||||
let mut additional_props = FxHashMap::<_, Vec<_>>::default();
|
||||
// Handle `export *` for wrapped modules.
|
||||
for (module_id, ctxts) in map.drain() {
|
||||
for (_, stmt) in entry.iter() {
|
||||
@ -858,6 +857,8 @@ where
|
||||
return;
|
||||
}
|
||||
|
||||
let mut extra = vec![];
|
||||
|
||||
module.map_any_items(|_, items| {
|
||||
let mut new = Vec::with_capacity(items.len() * 11 / 10);
|
||||
|
||||
@ -1039,7 +1040,7 @@ where
|
||||
orig: local,
|
||||
exported: Some(exported),
|
||||
});
|
||||
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
extra.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
NamedExport {
|
||||
span: export.span.with_ctxt(injected_ctxt),
|
||||
specifiers: vec![specifier],
|
||||
@ -1086,7 +1087,7 @@ where
|
||||
exported: Some(exported),
|
||||
});
|
||||
log::trace!("Exporting `default` with `export default expr`");
|
||||
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
extra.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
NamedExport {
|
||||
span: export.span.with_ctxt(injected_ctxt),
|
||||
specifiers: vec![specifier],
|
||||
@ -1158,7 +1159,7 @@ where
|
||||
type_only: false,
|
||||
asserts: None,
|
||||
}));
|
||||
new.push(export);
|
||||
extra.push(export);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -1190,7 +1191,7 @@ where
|
||||
exported: Some(exported),
|
||||
});
|
||||
|
||||
new.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
extra.push(ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(
|
||||
NamedExport {
|
||||
span: export.span.with_ctxt(injected_ctxt),
|
||||
specifiers: vec![specifier],
|
||||
@ -1254,6 +1255,10 @@ where
|
||||
new
|
||||
});
|
||||
|
||||
for item in extra {
|
||||
module.append(info.id, item);
|
||||
}
|
||||
|
||||
// print_hygiene(
|
||||
// &format!("prepared: {}", info.fm.name),
|
||||
// &self.cm,
|
||||
|
@ -4,8 +4,8 @@ use crate::{
|
||||
util::IntoParallelIterator, Bundle,
|
||||
};
|
||||
use ahash::AHashMap;
|
||||
use ahash::AHashSet;
|
||||
use anyhow::{Context, Error};
|
||||
use fxhash::FxHashSet;
|
||||
#[cfg(feature = "rayon")]
|
||||
use rayon::iter::ParallelIterator;
|
||||
|
||||
@ -26,9 +26,9 @@ struct InternalEntry {
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct State {
|
||||
synchronously_included: AHashSet<ModuleId>,
|
||||
dynamic_entries: AHashSet<ModuleId>,
|
||||
common_libs: AHashSet<ModuleId>,
|
||||
synchronously_included: FxHashSet<ModuleId>,
|
||||
dynamic_entries: FxHashSet<ModuleId>,
|
||||
common_libs: FxHashSet<ModuleId>,
|
||||
}
|
||||
|
||||
impl<L, R> Bundler<'_, L, R>
|
||||
|
@ -5,8 +5,9 @@ use crate::{
|
||||
BundleKind, Bundler, Load, ModuleId, Resolve,
|
||||
};
|
||||
use ahash::AHashMap;
|
||||
use ahash::AHashSet;
|
||||
use anyhow::{bail, Error};
|
||||
use fxhash::FxHashMap;
|
||||
use fxhash::FxHashSet;
|
||||
use petgraph::{
|
||||
algo::all_simple_paths,
|
||||
visit::Bfs,
|
||||
@ -30,7 +31,7 @@ struct PlanBuilder {
|
||||
/// `(a, b)`, `(a, c)`,`(b, c)` will be inserted.
|
||||
///
|
||||
/// `bool` is `true` if it's connected with exports.
|
||||
all_deps: AHashMap<(ModuleId, ModuleId), bool>,
|
||||
all_deps: FxHashMap<(ModuleId, ModuleId), bool>,
|
||||
|
||||
/// Graph to compute direct dependencies (direct means it will be merged
|
||||
/// directly)
|
||||
@ -38,14 +39,14 @@ struct PlanBuilder {
|
||||
|
||||
circular: Circulars,
|
||||
|
||||
kinds: AHashMap<ModuleId, BundleKind>,
|
||||
kinds: FxHashMap<ModuleId, BundleKind>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
struct Circulars(Vec<AHashSet<ModuleId>>);
|
||||
struct Circulars(Vec<FxHashSet<ModuleId>>);
|
||||
|
||||
impl Circulars {
|
||||
pub fn get(&self, id: ModuleId) -> Option<&AHashSet<ModuleId>> {
|
||||
pub fn get(&self, id: ModuleId) -> Option<&FxHashSet<ModuleId>> {
|
||||
let pos = self.0.iter().position(|set| set.contains(&id))?;
|
||||
|
||||
Some(&self.0[pos])
|
||||
@ -53,7 +54,7 @@ impl Circulars {
|
||||
}
|
||||
|
||||
impl Deref for Circulars {
|
||||
type Target = Vec<AHashSet<ModuleId>>;
|
||||
type Target = Vec<FxHashSet<ModuleId>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
@ -76,7 +77,7 @@ impl PlanBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
let mut set = AHashSet::default();
|
||||
let mut set = FxHashSet::default();
|
||||
set.insert(src);
|
||||
set.insert(imported);
|
||||
self.circular.push(set);
|
||||
@ -98,11 +99,11 @@ pub(super) struct Plan {
|
||||
pub entries: Vec<ModuleId>,
|
||||
|
||||
/// key is entry
|
||||
pub normal: AHashMap<ModuleId, NormalPlan>,
|
||||
pub normal: FxHashMap<ModuleId, NormalPlan>,
|
||||
/// key is entry
|
||||
pub circular: AHashMap<ModuleId, CircularPlan>,
|
||||
pub circular: FxHashMap<ModuleId, CircularPlan>,
|
||||
|
||||
pub bundle_kinds: AHashMap<ModuleId, BundleKind>,
|
||||
pub bundle_kinds: FxHashMap<ModuleId, BundleKind>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
@ -165,7 +166,7 @@ where
|
||||
self.add_to_graph(&mut builder, module.id, &mut vec![], true);
|
||||
}
|
||||
|
||||
let mut metadata = AHashMap::<ModuleId, Metadata>::default();
|
||||
let mut metadata = FxHashMap::<ModuleId, Metadata>::default();
|
||||
|
||||
// Draw dependency graph to calculte
|
||||
for (id, _) in &builder.kinds {
|
||||
@ -205,7 +206,7 @@ where
|
||||
Ok((self.build_plan(&metadata, builder), graph))
|
||||
}
|
||||
|
||||
fn build_plan(&self, _metadata: &AHashMap<ModuleId, Metadata>, builder: PlanBuilder) -> Plan {
|
||||
fn build_plan(&self, _metadata: &FxHashMap<ModuleId, Metadata>, builder: PlanBuilder) -> Plan {
|
||||
let mut plans = Plan::default();
|
||||
|
||||
for (id, kind) in builder.kinds.iter() {
|
||||
@ -218,7 +219,7 @@ where
|
||||
let root_entry = *root_entry;
|
||||
let mut bfs = Bfs::new(&builder.direct_deps, root_entry);
|
||||
|
||||
let mut done = AHashSet::new();
|
||||
let mut done = FxHashSet::default();
|
||||
|
||||
while let Some(entry) = bfs.next(&builder.direct_deps) {
|
||||
let mut deps: Vec<_> = builder
|
||||
|
@ -1,8 +1,8 @@
|
||||
use super::Bundler;
|
||||
use crate::{load::Load, resolve::Resolve};
|
||||
use ahash::AHashMap;
|
||||
use ahash::AHashSet;
|
||||
use anyhow::{Context, Error};
|
||||
use fxhash::FxHashMap;
|
||||
use fxhash::FxHashSet;
|
||||
use retain_mut::RetainMut;
|
||||
use swc_atoms::{js_word, JsWord};
|
||||
use swc_common::{sync::Lrc, FileName, Mark, Spanned, SyntaxContext, DUMMY_SP};
|
||||
@ -94,7 +94,7 @@ pub(super) struct RawImports {
|
||||
/// function bar() {}
|
||||
/// foo[bar()]
|
||||
/// ```
|
||||
pub forced_ns: AHashSet<JsWord>,
|
||||
pub forced_ns: FxHashSet<JsWord>,
|
||||
}
|
||||
|
||||
/// This type implements two operation (analysis, deglobbing) to reduce binary
|
||||
@ -114,13 +114,13 @@ where
|
||||
|
||||
/// HashMap from the local identifier of a namespace import to used
|
||||
/// properties.
|
||||
usages: AHashMap<Id, Vec<Id>>,
|
||||
usages: FxHashMap<Id, Vec<Id>>,
|
||||
|
||||
/// While deglobbing, we also marks imported identifiers.
|
||||
imported_idents: AHashMap<Id, SyntaxContext>,
|
||||
imported_idents: FxHashMap<Id, SyntaxContext>,
|
||||
|
||||
deglob_phase: bool,
|
||||
idents_to_deglob: AHashSet<Id>,
|
||||
idents_to_deglob: FxHashSet<Id>,
|
||||
|
||||
/// `true` while folding objects of a member expression.
|
||||
///
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::id::Id;
|
||||
use crate::util::MapWithMut;
|
||||
use ahash::AHashMap;
|
||||
use fxhash::FxHashMap;
|
||||
use swc_atoms::js_word;
|
||||
use swc_ecma_ast::*;
|
||||
use swc_ecma_utils::private_ident;
|
||||
@ -10,7 +10,7 @@ use swc_ecma_visit::VisitMutWith;
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct KeywordRenamer {
|
||||
renamed: AHashMap<Id, Ident>,
|
||||
renamed: FxHashMap<Id, Ident>,
|
||||
}
|
||||
|
||||
impl KeywordRenamer {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::ModuleId;
|
||||
use ahash::AHashMap;
|
||||
use fxhash::FxHashMap;
|
||||
use retain_mut::RetainMut;
|
||||
use std::mem::take;
|
||||
use swc_common::SourceMap;
|
||||
@ -24,8 +24,8 @@ pub struct Modules {
|
||||
|
||||
// We will change this into `Vec<Module>`.
|
||||
modules: Vec<(ModuleId, Module)>,
|
||||
prepended_stmts: AHashMap<ModuleId, Vec<ModuleItem>>,
|
||||
appended_stmts: AHashMap<ModuleId, Vec<ModuleItem>>,
|
||||
prepended_stmts: FxHashMap<ModuleId, Vec<ModuleItem>>,
|
||||
appended_stmts: FxHashMap<ModuleId, Vec<ModuleItem>>,
|
||||
}
|
||||
|
||||
impl Modules {
|
||||
|
@ -2,8 +2,8 @@ use super::stmt::sort_stmts;
|
||||
use crate::dep_graph::ModuleGraph;
|
||||
use crate::modules::Modules;
|
||||
use crate::ModuleId;
|
||||
use ahash::AHashSet;
|
||||
use ahash::RandomState;
|
||||
use fxhash::FxHashSet;
|
||||
use indexmap::IndexSet;
|
||||
use petgraph::algo::all_simple_paths;
|
||||
use petgraph::EdgeDirection::Outgoing;
|
||||
@ -96,6 +96,16 @@ fn toposort_real_modules<'a>(
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip sorting statements if there is no import.
|
||||
if ids.len() == 1 {
|
||||
if graph.neighbors_directed(ids[0], Outgoing).count() == 0 {
|
||||
chunks.push(Chunk {
|
||||
stmts: stmts.into_iter().next().unwrap(),
|
||||
});
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let stmts = sort_stmts(injected_ctxt, stmts, cm);
|
||||
|
||||
// print_hygiene(
|
||||
@ -117,7 +127,7 @@ fn toposort_real_modules<'a>(
|
||||
/// Get all modules in a cycle.
|
||||
fn all_modules_in_circle(
|
||||
id: ModuleId,
|
||||
done: &AHashSet<ModuleId>,
|
||||
done: &FxHashSet<ModuleId>,
|
||||
already_in_index: &mut IndexSet<ModuleId, RandomState>,
|
||||
graph: &ModuleGraph,
|
||||
) -> IndexSet<ModuleId, RandomState> {
|
||||
@ -159,7 +169,7 @@ fn toposort_real_module_ids<'a>(
|
||||
mut queue: VecDeque<ModuleId>,
|
||||
graph: &'a ModuleGraph,
|
||||
) -> impl 'a + Iterator<Item = Vec<ModuleId>> {
|
||||
let mut done = AHashSet::<ModuleId>::default();
|
||||
let mut done = FxHashSet::<ModuleId>::default();
|
||||
|
||||
from_fn(move || {
|
||||
while let Some(id) = queue.pop_front() {
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::util::fast_graph::FastDiGraphMap;
|
||||
use ahash::AHashSet;
|
||||
use fxhash::FxHashSet;
|
||||
use petgraph::EdgeDirection;
|
||||
use petgraph::EdgeDirection::Incoming;
|
||||
use petgraph::EdgeDirection::Outgoing;
|
||||
@ -22,7 +22,7 @@ pub(super) struct StmtDepGraph {
|
||||
inner: FastDiGraphMap<usize, Required>,
|
||||
/// Read-optimized hashset which contains all direct dependencies and
|
||||
/// transitive dependencies.
|
||||
paths: Vec<AHashSet<usize>>,
|
||||
paths: Vec<FxHashSet<usize>>,
|
||||
}
|
||||
|
||||
impl StmtDepGraph {
|
||||
@ -44,8 +44,8 @@ impl StmtDepGraph {
|
||||
self.insert_transitives(a, b);
|
||||
}
|
||||
|
||||
fn calc_transitives(&self, id: usize, dir: EdgeDirection) -> AHashSet<usize> {
|
||||
let mut set = AHashSet::default();
|
||||
fn calc_transitives(&self, id: usize, dir: EdgeDirection) -> FxHashSet<usize> {
|
||||
let mut set = FxHashSet::default();
|
||||
|
||||
let mut queue = VecDeque::default();
|
||||
queue.push_front(id);
|
||||
|
@ -2,8 +2,8 @@ use super::graph::Required;
|
||||
use crate::id::Id;
|
||||
use crate::modules::sort::graph::StmtDepGraph;
|
||||
use crate::util::MapWithMut;
|
||||
use ahash::AHashMap;
|
||||
use ahash::AHashSet;
|
||||
use fxhash::FxHashMap;
|
||||
use fxhash::FxHashSet;
|
||||
use indexmap::IndexSet;
|
||||
use petgraph::EdgeDirection::Incoming as Dependants;
|
||||
use petgraph::EdgeDirection::Outgoing as Dependancies;
|
||||
@ -103,8 +103,8 @@ fn iter<'a>(
|
||||
// dbg!(&free);
|
||||
// dbg!(&module_starts);
|
||||
|
||||
let mut moves = AHashSet::new();
|
||||
let mut done = AHashSet::new();
|
||||
let mut moves = FxHashSet::default();
|
||||
let mut done = FxHashSet::default();
|
||||
let mut stack = VecDeque::new();
|
||||
stack.extend(module_starts.iter().copied());
|
||||
|
||||
@ -343,7 +343,7 @@ fn iter<'a>(
|
||||
struct FieldInitFinter {
|
||||
in_object_assign: bool,
|
||||
in_rhs: bool,
|
||||
accessed: AHashSet<Id>,
|
||||
accessed: FxHashSet<Id>,
|
||||
}
|
||||
|
||||
impl FieldInitFinter {
|
||||
@ -643,8 +643,8 @@ fn calc_deps(new: &[ModuleItem]) -> StmtDepGraph {
|
||||
log::debug!("Analyzing dependencies between statements");
|
||||
let mut graph = StmtDepGraph::default();
|
||||
|
||||
let mut declared_by = AHashMap::<Id, Vec<usize>>::default();
|
||||
let mut uninitialized_ids = AHashMap::<Id, usize>::new();
|
||||
let mut declared_by = FxHashMap::<Id, Vec<usize>>::default();
|
||||
let mut uninitialized_ids = FxHashMap::<Id, usize>::default();
|
||||
|
||||
for (idx, item) in new.iter().enumerate() {
|
||||
graph.add_node(idx);
|
||||
|
@ -1,9 +1,9 @@
|
||||
use anyhow::{bail, Context, Error};
|
||||
use reqwest::Url;
|
||||
use sha1::{Digest, Sha1};
|
||||
use std::env::current_dir;
|
||||
use std::io::Write;
|
||||
use std::{
|
||||
self, env,
|
||||
fs::{create_dir_all, read_to_string, write},
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
@ -39,7 +39,7 @@ fn calc_cache_path(cache_dir: &Path, url: &Url) -> PathBuf {
|
||||
/// Load url. This method does caching.
|
||||
fn load_url(url: Url) -> Result<String, Error> {
|
||||
let cache_dir = PathBuf::from(
|
||||
env::var("CARGO_MANIFEST_DIR")
|
||||
current_dir()
|
||||
.expect("the test requires an environment variable named `CARGO_MANIFEST_DIR`"),
|
||||
)
|
||||
.join("tests")
|
||||
|
@ -1608,6 +1608,8 @@ function joinGlobs(globs, { extended =false , globstar =false } = {
|
||||
}
|
||||
const mod3 = function() {
|
||||
return {
|
||||
SEP: SEP,
|
||||
SEP_PATTERN: SEP_PATTERN,
|
||||
win32: mod1,
|
||||
posix: mod2,
|
||||
basename: basename2,
|
||||
@ -1625,8 +1627,6 @@ const mod3 = function() {
|
||||
sep: sep2,
|
||||
toFileUrl: toFileUrl2,
|
||||
toNamespacedPath: toNamespacedPath2,
|
||||
SEP: SEP,
|
||||
SEP_PATTERN: SEP_PATTERN,
|
||||
globToRegExp,
|
||||
isGlob,
|
||||
normalizeGlob,
|
||||
|
@ -1618,6 +1618,8 @@ function joinGlobs(globs, { extended =false , globstar =false } = {
|
||||
}
|
||||
const mod3 = function() {
|
||||
return {
|
||||
SEP: SEP,
|
||||
SEP_PATTERN: SEP_PATTERN,
|
||||
win32: win32,
|
||||
posix: posix,
|
||||
basename: basename2,
|
||||
@ -1635,8 +1637,6 @@ const mod3 = function() {
|
||||
sep: sep2,
|
||||
toFileUrl: toFileUrl2,
|
||||
toNamespacedPath: toNamespacedPath2,
|
||||
SEP: SEP,
|
||||
SEP_PATTERN: SEP_PATTERN,
|
||||
globToRegExp,
|
||||
isGlob,
|
||||
normalizeGlob,
|
||||
|
Loading…
Reference in New Issue
Block a user