Skip to content

Commit ac5ab60

Browse files
authoredMay 18, 2023
refactor(plugin/runner): Revise cache, module loading (#7408)
**Description:** One of the oversight around design of `TransformExecutor` is encapsulating plugin module logic. It has access to the cache and do its own loading & storing. This means consumer of plugin runner have tricky challenge to control its caching system. First, there is no way to escape how swc_plugin_runner controls cache and cannot synchronize into their own, also depends on the usecases cannot control the features they want to opt in: for example, there's no way one interface uses in-memory cache, and another uses filesystem since it is compile time configured singleton. PR revisits overall design of TransformExecutor: now it accepts a tratir `PluginModuleBytes`, which abstracts any kind of bytes we are dealing with, such as raw file slice or serialized `wasmer::Module`. Cache instantiation and managing is now bubbled up to the application level (`swc` in here), so if someone wants non-singleton caching or integrate into their own caching system it can be customized. Lastly, deprecated `memory_cache` feature and only exposes `filesystem_cache`. Cache implementation uses in-memory is always available, and can opt in filesystem cache where it's supported. **BREAKING CHANGE:** This is clearly breaking changes for the consumers of swc_core. for the @swc/core, this PR takes care of necessary changes. I'll work on next-swc changes later once we have new @swc/core version with this changes.
1 parent 31d7b88 commit ac5ab60

File tree

17 files changed

+1035
-729
lines changed

17 files changed

+1035
-729
lines changed
 

‎bindings/binding_core_node/Cargo.toml

+6-3
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ crate-type = ["cdylib"]
1414

1515
[features]
1616
default = ["swc_v1", "plugin"]
17-
plugin = ["swc_core/plugin_transform_host_native"]
18-
swc_v1 = ["swc_core/bundler_node_v1"]
19-
swc_v2 = ["swc_core/bundler_node_v2"]
17+
plugin = [
18+
"swc_core/plugin_transform_host_native",
19+
"swc_core/plugin_transform_host_native_filesystem_cache",
20+
]
21+
swc_v1 = ["swc_core/bundler_node_v1"]
22+
swc_v2 = ["swc_core/bundler_node_v2"]
2023

2124
# Internal flag for testing purpose only.
2225
__plugin_transform_vtest = [

‎bindings/swc_cli/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ path = "./src/main.rs"
1515

1616
[features]
1717
default = []
18-
plugin = ["swc_core/plugin_transform_host_native"]
18+
plugin = [
19+
"swc_core/plugin_transform_host_native",
20+
"swc_core/plugin_transform_host_native_filesystem_cache",
21+
]
1922

2023
[dependencies]
2124
anyhow = "1.0.66"

‎crates/swc/src/config/mod.rs

+107-55
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,33 @@ use crate::{
8080
#[cfg(test)]
8181
mod tests;
8282

83+
#[cfg(feature = "plugin")]
84+
/// A shared instance to plugin's module bytecode cache.
85+
pub static PLUGIN_MODULE_CACHE: Lazy<swc_plugin_runner::cache::PluginModuleCache> =
86+
Lazy::new(Default::default);
87+
88+
/// Create a new cache instance if not initialized. This can be called multiple
89+
/// time, but any subsequent call will be ignored.
90+
///
91+
/// This fn have a side effect to create path to cache if given path is not
92+
/// resolvable if fs_cache_store is enabled. If root is not specified, it'll
93+
/// generate default root for cache location.
94+
///
95+
/// If cache failed to initialize filesystem cache for given location
96+
/// it'll be serve in-memory cache only.
97+
#[cfg(feature = "plugin")]
98+
pub fn init_plugin_module_cache_once(
99+
enable_fs_cache_store: bool,
100+
fs_cache_store_root: &Option<String>,
101+
) {
102+
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
103+
parking_lot::Mutex::new(swc_plugin_runner::cache::PluginModuleCache::create_inner(
104+
enable_fs_cache_store,
105+
fs_cache_store_root,
106+
))
107+
});
108+
}
109+
83110
#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
84111
pub enum IsModule {
85112
Bool(bool),
@@ -619,77 +646,102 @@ impl Options {
619646

620647
let keep_import_assertions = experimental.keep_import_assertions.into_bool();
621648

622-
// Embedded runtime plugin target, based on assumption we have
623-
// 1. filesystem access for the cache
624-
// 2. embedded runtime can compiles & execute wasm
625-
#[cfg(all(any(feature = "plugin"), not(target_arch = "wasm32")))]
626-
let plugins = {
627-
let plugin_resolver = CachingResolver::new(
628-
40,
629-
NodeModulesResolver::new(TargetEnv::Node, Default::default(), true),
630-
);
631-
649+
#[cfg(feature = "plugin")]
650+
let plugin_transforms = {
632651
let transform_filename = match base {
633652
FileName::Real(path) => path.as_os_str().to_str().map(String::from),
634653
FileName::Custom(filename) => Some(filename.to_owned()),
635654
_ => None,
636655
};
637-
638656
let transform_metadata_context = Arc::new(TransformPluginMetadataContext::new(
639657
transform_filename,
640658
self.env_name.to_owned(),
641659
None,
642660
));
643661

644-
if experimental.plugins.is_some() {
645-
swc_plugin_runner::cache::init_plugin_module_cache_once(&experimental.cache_root);
646-
}
662+
// Embedded runtime plugin target, based on assumption we have
663+
// 1. filesystem access for the cache
664+
// 2. embedded runtime can compiles & execute wasm
665+
#[cfg(all(any(feature = "plugin"), not(target_arch = "wasm32")))]
666+
{
667+
use swc_ecma_loader::resolve::Resolve;
647668

648-
let comments = comments.cloned();
649-
let source_map = cm.clone();
650-
crate::plugin::plugins(
651-
experimental.plugins,
652-
transform_metadata_context,
653-
Some(plugin_resolver),
654-
comments,
655-
source_map,
656-
unresolved_mark,
657-
)
658-
};
669+
// Currently swc enables filesystemcache by default on Embedded runtime plugin
670+
// target.
671+
init_plugin_module_cache_once(true, &experimental.cache_root);
659672

660-
// Native runtime plugin target, based on assumption we have
661-
// 1. no filesystem access, loading binary / cache management should be
662-
// performed externally
663-
// 2. native runtime compiles & execute wasm (i.e v8 on node, chrome)
664-
#[cfg(all(any(feature = "plugin"), target_arch = "wasm32"))]
665-
let plugins = {
666-
let transform_filename = match base {
667-
FileName::Real(path) => path.as_os_str().to_str().map(String::from),
668-
FileName::Custom(filename) => Some(filename.to_owned()),
669-
_ => None,
670-
};
673+
let plugin_resolver = CachingResolver::new(
674+
40,
675+
NodeModulesResolver::new(TargetEnv::Node, Default::default(), true),
676+
);
671677

672-
let transform_metadata_context = Arc::new(TransformPluginMetadataContext::new(
673-
transform_filename,
674-
self.env_name.to_owned(),
675-
None,
676-
));
678+
if let Some(plugins) = &experimental.plugins {
679+
// Populate cache to the plugin modules if not loaded
680+
for plugin_config in plugins.iter() {
681+
let plugin_name = &plugin_config.0;
682+
683+
if !PLUGIN_MODULE_CACHE
684+
.inner
685+
.get()
686+
.unwrap()
687+
.lock()
688+
.contains(&plugin_name)
689+
{
690+
let resolved_path = plugin_resolver.resolve(
691+
&FileName::Real(PathBuf::from(&plugin_name)),
692+
&plugin_name,
693+
)?;
694+
695+
let path = if let FileName::Real(value) = resolved_path {
696+
value
697+
} else {
698+
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
699+
};
700+
701+
let mut inner_cache = PLUGIN_MODULE_CACHE
702+
.inner
703+
.get()
704+
.expect("Cache should be available")
705+
.lock();
706+
inner_cache.store_bytes_from_path(&path, &plugin_name)?;
707+
}
708+
}
709+
}
677710

678-
swc_plugin_runner::cache::init_plugin_module_cache_once();
679-
let comments = comments.cloned();
680-
let source_map = cm.clone();
681-
crate::plugin::plugins(
682-
experimental.plugins,
683-
transform_metadata_context,
684-
None,
685-
comments,
686-
source_map,
687-
unresolved_mark,
688-
)
711+
crate::plugin::plugins(
712+
experimental.plugins,
713+
transform_metadata_context,
714+
comments.cloned(),
715+
cm.clone(),
716+
unresolved_mark,
717+
)
718+
}
719+
720+
// Native runtime plugin target, based on assumption we have
721+
// 1. no filesystem access, loading binary / cache management should be
722+
// performed externally
723+
// 2. native runtime compiles & execute wasm (i.e v8 on node, chrome)
724+
#[cfg(all(any(feature = "plugin"), target_arch = "wasm32"))]
725+
{
726+
handler.warn(
727+
"Currently @swc/wasm does not support plugins, plugin transform will be \
728+
skipped. Refer https://github.com/swc-project/swc/issues/3934 for the details.",
729+
);
730+
731+
noop()
732+
}
689733
};
690734

691-
#[cfg(not(any(feature = "plugin")))]
692-
let plugins = crate::plugin::plugins();
735+
#[cfg(not(feature = "plugin"))]
736+
let plugin_transforms = {
737+
if experimental.plugins.is_some() {
738+
handler.warn(
739+
"Plugin is not supported with current @swc/core. Plugin transform will be \
740+
skipped.",
741+
);
742+
}
743+
noop()
744+
};
693745

694746
let pass = chain!(
695747
lint_to_fold(swc_ecma_lints::rules::all(LintParams {
@@ -753,7 +805,7 @@ impl Options {
753805
),
754806
syntax.typescript()
755807
),
756-
plugins,
808+
plugin_transforms,
757809
custom_before_pass(&program),
758810
// handle jsx
759811
Optional::new(

‎crates/swc/src/plugin.rs

+23-92
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use serde::{Deserialize, Serialize};
1010
#[cfg(any(feature = "plugin"))]
1111
use swc_ecma_ast::*;
12-
use swc_ecma_loader::resolvers::{lru::CachingResolver, node::NodeModulesResolver};
1312
#[cfg(not(any(feature = "plugin")))]
1413
use swc_ecma_transforms::pass::noop;
1514
use swc_ecma_visit::{noop_fold_type, Fold};
@@ -24,36 +23,25 @@ use swc_ecma_visit::{noop_fold_type, Fold};
2423
#[serde(deny_unknown_fields, rename_all = "camelCase")]
2524
pub struct PluginConfig(pub String, pub serde_json::Value);
2625

27-
#[cfg(any(feature = "plugin"))]
2826
pub fn plugins(
2927
configured_plugins: Option<Vec<PluginConfig>>,
3028
metadata_context: std::sync::Arc<swc_common::plugin::metadata::TransformPluginMetadataContext>,
31-
resolver: Option<CachingResolver<NodeModulesResolver>>,
3229
comments: Option<swc_common::comments::SingleThreadedComments>,
3330
source_map: std::sync::Arc<swc_common::SourceMap>,
3431
unresolved_mark: swc_common::Mark,
3532
) -> impl Fold {
36-
{
37-
RustPlugins {
38-
plugins: configured_plugins,
39-
metadata_context,
40-
resolver,
41-
comments,
42-
source_map,
43-
unresolved_mark,
44-
}
33+
RustPlugins {
34+
plugins: configured_plugins,
35+
metadata_context,
36+
comments,
37+
source_map,
38+
unresolved_mark,
4539
}
4640
}
4741

48-
#[cfg(not(any(feature = "plugin")))]
49-
pub fn plugins() -> impl Fold {
50-
noop()
51-
}
52-
5342
struct RustPlugins {
5443
plugins: Option<Vec<PluginConfig>>,
5544
metadata_context: std::sync::Arc<swc_common::plugin::metadata::TransformPluginMetadataContext>,
56-
resolver: Option<CachingResolver<NodeModulesResolver>>,
5745
comments: Option<swc_common::comments::SingleThreadedComments>,
5846
source_map: std::sync::Arc<swc_common::SourceMap>,
5947
unresolved_mark: swc_common::Mark,
@@ -78,11 +66,8 @@ impl RustPlugins {
7866
#[tracing::instrument(level = "info", skip_all, name = "apply_plugins")]
7967
#[cfg(all(any(feature = "plugin"), not(target_arch = "wasm32")))]
8068
fn apply_inner(&mut self, n: Program) -> Result<Program, anyhow::Error> {
81-
use std::{path::PathBuf, sync::Arc};
82-
8369
use anyhow::Context;
84-
use swc_common::{plugin::serialized::PluginSerializedBytes, FileName};
85-
use swc_ecma_loader::resolve::Resolve;
70+
use swc_common::plugin::serialized::PluginSerializedBytes;
8671

8772
// swc_plugin_macro will not inject proxy to the comments if comments is empty
8873
let should_enable_comments_proxy = self.comments.is_some();
@@ -106,30 +91,23 @@ impl RustPlugins {
10691
// transform.
10792
if let Some(plugins) = &mut self.plugins {
10893
for p in plugins.drain(..) {
109-
let resolved_path = self
110-
.resolver
111-
.as_ref()
112-
.expect("filesystem_cache should provide resolver")
113-
.resolve(&FileName::Real(PathBuf::from(&p.0)), &p.0)?;
114-
115-
let path = if let FileName::Real(value) = resolved_path {
116-
Arc::new(value)
117-
} else {
118-
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
119-
};
120-
94+
let plugin_module_bytes = crate::config::PLUGIN_MODULE_CACHE
95+
.inner
96+
.get()
97+
.unwrap()
98+
.lock()
99+
.get(&p.0)
100+
.expect("plugin module should be loaded");
101+
102+
let plugin_name = plugin_module_bytes.get_module_name().to_string();
121103
let mut transform_plugin_executor =
122104
swc_plugin_runner::create_plugin_transform_executor(
123-
&path,
124-
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
125105
&self.source_map,
106+
&self.unresolved_mark,
126107
&self.metadata_context,
108+
plugin_module_bytes,
127109
Some(p.1),
128-
)?;
129-
130-
if !transform_plugin_executor.is_transform_schema_compatible()? {
131-
anyhow::bail!("Cannot execute incompatible plugin {}", &p.0);
132-
}
110+
);
133111

134112
let span = tracing::span!(
135113
tracing::Level::INFO,
@@ -139,16 +117,11 @@ impl RustPlugins {
139117
.entered();
140118

141119
serialized = transform_plugin_executor
142-
.transform(
143-
&serialized,
144-
self.unresolved_mark,
145-
should_enable_comments_proxy,
146-
)
120+
.transform(&serialized, Some(should_enable_comments_proxy))
147121
.with_context(|| {
148122
format!(
149123
"failed to invoke `{}` as js transform plugin at {}",
150-
&p.0,
151-
path.display()
124+
&p.0, plugin_name
152125
)
153126
})?;
154127
drop(span);
@@ -165,50 +138,8 @@ impl RustPlugins {
165138
#[cfg(all(any(feature = "plugin"), target_arch = "wasm32"))]
166139
#[tracing::instrument(level = "info", skip_all)]
167140
fn apply_inner(&mut self, n: Program) -> Result<Program, anyhow::Error> {
168-
use std::{path::PathBuf, sync::Arc};
169-
170-
use anyhow::Context;
171-
use swc_common::{
172-
collections::AHashMap, plugin::serialized::PluginSerializedBytes, FileName,
173-
};
174-
use swc_ecma_loader::resolve::Resolve;
175-
176-
let should_enable_comments_proxy = self.comments.is_some();
177-
178-
swc_plugin_proxy::COMMENTS.set(
179-
&swc_plugin_proxy::HostCommentsStorage {
180-
inner: self.comments.clone(),
181-
},
182-
|| {
183-
let program = swc_common::plugin::serialized::VersionedSerializable::new(n);
184-
let mut serialized = PluginSerializedBytes::try_serialize(&program)?;
185-
186-
if let Some(plugins) = &mut self.plugins {
187-
for p in plugins.drain(..) {
188-
let mut transform_plugin_executor =
189-
swc_plugin_runner::create_plugin_transform_executor(
190-
&PathBuf::from(&p.0),
191-
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
192-
&self.source_map,
193-
&self.metadata_context,
194-
Some(p.1),
195-
)?;
196-
197-
serialized = transform_plugin_executor
198-
.transform(
199-
&serialized,
200-
self.unresolved_mark,
201-
should_enable_comments_proxy,
202-
)
203-
.with_context(|| {
204-
format!("failed to invoke `{}` as js transform plugin", &p.0)
205-
})?;
206-
}
207-
}
208-
209-
serialized_program.deserialize().map(|v| v.into_inner())
210-
},
211-
)
141+
// [TODO]: unimplemented
142+
n
212143
}
213144
}
214145

‎crates/swc_core/Cargo.toml

+3-13
Original file line numberDiff line numberDiff line change
@@ -200,19 +200,10 @@ plugin_transform_host_native = [
200200
"__plugin_transform_host",
201201
"__plugin_transform_host_schema_v1",
202202
"__plugin_transform_env_native",
203-
"swc_plugin_runner/filesystem_cache",
204203
]
205-
# For the environment who have its own caching mechanism doesn't want
206-
# to have cache out of its control.
207-
# [TODO]: ideally `plugin_transform_host_native` should be a feature
208-
# agnostic to the caching mechanism with explicit opt in for the caching options,
209-
# but that's a breaking changes for the future version.
210-
plugin_transform_host_native_memory_cache = [
211-
# Dependent features
212-
"__plugin_transform_host",
213-
"__plugin_transform_host_schema_v1",
214-
"__plugin_transform_env_native",
215-
"swc_plugin_runner/memory_cache",
204+
# Enables FileSystemCache support for the plugin runner.
205+
plugin_transform_host_native_filesystem_cache = [
206+
"swc_plugin_runner/filesystem_cache",
216207
]
217208

218209
### Internal features that public features are relying on.
@@ -290,7 +281,6 @@ __plugin_transform_env_native = [
290281

291282
__plugin_transform_env_js = [
292283
"swc/plugin_transform_host_js",
293-
"swc_plugin_runner/memory_cache",
294284
"swc_plugin_runner/plugin_transform_host_js",
295285
]
296286

‎crates/swc_core/tests/fixture/stub_napi/Cargo.toml

+6-3
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,12 @@ crate-type = ["cdylib"]
1111

1212
[features]
1313
default = ["swc_v1", "plugin"]
14-
plugin = ["swc_core/plugin_transform_host_native"]
15-
swc_v1 = ["swc_core/bundler_node_v1"]
16-
swc_v2 = ["swc_core/bundler_node_v2"]
14+
plugin = [
15+
"swc_core/plugin_transform_host_native",
16+
"swc_core/plugin_transform_host_native_filesystem_cache",
17+
]
18+
swc_v1 = ["swc_core/bundler_node_v1"]
19+
swc_v2 = ["swc_core/bundler_node_v2"]
1720

1821
# Internal flag for testing purpose only.
1922
__plugin_transform_vtest = [

‎crates/swc_plugin_runner/Cargo.toml

+2-5
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,8 @@ plugin_transform_host_native = [
3131
"wasmer-compiler-cranelift/default",
3232
]
3333
# Supports a cache allow to store compiled bytecode into filesystem location.
34-
# This feature implies in-memory cache support, but not via `memory_cache` feature.
35-
filesystem_cache = ["wasmer-cache"]
36-
# Supports a cache allow to store wasm module in-memory. This avoids recompilation
37-
# to the same module in a single procress lifecycle.
38-
memory_cache = []
34+
# This feature implies in-memory cache support. This is not supported on wasm32 target.
35+
filesystem_cache = ["wasmer-cache"]
3936
plugin_transform_schema_v1 = ["swc_common/plugin_transform_schema_v1"]
4037
plugin_transform_schema_vtest = ["swc_common/plugin_transform_schema_vtest"]
4138

‎crates/swc_plugin_runner/benches/ecma_invoke.rs

+30-20
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,10 @@ use swc_common::{
1818
};
1919
use swc_ecma_ast::EsVersion;
2020
use swc_ecma_parser::parse_file_as_program;
21-
use swc_plugin_runner::cache::init_plugin_module_cache_once;
2221

2322
static SOURCE: &str = include_str!("./assets/input.js");
2423

2524
fn plugin_group(c: &mut Criterion) {
26-
init_plugin_module_cache_once(&None);
27-
2825
let plugin_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
2926
.join("tests")
3027
.join("fixture")
@@ -46,6 +43,25 @@ fn plugin_group(c: &mut Criterion) {
4643
}
4744

4845
fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
46+
let path = &plugin_dir
47+
.join("target")
48+
.join("wasm32-wasi")
49+
.join("release")
50+
.join("swc_noop_plugin.wasm");
51+
let raw_module_bytes = std::fs::read(path).expect("Should able to read plugin bytes");
52+
53+
let store = wasmer::Store::default();
54+
let module = wasmer::Module::new(&store, raw_module_bytes).unwrap();
55+
56+
let plugin_module = swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes::new(
57+
path.as_os_str()
58+
.to_str()
59+
.expect("Should able to get path")
60+
.to_string(),
61+
module,
62+
store,
63+
);
64+
4965
#[cfg(feature = "__rkyv")]
5066
b.iter(|| {
5167
GLOBALS.set(&Globals::new(), || {
@@ -65,23 +81,17 @@ fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
6581
let program = VersionedSerializable::new(program);
6682
let program_ser = PluginSerializedBytes::try_serialize(&program).unwrap();
6783

68-
let mut transform_plugin_executor =
69-
swc_plugin_runner::create_plugin_transform_executor(
70-
&plugin_dir
71-
.join("target")
72-
.join("wasm32-wasi")
73-
.join("release")
74-
.join("swc_noop_plugin.wasm"),
75-
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
76-
&cm,
77-
&Arc::new(TransformPluginMetadataContext::new(
78-
None,
79-
"development".to_string(),
80-
None,
81-
)),
84+
let mut transform_plugin_executor = swc_plugin_runner::create_plugin_transform_executor(
85+
&cm,
86+
&Mark::new(),
87+
&Arc::new(TransformPluginMetadataContext::new(
8288
None,
83-
)
84-
.unwrap();
89+
"development".to_string(),
90+
None,
91+
)),
92+
Box::new(plugin_module.clone()),
93+
None,
94+
);
8595

8696
let experimental_metadata: VersionedSerializable<AHashMap<String, String>> =
8797
VersionedSerializable::new(AHashMap::default());
@@ -90,7 +100,7 @@ fn bench_transform(b: &mut Bencher, plugin_dir: &Path) {
90100
.expect("Should be a hashmap");
91101

92102
let res = transform_plugin_executor
93-
.transform(&program_ser, Mark::new(), true)
103+
.transform(&program_ser, Some(true))
94104
.unwrap();
95105

96106
let _ = black_box(res);

‎crates/swc_plugin_runner/src/cache.rs

+149-182
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
use std::{
44
env::current_dir,
55
path::{Path, PathBuf},
6+
str::FromStr,
67
};
78

89
use anyhow::{Context, Error};
@@ -18,14 +19,9 @@ use wasmer::{Module, Store};
1819
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
1920
use wasmer_cache::{Cache as WasmerCache, FileSystemCache, Hash};
2021

21-
#[cfg(all(not(feature = "filesystem_cache"), not(feature = "memory_cache")))]
22-
compile_error!("Plugin_runner should enable either filesystem, or memory cache");
23-
24-
#[cfg(all(feature = "filesystem_cache", feature = "memory_cache"))]
25-
compile_error!(
26-
"Only one cache feature should be enabled. If you enabled filesystem_cache, it activates its \
27-
memory cache as well."
28-
);
22+
use crate::plugin_module_bytes::{
23+
CompiledPluginModuleBytes, PluginModuleBytes, RawPluginModuleBytes,
24+
};
2925

3026
/// Version for bytecode cache stored in local filesystem.
3127
///
@@ -37,37 +33,164 @@ compile_error!(
3733
/// https://github.com/wasmerio/wasmer/issues/2781
3834
const MODULE_SERIALIZATION_VERSION: &str = "v6";
3935

40-
/// A shared instance to plugin's module bytecode cache.
41-
pub static PLUGIN_MODULE_CACHE: Lazy<PluginModuleCache> = Lazy::new(Default::default);
42-
43-
#[cfg(feature = "filesystem_cache")]
4436
#[derive(Default)]
45-
pub struct CacheInner {
46-
fs_cache: Option<FileSystemCache>,
47-
// A naive hashmap to the compiled plugin modules.
48-
// Current it doesn't have any invalidation or expiration logics like lru,
49-
// having a lot of plugins may create some memory pressure.
50-
loaded_module_bytes: AHashMap<PathBuf, Module>,
37+
pub struct PluginModuleCacheInner {
38+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
39+
fs_cache_store: Option<FileSystemCache>,
40+
// Stores the string representation of the hash of the plugin module to store into
41+
// FileSystemCache. This works since SWC does not revalidates plugin in single process
42+
// lifecycle.
43+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
44+
fs_cache_hash_store: AHashMap<String, Hash>,
45+
// Generic in-memory cache to the raw bytes, either read by fs or supplied by bindgen.
46+
memory_cache_store: AHashMap<String, Vec<u8>>,
47+
/*
48+
A naive hashmap to the compiled plugin modules.
49+
Current it doesn't have any invalidation or expiration logics like lru,
50+
having a lot of plugins may create some memory pressure.
51+
[TODO]: This is currently disabled, since on the latest wasmer@3 subsequent
52+
plugin load via in memory module causes intermittent heap_get_oob when
53+
host tries to allocate memory inside of the guest.
54+
55+
Current guess is memory instance is being corrupted by the previous run, but
56+
until figure out root cause & fix will only use fs_cache directly.
57+
*/
58+
compiled_module_bytes: AHashMap<String, (wasmer::Store, wasmer::Module)>,
5159
}
5260

53-
#[cfg(feature = "memory_cache")]
54-
#[derive(Default)]
55-
pub struct CacheInner {
56-
// Unlike sys::Module, we'll keep raw bytes from the module instead of js::Module which
57-
// implies bindgen's JsValue
58-
loaded_module_bytes: AHashMap<PathBuf, Vec<u8>>,
61+
impl PluginModuleCacheInner {
62+
/// Check if the cache contains bytes for the corresponding key.
63+
pub fn contains(&self, key: &str) -> bool {
64+
let is_in_cache = self.memory_cache_store.contains_key(key)
65+
|| self.compiled_module_bytes.contains_key(key);
66+
67+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
68+
{
69+
// Instead of accessing FileSystemCache, check if the key have corresponding
70+
// hash since FileSystemCache does not have a way to check if the key
71+
// exists.
72+
return is_in_cache || self.fs_cache_hash_store.contains_key(key);
73+
}
74+
75+
is_in_cache
76+
}
77+
78+
pub fn insert_raw_bytes(&mut self, key: String, value: Vec<u8>) {
79+
self.memory_cache_store.insert(key, value);
80+
}
81+
82+
fn insert_compiled_module_bytes(
83+
&mut self,
84+
key: String,
85+
value: (wasmer::Store, wasmer::Module),
86+
) {
87+
self.compiled_module_bytes.insert(key, value);
88+
}
89+
90+
/// Store plugin module bytes into the cache, from actual filesystem.
91+
pub fn store_bytes_from_path(&mut self, binary_path: &Path, key: &str) -> Result<(), Error> {
92+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
93+
{
94+
let raw_module_bytes =
95+
std::fs::read(binary_path).context("Cannot read plugin from specified path")?;
96+
97+
// If FilesystemCache is available, store serialized bytes into fs.
98+
if let Some(fs_cache_store) = &mut self.fs_cache_store {
99+
let module_bytes_hash = Hash::generate(&raw_module_bytes);
100+
let store = crate::plugin_module_bytes::new_store();
101+
let module = Module::new(&store, raw_module_bytes.clone())
102+
.context("Cannot compile plugin binary")?;
103+
fs_cache_store.store(module_bytes_hash, &module)?;
104+
105+
// Store hash to load from fs_cache_store later.
106+
self.fs_cache_hash_store
107+
.insert(key.to_string(), module_bytes_hash);
108+
109+
// [TODO]: reenable this
110+
// self.insert_compiled_module_bytes(key.to_string(), (store,
111+
// module));
112+
}
113+
114+
// Store raw bytes into memory cache.
115+
self.insert_raw_bytes(key.to_string(), raw_module_bytes);
116+
117+
return Ok(());
118+
}
119+
120+
anyhow::bail!("Filesystem cache is not enabled, cannot read plugin from phsyical path");
121+
}
122+
123+
/// Returns a PluingModuleBytes can be compiled into a wasmer::Module.
124+
/// Depends on the cache availability, it may return a raw bytes or a
125+
/// serialized bytes.
126+
pub fn get(&self, key: &str) -> Option<Box<dyn PluginModuleBytes>> {
127+
// Look for compiled module bytes first, it is the cheapest way to get compile
128+
// wasmer::Module.
129+
if let Some(compiled_module) = self.compiled_module_bytes.get(key) {
130+
return Some(Box::new(CompiledPluginModuleBytes::new(
131+
key.to_string(),
132+
compiled_module.1.clone(),
133+
Store::new(compiled_module.0.engine().clone()),
134+
)));
135+
}
136+
137+
// Next, read serialzied bytes from filesystem cache.
138+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
139+
if let Some(fs_cache_store) = &self.fs_cache_store {
140+
let hash = self.fs_cache_hash_store.get(key)?;
141+
let store = crate::plugin_module_bytes::new_store();
142+
let module = unsafe { fs_cache_store.load(&store, *hash) };
143+
if let Ok(module) = module {
144+
return Some(Box::new(CompiledPluginModuleBytes::new(
145+
key.to_string(),
146+
module,
147+
store,
148+
)));
149+
}
150+
}
151+
152+
// Lastly, look for if there's a raw bytes in memory. This requires compilation
153+
// still, but doesn't go through filesystem access.
154+
if let Some(memory_cache_bytes) = self.memory_cache_store.get(key) {
155+
return Some(Box::new(RawPluginModuleBytes::new(
156+
key.to_string(),
157+
memory_cache_bytes.clone(),
158+
)));
159+
}
160+
None
161+
}
59162
}
60163

61164
#[derive(Default)]
62165
pub struct PluginModuleCache {
63-
inner: OnceCell<Mutex<CacheInner>>,
166+
pub inner: OnceCell<Mutex<PluginModuleCacheInner>>,
64167
/// To prevent concurrent access to `WasmerInstance::new`.
65168
/// This is a precaution only yet, for the preparation of wasm thread
66169
/// support in the future.
67170
instantiation_lock: Mutex<()>,
68171
}
69172

70-
#[cfg(feature = "filesystem_cache")]
173+
impl PluginModuleCache {
174+
pub fn create_inner(
175+
enable_fs_cache_store: bool,
176+
fs_cache_store_root: &Option<String>,
177+
) -> PluginModuleCacheInner {
178+
PluginModuleCacheInner {
179+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
180+
fs_cache_store: if enable_fs_cache_store {
181+
create_filesystem_cache(fs_cache_store_root)
182+
} else {
183+
None
184+
},
185+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
186+
fs_cache_hash_store: Default::default(),
187+
memory_cache_store: Default::default(),
188+
compiled_module_bytes: Default::default(),
189+
}
190+
}
191+
}
192+
193+
#[cfg(all(not(target_arch = "wasm32"), feature = "filesystem_cache"))]
71194
#[tracing::instrument(level = "info", skip_all)]
72195
fn create_filesystem_cache(filesystem_cache_root: &Option<String>) -> Option<FileSystemCache> {
73196
let mut root_path = if let Some(root) = filesystem_cache_root {
@@ -93,159 +216,3 @@ fn create_filesystem_cache(filesystem_cache_root: &Option<String>) -> Option<Fil
93216

94217
None
95218
}
96-
97-
/// Create a new cache instance if not initialized. This can be called multiple
98-
/// time, but any subsequent call will be ignored.
99-
///
100-
/// This fn have a side effect to create path to cache if given path is not
101-
/// resolvable. If root is not specified, it'll generate default root for
102-
/// cache location.
103-
///
104-
/// If cache failed to initialize filesystem cache for given location
105-
/// it'll be serve in-memory cache only.
106-
#[cfg(feature = "filesystem_cache")]
107-
pub fn init_plugin_module_cache_once(filesystem_cache_root: &Option<String>) {
108-
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
109-
Mutex::new(CacheInner {
110-
fs_cache: create_filesystem_cache(filesystem_cache_root),
111-
loaded_module_bytes: Default::default(),
112-
})
113-
});
114-
}
115-
116-
#[cfg(feature = "memory_cache")]
117-
pub fn init_plugin_module_cache_once(_unused_cache_root: &Option<String>) {
118-
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
119-
Mutex::new(CacheInner {
120-
loaded_module_bytes: Default::default(),
121-
})
122-
});
123-
}
124-
125-
impl PluginModuleCache {
126-
/// DO NOT USE unless absolutely necessary. This is mainly for testing
127-
/// purpose.
128-
pub fn new() -> Self {
129-
PluginModuleCache {
130-
inner: OnceCell::from(Mutex::new(Default::default())),
131-
instantiation_lock: Mutex::new(()),
132-
}
133-
}
134-
135-
/// Load a compiled plugin Module from specified path.
136-
/// Since plugin will be initialized per-file transform, this function tries
137-
/// to avoid reading filesystem per each initialization via naive
138-
/// in-memory map which stores raw bytecodes from file. Unlike compiled
139-
/// bytecode cache for the wasm, this is volatile.
140-
///
141-
/// ### Notes
142-
/// [This code](https://github.com/swc-project/swc/blob/fc4c6708f24cda39640fbbfe56123f2f6eeb2474/crates/swc/src/plugin.rs#L19-L44)
143-
/// includes previous incorrect attempt to workaround file read issues.
144-
/// In actual transform, `plugins` is also being called per each transform.
145-
#[cfg(feature = "filesystem_cache")]
146-
#[tracing::instrument(level = "info", skip_all)]
147-
pub fn load_module(&self, wasmer_store: &Store, binary_path: &Path) -> Result<Module, Error> {
148-
let binary_path = binary_path.to_path_buf();
149-
let mut inner_cache = self.inner.get().expect("Cache should be available").lock();
150-
151-
// if constructed Module is available in-memory, directly return it.
152-
// Note we do not invalidate in-memory cache currently: if wasm binary is
153-
// replaced in-process lifecycle (i.e devserver) it won't be reflected.
154-
155-
/*
156-
[TODO]: This is currently disabled, since on the latest wasmer@3 subsequent
157-
plugin load via in memory module causes intermittent heap_get_oob when
158-
host tries to allocate memory inside of the guest.
159-
160-
Current guess is memory instance is being corrupted by the previous run, but
161-
until figure out root cause & fix will only use fs_cache directly.
162-
let in_memory_module = inner_cache.loaded_module_bytes.get(&binary_path);
163-
if let Some(module) = in_memory_module {
164-
return Ok(module.clone());
165-
}*/
166-
167-
let module_bytes =
168-
std::fs::read(&binary_path).context("Cannot read plugin from specified path")?;
169-
let module_bytes_hash = Hash::generate(&module_bytes);
170-
171-
let load_cold_wasm_bytes = || {
172-
let span = tracing::span!(
173-
tracing::Level::INFO,
174-
"load_cold_wasm_bytes",
175-
plugin_module = binary_path.to_str()
176-
);
177-
let span_guard = span.enter();
178-
let _lock = self.instantiation_lock.lock();
179-
let ret =
180-
Module::new(wasmer_store, module_bytes).context("Cannot compile plugin binary");
181-
drop(span_guard);
182-
ret
183-
};
184-
185-
// Try to load compiled bytes from filesystem cache if available.
186-
// Otherwise, cold compile instead.
187-
let module = if let Some(fs_cache) = &mut inner_cache.fs_cache {
188-
let load_result = unsafe { fs_cache.load(wasmer_store, module_bytes_hash) };
189-
if let Ok(module) = load_result {
190-
module
191-
} else {
192-
let cold_bytes = load_cold_wasm_bytes()?;
193-
fs_cache.store(module_bytes_hash, &cold_bytes)?;
194-
cold_bytes
195-
}
196-
} else {
197-
load_cold_wasm_bytes()?
198-
};
199-
200-
inner_cache
201-
.loaded_module_bytes
202-
.insert(binary_path, module.clone());
203-
204-
Ok(module)
205-
}
206-
207-
#[cfg(feature = "memory_cache")]
208-
#[tracing::instrument(level = "info", skip_all)]
209-
pub fn load_module(&self, wasmer_store: &Store, binary_path: &Path) -> Result<Module, Error> {
210-
let binary_path = binary_path.to_path_buf();
211-
let mut inner_cache = self.inner.get().expect("Cache should be available").lock();
212-
213-
// In case of memory_cache, we do not have way to resolve / load modules
214-
// externally. Bail out if cache doesn't have corresponding binary.
215-
let in_memory_module_bytes = inner_cache
216-
.loaded_module_bytes
217-
.get(&binary_path)
218-
.ok_or_else(|| {
219-
anyhow::anyhow!("Could not locate plugin binary {}", binary_path.display())
220-
})?;
221-
222-
//TODO: In native runtime we have to reconstruct module using raw bytes in
223-
// memory cache. requires https://github.com/wasmerio/wasmer/pull/2821
224-
let module = Module::new(wasmer_store, in_memory_module_bytes)?;
225-
226-
Ok(module)
227-
}
228-
229-
/// An experimental interface to store externally loaded module bytes into
230-
/// cache. This is primarily to support swc/wasm-* target, which does
231-
/// not have way to access system, especially filesystem by default.
232-
///
233-
/// Currently this doesn't do any validation or expiration: once a bytes set
234-
/// with specific id, subsequent call will noop.
235-
///
236-
/// This interface is not a public, but also will likely change anytime
237-
/// while stablizing plugin interface.
238-
#[cfg(feature = "memory_cache")]
239-
#[tracing::instrument(level = "info", skip_all)]
240-
pub fn store_once(&self, module_name: &str, module_bytes: Vec<u8>) {
241-
// We use path as canonical id for the cache
242-
let binary_path = PathBuf::from(module_name);
243-
let mut inner_cache = self.inner.get().expect("Cache should be available").lock();
244-
245-
if !inner_cache.loaded_module_bytes.contains_key(&binary_path) {
246-
inner_cache
247-
.loaded_module_bytes
248-
.insert(binary_path, module_bytes);
249-
}
250-
}
251-
}

‎crates/swc_plugin_runner/src/lib.rs

+18-18
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
#![cfg_attr(not(feature = "__rkyv"), allow(warnings))]
22

3-
use std::{path::Path, sync::Arc};
3+
use std::sync::Arc;
44

5-
use anyhow::Error;
6-
use once_cell::sync::Lazy;
75
use swc_common::{plugin::metadata::TransformPluginMetadataContext, SourceMap};
86
use transform_executor::TransformExecutor;
97

@@ -12,37 +10,39 @@ mod host_environment;
1210
#[cfg(feature = "__rkyv")]
1311
mod imported_fn;
1412
#[cfg(feature = "__rkyv")]
15-
mod load_plugin;
16-
#[cfg(feature = "__rkyv")]
1713
mod memory_interop;
14+
pub mod plugin_module_bytes;
1815
mod transform_executor;
1916

17+
use plugin_module_bytes::PluginModuleBytes;
18+
2019
/**
21-
* Attempt to create a executor to run plugin binaries.
22-
* Internally this will try to load binary from given cache which can fail,
23-
* returns error in that case.
24-
*
25-
* Note you CANNOT reuse executor once trasform has been executed: executor
26-
* is stateful.
20+
* Creates an executor to run plugin binaries.
2721
*/
2822
#[cfg(feature = "__rkyv")]
2923
pub fn create_plugin_transform_executor(
30-
path: &Path,
31-
cache: &Lazy<cache::PluginModuleCache>,
3224
source_map: &Arc<SourceMap>,
25+
unresolved_mark: &swc_common::Mark,
3326
metadata_context: &Arc<TransformPluginMetadataContext>,
27+
plugin_module: Box<dyn PluginModuleBytes>,
3428
plugin_config: Option<serde_json::Value>,
35-
) -> Result<TransformExecutor, Error> {
36-
TransformExecutor::new(path, cache, source_map, metadata_context, plugin_config)
29+
) -> TransformExecutor {
30+
TransformExecutor::new(
31+
plugin_module,
32+
source_map,
33+
unresolved_mark,
34+
metadata_context,
35+
plugin_config,
36+
)
3737
}
3838

3939
#[cfg(not(feature = "__rkyv"))]
4040
pub fn create_plugin_transform_executor(
41-
path: &Path,
42-
cache: &Lazy<cache::PluginModuleCache>,
4341
source_map: &Arc<SourceMap>,
42+
unresolved_mark: &swc_common::Mark,
4443
metadata_context: &Arc<TransformPluginMetadataContext>,
44+
plugin_module: Box<dyn PluginModuleBytes>,
4545
plugin_config: Option<serde_json::Value>,
46-
) -> Result<TransformExecutor, Error> {
46+
) -> TransformExecutor {
4747
unimplemented!("Transform plugin cannot be used without serialization support")
4848
}

‎crates/swc_plugin_runner/src/load_plugin.rs

-185
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
use anyhow::Error;
2+
use wasmer::{Module, Store};
3+
4+
/// Creates an instnace of [Store].
5+
///
6+
/// This function exists because we need to disable simd.
7+
#[cfg(not(target_arch = "wasm32"))]
8+
#[allow(unused_mut)]
9+
pub(crate) fn new_store() -> Store {
10+
// Use empty enumset to disable simd.
11+
use enumset::EnumSet;
12+
use wasmer::{BaseTunables, CompilerConfig, EngineBuilder, Target, Triple};
13+
let mut set = EnumSet::new();
14+
15+
// [TODO]: Should we use is_x86_feature_detected! macro instead?
16+
#[cfg(target_arch = "x86_64")]
17+
set.insert(wasmer::CpuFeature::SSE2);
18+
let target = Target::new(Triple::host(), set);
19+
20+
let config = wasmer_compiler_cranelift::Cranelift::default();
21+
let mut engine = EngineBuilder::new(Box::new(config) as Box<dyn CompilerConfig>)
22+
.set_target(Some(target))
23+
.engine();
24+
let tunables = BaseTunables::for_target(engine.target());
25+
engine.set_tunables(tunables);
26+
27+
Store::new(engine)
28+
}
29+
30+
#[cfg(target_arch = "wasm32")]
31+
fn new_store() -> Store {
32+
Store::default()
33+
}
34+
35+
// A trait abstracts plugin's wasm compilation and instantiation.
36+
// Depends on the caller, this could be a simple clone from existing module, or
37+
// load from file system cache.
38+
pub trait PluginModuleBytes {
39+
// Returns a name to the module, typically either path to the plugin or its
40+
// package name.
41+
fn get_module_name(&self) -> &str;
42+
// Returns a compiled wasmer::Module for the plugin module.
43+
fn compile_module(&self) -> Result<(Store, Module), Error>;
44+
}
45+
46+
/// A struct for the plugin contains raw bytes can be compiled into Wasm Module.
47+
#[derive(Clone)]
48+
pub struct RawPluginModuleBytes {
49+
plugin_name: String,
50+
bytes: Vec<u8>,
51+
}
52+
53+
impl PluginModuleBytes for RawPluginModuleBytes {
54+
fn get_module_name(&self) -> &str {
55+
&self.plugin_name
56+
}
57+
58+
fn compile_module(&self) -> Result<(Store, Module), Error> {
59+
let store = new_store();
60+
let module = Module::new(&store, &self.bytes)?;
61+
Ok((store, module))
62+
}
63+
}
64+
65+
impl RawPluginModuleBytes {
66+
pub fn new(identifier: String, bytes: Vec<u8>) -> Self {
67+
Self {
68+
plugin_name: identifier,
69+
bytes,
70+
}
71+
}
72+
}
73+
74+
/// A struct for the plugin contains pre-compiled binary.
75+
/// This is for the cases would like to reuse the compiled module, or either
76+
/// load from FileSystemCache.
77+
pub struct CompiledPluginModuleBytes {
78+
plugin_name: String,
79+
bytes: wasmer::Module,
80+
store: wasmer::Store,
81+
}
82+
83+
impl Clone for CompiledPluginModuleBytes {
84+
fn clone(&self) -> Self {
85+
Self {
86+
plugin_name: self.plugin_name.clone(),
87+
bytes: self.bytes.clone(),
88+
store: Store::new(self.store.engine().clone()),
89+
}
90+
}
91+
}
92+
93+
impl CompiledPluginModuleBytes {
94+
pub fn new(identifier: String, bytes: wasmer::Module, store: wasmer::Store) -> Self {
95+
Self {
96+
plugin_name: identifier,
97+
bytes,
98+
store,
99+
}
100+
}
101+
}
102+
103+
// Allow to `pre` compile wasm module when there is a raw bytes, want to avoid
104+
// to skip the compilation step per each trasform.
105+
impl From<RawPluginModuleBytes> for CompiledPluginModuleBytes {
106+
fn from(raw: RawPluginModuleBytes) -> Self {
107+
let (store, module) = raw.compile_module().unwrap();
108+
Self::new(raw.plugin_name, module, store)
109+
}
110+
}
111+
112+
impl PluginModuleBytes for CompiledPluginModuleBytes {
113+
fn get_module_name(&self) -> &str {
114+
&self.plugin_name
115+
}
116+
117+
fn compile_module(&self) -> Result<(Store, Module), Error> {
118+
Ok((Store::new(self.store.engine().clone()), self.bytes.clone()))
119+
}
120+
}

‎crates/swc_plugin_runner/src/transform_executor.rs

+424-43
Large diffs are not rendered by default.

‎crates/swc_plugin_runner/tests/css_rkyv.rs

+35-28
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ use swc_common::{
1414
collections::AHashMap, plugin::metadata::TransformPluginMetadataContext, sync::Lazy, FileName,
1515
Mark,
1616
};
17-
use swc_plugin_runner::cache::{init_plugin_module_cache_once, PLUGIN_MODULE_CACHE};
1817
use tracing::info;
1918

2019
/// Returns the path to the built plugin
2120
fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
22-
init_plugin_module_cache_once(&None);
2321
{
2422
let mut cmd = Command::new("cargo");
2523
cmd.current_dir(dir);
@@ -49,23 +47,35 @@ fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
4947
}
5048

5149
#[cfg(feature = "__rkyv")]
52-
static PLUGIN_PATH: Lazy<PathBuf> = Lazy::new(|| {
53-
build_plugin(
54-
&PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
55-
.join("tests")
56-
.join("css-plugins")
57-
.join("swc_noop_plugin"),
58-
)
59-
.unwrap()
60-
});
50+
static PLUGIN_BYTES: Lazy<swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes> =
51+
Lazy::new(|| {
52+
let path = build_plugin(
53+
&PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
54+
.join("tests")
55+
.join("css-plugins")
56+
.join("swc_noop_plugin"),
57+
)
58+
.unwrap();
59+
60+
let raw_module_bytes = std::fs::read(&path).expect("Should able to read plugin bytes");
61+
let store = wasmer::Store::default();
62+
let module = wasmer::Module::new(&store, raw_module_bytes).unwrap();
63+
64+
swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes::new(
65+
path.as_os_str()
66+
.to_str()
67+
.expect("Should able to get path")
68+
.to_string(),
69+
module,
70+
store,
71+
)
72+
});
6173

6274
#[cfg(feature = "__rkyv")]
6375
#[testing::fixture("../swc_css_parser/tests/fixture/**/input.css")]
6476
fn invoke(input: PathBuf) -> Result<(), Error> {
6577
use swc_css_ast::Stylesheet;
6678

67-
let path = PLUGIN_PATH.clone();
68-
6979
// run single plugin
7080
testing::run_test(false, |cm, _handler| {
7181
let fm = cm.new_source_file(FileName::Anon, "console.log(foo)".into());
@@ -88,22 +98,21 @@ fn invoke(input: PathBuf) -> Result<(), Error> {
8898
.collect();
8999

90100
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
91-
&path,
92-
&PLUGIN_MODULE_CACHE,
93101
&cm,
102+
&Mark::new(),
94103
&Arc::new(TransformPluginMetadataContext::new(
95104
None,
96105
"development".to_string(),
97106
Some(experimental_metadata),
98107
)),
108+
Box::new(PLUGIN_BYTES.clone()),
99109
Some(json!({ "pluginConfig": "testValue" })),
100-
)
101-
.expect("Should load plugin");
110+
);
102111

103112
info!("Created transform executor");
104113

105114
let program_bytes = plugin_transform_executor
106-
.transform(&program, Mark::new(), false)
115+
.transform(&program, Some(false))
107116
.expect("Plugin should apply transform");
108117

109118
let program: Stylesheet = program_bytes
@@ -140,38 +149,36 @@ fn invoke(input: PathBuf) -> Result<(), Error> {
140149
.collect();
141150

142151
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
143-
&path,
144-
&PLUGIN_MODULE_CACHE,
145152
&cm,
153+
&Mark::new(),
146154
&Arc::new(TransformPluginMetadataContext::new(
147155
None,
148156
"development".to_string(),
149157
Some(experimental_metadata.clone()),
150158
)),
159+
Box::new(PLUGIN_BYTES.clone()),
151160
Some(json!({ "pluginConfig": "testValue" })),
152-
)
153-
.expect("Should load first plugin");
161+
);
154162

155163
serialized_program = plugin_transform_executor
156-
.transform(&serialized_program, Mark::new(), false)
164+
.transform(&serialized_program, Some(false))
157165
.expect("Plugin should apply transform");
158166

159167
// TODO: we'll need to apply 2 different plugins
160168
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
161-
&path,
162-
&PLUGIN_MODULE_CACHE,
163169
&cm,
170+
&Mark::new(),
164171
&Arc::new(TransformPluginMetadataContext::new(
165172
None,
166173
"development".to_string(),
167174
Some(experimental_metadata),
168175
)),
176+
Box::new(PLUGIN_BYTES.clone()),
169177
Some(json!({ "pluginConfig": "testValue" })),
170-
)
171-
.expect("Should load second plugin");
178+
);
172179

173180
serialized_program = plugin_transform_executor
174-
.transform(&serialized_program, Mark::new(), false)
181+
.transform(&serialized_program, Some(false))
175182
.expect("Plugin should apply transform");
176183

177184
let program: Stylesheet = serialized_program

‎crates/swc_plugin_runner/tests/ecma_integration.rs

+51-41
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use swc_common::{
1818
use swc_ecma_ast::{CallExpr, Callee, EsVersion, Expr, Lit, MemberExpr, Program, Str};
1919
use swc_ecma_parser::{parse_file_as_program, Syntax};
2020
use swc_ecma_visit::{Visit, VisitWith};
21-
use swc_plugin_runner::cache::PluginModuleCache;
2221

2322
/// Returns the path to the built plugin
2423
fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
@@ -71,18 +70,36 @@ impl Visit for TestVisitor {
7170
}
7271
}
7372

73+
#[cfg(feature = "__rkyv")]
74+
static PLUGIN_BYTES: Lazy<swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes> =
75+
Lazy::new(|| {
76+
let path = build_plugin(
77+
&PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
78+
.join("tests")
79+
.join("fixture")
80+
.join("swc_internal_plugin"),
81+
)
82+
.unwrap();
83+
84+
let raw_module_bytes = std::fs::read(&path).expect("Should able to read plugin bytes");
85+
let store = wasmer::Store::default();
86+
let module = wasmer::Module::new(&store, raw_module_bytes).unwrap();
87+
88+
swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes::new(
89+
path.as_os_str()
90+
.to_str()
91+
.expect("Should able to get path")
92+
.to_string(),
93+
module,
94+
store,
95+
)
96+
});
97+
7498
#[cfg(feature = "__rkyv")]
7599
#[test]
76100
fn internal() -> Result<(), Error> {
77101
use swc_common::plugin::serialized::VersionedSerializable;
78102

79-
let path = build_plugin(
80-
&PathBuf::from(env::var("CARGO_MANIFEST_DIR")?)
81-
.join("tests")
82-
.join("fixture")
83-
.join("swc_internal_plugin"),
84-
)?;
85-
86103
// run single plugin
87104
testing::run_test(false, |cm, _handler| {
88105
let fm = cm.new_source_file(FileName::Anon, "console.log(foo)".into());
@@ -108,27 +125,27 @@ fn internal() -> Result<(), Error> {
108125
.into_iter()
109126
.collect();
110127

111-
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
112128
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
113-
&path,
114-
&cache,
115129
&cm,
130+
&Mark::new(),
116131
&Arc::new(TransformPluginMetadataContext::new(
117132
None,
118133
"development".to_string(),
119134
Some(experimental_metadata),
120135
)),
136+
Box::new(PLUGIN_BYTES.clone()),
121137
Some(json!({ "pluginConfig": "testValue" })),
122-
)
123-
.expect("Should load plugin");
138+
);
124139

140+
/* [TODO]: reenable this later
125141
assert!(!plugin_transform_executor
126142
.plugin_core_diag
127143
.pkg_version
128144
.is_empty());
145+
*/
129146

130147
let program_bytes = plugin_transform_executor
131-
.transform(&program, Mark::new(), false)
148+
.transform(&program, Some(false))
132149
.expect("Plugin should apply transform");
133150

134151
let program: Program = program_bytes
@@ -172,25 +189,21 @@ fn internal() -> Result<(), Error> {
172189
.into_iter()
173190
.collect();
174191

175-
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
176-
177192
let _res = HANDLER.set(&handler, || {
178-
let mut plugin_transform_executor =
179-
swc_plugin_runner::create_plugin_transform_executor(
180-
&path,
181-
&cache,
182-
&cm,
183-
&Arc::new(TransformPluginMetadataContext::new(
184-
None,
185-
"development".to_string(),
186-
Some(experimental_metadata),
187-
)),
188-
Some(json!({ "pluginConfig": "testValue" })),
189-
)
190-
.expect("Should load plugin");
193+
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
194+
&cm,
195+
&Mark::new(),
196+
&Arc::new(TransformPluginMetadataContext::new(
197+
None,
198+
"development".to_string(),
199+
Some(experimental_metadata),
200+
)),
201+
Box::new(PLUGIN_BYTES.clone()),
202+
Some(json!({ "pluginConfig": "testValue" })),
203+
);
191204

192205
plugin_transform_executor
193-
.transform(&program, Mark::new(), false)
206+
.transform(&program, Some(false))
194207
.expect("Plugin should apply transform")
195208
});
196209

@@ -214,7 +227,6 @@ fn internal() -> Result<(), Error> {
214227
let mut serialized_program =
215228
PluginSerializedBytes::try_serialize(&VersionedSerializable::new(program))
216229
.expect("Should serializable");
217-
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
218230

219231
let experimental_metadata: AHashMap<String, String> = [
220232
(
@@ -227,38 +239,36 @@ fn internal() -> Result<(), Error> {
227239
.collect();
228240

229241
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
230-
&path,
231-
&cache,
232242
&cm,
243+
&Mark::new(),
233244
&Arc::new(TransformPluginMetadataContext::new(
234245
None,
235246
"development".to_string(),
236247
Some(experimental_metadata.clone()),
237248
)),
249+
Box::new(PLUGIN_BYTES.clone()),
238250
Some(json!({ "pluginConfig": "testValue" })),
239-
)
240-
.expect("Should load plugin");
251+
);
241252

242253
serialized_program = plugin_transform_executor
243-
.transform(&serialized_program, Mark::new(), false)
254+
.transform(&serialized_program, Some(false))
244255
.expect("Plugin should apply transform");
245256

246257
// TODO: we'll need to apply 2 different plugins
247258
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
248-
&path,
249-
&cache,
250259
&cm,
260+
&Mark::new(),
251261
&Arc::new(TransformPluginMetadataContext::new(
252262
None,
253263
"development".to_string(),
254264
Some(experimental_metadata),
255265
)),
266+
Box::new(PLUGIN_BYTES.clone()),
256267
Some(json!({ "pluginConfig": "testValue" })),
257-
)
258-
.expect("Should load plugin");
268+
);
259269

260270
serialized_program = plugin_transform_executor
261-
.transform(&serialized_program, Mark::new(), false)
271+
.transform(&serialized_program, Some(false))
262272
.expect("Plugin should apply transform");
263273

264274
let program: Program = serialized_program

‎crates/swc_plugin_runner/tests/ecma_rkyv.rs

+35-30
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@ use swc_common::{
1616
};
1717
use swc_ecma_ast::{EsVersion, Program};
1818
use swc_ecma_parser::{parse_file_as_program, Syntax, TsConfig};
19-
use swc_plugin_runner::cache::{init_plugin_module_cache_once, PLUGIN_MODULE_CACHE};
2019
use tracing::info;
2120

2221
/// Returns the path to the built plugin
2322
fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
24-
init_plugin_module_cache_once(&None);
2523
{
2624
let mut cmd = Command::new("cargo");
2725
cmd.current_dir(dir);
@@ -51,22 +49,34 @@ fn build_plugin(dir: &Path) -> Result<PathBuf, Error> {
5149
}
5250

5351
#[cfg(feature = "__rkyv")]
54-
static PLUGIN_PATH: Lazy<PathBuf> = Lazy::new(|| {
55-
build_plugin(
56-
&PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
57-
.join("tests")
58-
.join("fixture")
59-
.join("swc_noop_plugin"),
60-
)
61-
.unwrap()
62-
});
52+
static PLUGIN_BYTES: Lazy<swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes> =
53+
Lazy::new(|| {
54+
let path = build_plugin(
55+
&PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap())
56+
.join("tests")
57+
.join("fixture")
58+
.join("swc_noop_plugin"),
59+
)
60+
.unwrap();
61+
62+
let raw_module_bytes = std::fs::read(&path).expect("Should able to read plugin bytes");
63+
let store = wasmer::Store::default();
64+
let module = wasmer::Module::new(&store, raw_module_bytes).unwrap();
65+
66+
swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes::new(
67+
path.as_os_str()
68+
.to_str()
69+
.expect("Should able to get path")
70+
.to_string(),
71+
module,
72+
store,
73+
)
74+
});
6375

6476
#[cfg(feature = "__rkyv")]
6577
#[testing::fixture("../swc_ecma_parser/tests/tsc/*.ts")]
6678
#[testing::fixture("../swc_ecma_parser/tests/tsc/*.tsx")]
6779
fn internal(input: PathBuf) -> Result<(), Error> {
68-
let path = PLUGIN_PATH.clone();
69-
7080
// run single plugin
7181
testing::run_test(false, |cm, _handler| {
7282
let fm = cm.new_source_file(FileName::Anon, "console.log(foo)".into());
@@ -97,25 +107,22 @@ fn internal(input: PathBuf) -> Result<(), Error> {
97107
.into_iter()
98108
.collect();
99109

100-
info!("Creating cache");
101-
102110
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
103-
&path,
104-
&PLUGIN_MODULE_CACHE,
105111
&cm,
112+
&Mark::new(),
106113
&Arc::new(TransformPluginMetadataContext::new(
107114
None,
108115
"development".to_string(),
109116
Some(experimental_metadata),
110117
)),
118+
Box::new(PLUGIN_BYTES.clone()),
111119
Some(json!({ "pluginConfig": "testValue" })),
112-
)
113-
.expect("Should load plugin");
120+
);
114121

115122
info!("Created transform executor");
116123

117124
let program_bytes = plugin_transform_executor
118-
.transform(&program, Mark::new(), false)
125+
.transform(&program, Some(false))
119126
.expect("Plugin should apply transform");
120127

121128
let program: Program = program_bytes
@@ -158,38 +165,36 @@ fn internal(input: PathBuf) -> Result<(), Error> {
158165
.collect();
159166

160167
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
161-
&path,
162-
&PLUGIN_MODULE_CACHE,
163168
&cm,
169+
&Mark::new(),
164170
&Arc::new(TransformPluginMetadataContext::new(
165171
None,
166172
"development".to_string(),
167173
Some(experimental_metadata.clone()),
168174
)),
175+
Box::new(PLUGIN_BYTES.clone()),
169176
Some(json!({ "pluginConfig": "testValue" })),
170-
)
171-
.expect("Should load plugin");
177+
);
172178

173179
serialized_program = plugin_transform_executor
174-
.transform(&serialized_program, Mark::new(), false)
180+
.transform(&serialized_program, Some(false))
175181
.expect("Plugin should apply transform");
176182

177183
// TODO: we'll need to apply 2 different plugins
178184
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
179-
&path,
180-
&PLUGIN_MODULE_CACHE,
181185
&cm,
186+
&Mark::new(),
182187
&Arc::new(TransformPluginMetadataContext::new(
183188
None,
184189
"development".to_string(),
185190
Some(experimental_metadata),
186191
)),
192+
Box::new(PLUGIN_BYTES.clone()),
187193
Some(json!({ "pluginConfig": "testValue" })),
188-
)
189-
.expect("Should load plugin");
194+
);
190195

191196
serialized_program = plugin_transform_executor
192-
.transform(&serialized_program, Mark::new(), false)
197+
.transform(&serialized_program, Some(false))
193198
.expect("Plugin should apply transform");
194199

195200
let program: Program = serialized_program

‎crates/swc_plugin_runner/tests/issues.rs

+22-10
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,10 @@ use anyhow::{anyhow, Error};
1111
use serde_json::json;
1212
#[cfg(feature = "__rkyv")]
1313
use swc_common::plugin::serialized::PluginSerializedBytes;
14-
use swc_common::{
15-
collections::AHashMap, plugin::metadata::TransformPluginMetadataContext, sync::Lazy, Mark,
16-
};
14+
use swc_common::{collections::AHashMap, plugin::metadata::TransformPluginMetadataContext, Mark};
1715
use swc_ecma_ast::{CallExpr, Callee, EsVersion, Expr, Lit, MemberExpr, Program, Str};
1816
use swc_ecma_parser::{parse_file_as_program, Syntax};
1917
use swc_ecma_visit::Visit;
20-
use swc_plugin_runner::cache::PluginModuleCache;
2118

2219
/// Returns the path to the built plugin
2320
fn build_plugin(dir: &Path, crate_name: &str) -> Result<PathBuf, Error> {
@@ -112,27 +109,42 @@ fn issue_6404() -> Result<(), Error> {
112109
.into_iter()
113110
.collect();
114111

115-
let cache: Lazy<PluginModuleCache> = Lazy::new(PluginModuleCache::new);
112+
let raw_module_bytes =
113+
std::fs::read(&plugin_path).expect("Should able to read plugin bytes");
114+
let store = wasmer::Store::default();
115+
let module = wasmer::Module::new(&store, raw_module_bytes).unwrap();
116+
117+
let plugin_module = swc_plugin_runner::plugin_module_bytes::CompiledPluginModuleBytes::new(
118+
plugin_path
119+
.as_os_str()
120+
.to_str()
121+
.expect("Should able to get path")
122+
.to_string(),
123+
module,
124+
store,
125+
);
126+
116127
let mut plugin_transform_executor = swc_plugin_runner::create_plugin_transform_executor(
117-
&plugin_path,
118-
&cache,
119128
&cm,
129+
&Mark::new(),
120130
&Arc::new(TransformPluginMetadataContext::new(
121131
None,
122132
"development".to_string(),
123133
Some(experimental_metadata),
124134
)),
135+
Box::new(plugin_module),
125136
Some(json!({ "pluginConfig": "testValue" })),
126-
)
127-
.expect("Should load plugin");
137+
);
128138

139+
/* [TODO]: reenable this test
129140
assert!(!plugin_transform_executor
130141
.plugin_core_diag
131142
.pkg_version
132143
.is_empty());
144+
*/
133145

134146
let program_bytes = plugin_transform_executor
135-
.transform(&program, Mark::new(), false)
147+
.transform(&program, Some(false))
136148
.expect("Plugin should apply transform");
137149

138150
let _: Program = program_bytes

1 commit comments

Comments
 (1)

github-actions[bot] commented on May 18, 2023

@github-actions[bot]

Benchmark

Benchmark suite Current: ac5ab60 Previous: 5dbbbea Ratio
es/full/bugs-1 252592 ns/iter (± 5424) 257674 ns/iter (± 7664) 0.98
es/full/minify/libraries/antd 1202844503 ns/iter (± 4954937) 1266231558 ns/iter (± 17322954) 0.95
es/full/minify/libraries/d3 242352186 ns/iter (± 3807527) 250740202 ns/iter (± 3279625) 0.97
es/full/minify/libraries/echarts 980360776 ns/iter (± 16942866) 1013967363 ns/iter (± 6882597) 0.97
es/full/minify/libraries/jquery 77325100 ns/iter (± 220040) 77764633 ns/iter (± 311808) 0.99
es/full/minify/libraries/lodash 87289589 ns/iter (± 171655) 88251649 ns/iter (± 312335) 0.99
es/full/minify/libraries/moment 45097304 ns/iter (± 72779) 45181276 ns/iter (± 220821) 1.00
es/full/minify/libraries/react 16352722 ns/iter (± 55096) 16362531 ns/iter (± 72352) 1.00
es/full/minify/libraries/terser 200055431 ns/iter (± 985227) 203958448 ns/iter (± 1742757) 0.98
es/full/minify/libraries/three 344506794 ns/iter (± 3934984) 356163069 ns/iter (± 1397637) 0.97
es/full/minify/libraries/typescript 2438984073 ns/iter (± 18420607) 2546082292 ns/iter (± 17576069) 0.96
es/full/minify/libraries/victory 509710826 ns/iter (± 4560544) 557689635 ns/iter (± 13252207) 0.91
es/full/minify/libraries/vue 109674007 ns/iter (± 548997) 111454460 ns/iter (± 361771) 0.98
es/full/codegen/es3 31548 ns/iter (± 63) 30830 ns/iter (± 81) 1.02
es/full/codegen/es5 31450 ns/iter (± 41) 30778 ns/iter (± 28) 1.02
es/full/codegen/es2015 31583 ns/iter (± 83) 30791 ns/iter (± 53) 1.03
es/full/codegen/es2016 31621 ns/iter (± 55) 30841 ns/iter (± 47) 1.03
es/full/codegen/es2017 31695 ns/iter (± 59) 30837 ns/iter (± 52) 1.03
es/full/codegen/es2018 31677 ns/iter (± 65) 30847 ns/iter (± 55) 1.03
es/full/codegen/es2019 31567 ns/iter (± 90) 30772 ns/iter (± 31) 1.03
es/full/codegen/es2020 31626 ns/iter (± 74) 30815 ns/iter (± 51) 1.03
es/full/all/es3 157139680 ns/iter (± 597935) 155922442 ns/iter (± 809464) 1.01
es/full/all/es5 150520055 ns/iter (± 640589) 149541304 ns/iter (± 999754) 1.01
es/full/all/es2015 112126624 ns/iter (± 541628) 109853283 ns/iter (± 692847) 1.02
es/full/all/es2016 111067630 ns/iter (± 677859) 108487420 ns/iter (± 509376) 1.02
es/full/all/es2017 109804842 ns/iter (± 295091) 108601255 ns/iter (± 506021) 1.01
es/full/all/es2018 108435236 ns/iter (± 763102) 106717214 ns/iter (± 682804) 1.02
es/full/all/es2019 107569052 ns/iter (± 378890) 106150576 ns/iter (± 705550) 1.01
es/full/all/es2020 102757893 ns/iter (± 483932) 101121347 ns/iter (± 442632) 1.02
es/full/parser 466064 ns/iter (± 4742) 451937 ns/iter (± 5434) 1.03
es/full/base/fixer 17322 ns/iter (± 35) 17828 ns/iter (± 116) 0.97
es/full/base/resolver_and_hygiene 75371 ns/iter (± 114) 74803 ns/iter (± 209) 1.01
serialization of serde 112 ns/iter (± 0) 115 ns/iter (± 0) 0.97
css/minify/libraries/bootstrap 23466855 ns/iter (± 106481) 23407964 ns/iter (± 62960) 1.00
css/visitor/compare/clone 1648014 ns/iter (± 2306) 1655630 ns/iter (± 7660) 1.00
css/visitor/compare/visit_mut_span 1781773 ns/iter (± 11865) 1803241 ns/iter (± 5888) 0.99
css/visitor/compare/visit_mut_span_panic 1858557 ns/iter (± 5501) 1864307 ns/iter (± 3125) 1.00
css/visitor/compare/fold_span 2538700 ns/iter (± 13291) 2582450 ns/iter (± 12922) 0.98
css/visitor/compare/fold_span_panic 2722417 ns/iter (± 10002) 2746327 ns/iter (± 12913) 0.99
css/lexer/bootstrap_5_1_3 4550821 ns/iter (± 3565) 4615709 ns/iter (± 4566) 0.99
css/lexer/foundation_6_7_4 3782648 ns/iter (± 2110) 3902842 ns/iter (± 2021) 0.97
css/lexer/tailwind_3_1_1 716361 ns/iter (± 176) 749177 ns/iter (± 266) 0.96
css/parser/bootstrap_5_1_3 18160277 ns/iter (± 19317) 18103554 ns/iter (± 21624) 1.00
css/parser/foundation_6_7_4 14509286 ns/iter (± 12483) 14461561 ns/iter (± 30099) 1.00
css/parser/tailwind_3_1_1 2797938 ns/iter (± 2586) 2824616 ns/iter (± 5648) 0.99
es/codegen/colors 732469 ns/iter (± 399948) 730739 ns/iter (± 400259) 1.00
es/codegen/large 3027150 ns/iter (± 1590754) 2966580 ns/iter (± 1574944) 1.02
es/codegen/with-parser/colors 42973 ns/iter (± 482) 43364 ns/iter (± 478) 0.99
es/codegen/with-parser/large 475056 ns/iter (± 1076) 477160 ns/iter (± 874) 1.00
es/minify/libraries/antd 1063905053 ns/iter (± 10946120) 1113966302 ns/iter (± 6138488) 0.96
es/minify/libraries/d3 214423687 ns/iter (± 946122) 216890742 ns/iter (± 896499) 0.99
es/minify/libraries/echarts 843397903 ns/iter (± 5085529) 892573497 ns/iter (± 5422988) 0.94
es/minify/libraries/jquery 68999765 ns/iter (± 133936) 69832194 ns/iter (± 986298) 0.99
es/minify/libraries/lodash 79335248 ns/iter (± 121033) 80058998 ns/iter (± 220803) 0.99
es/minify/libraries/moment 40508573 ns/iter (± 97458) 40390891 ns/iter (± 117549) 1.00
es/minify/libraries/react 14865390 ns/iter (± 28036) 14791940 ns/iter (± 29838) 1.00
es/minify/libraries/terser 176139926 ns/iter (± 1862284) 177969826 ns/iter (± 782232) 0.99
es/minify/libraries/three 295337616 ns/iter (± 7401562) 305079363 ns/iter (± 1757013) 0.97
es/minify/libraries/typescript 2119142460 ns/iter (± 16202173) 2176181947 ns/iter (± 7917582) 0.97
es/minify/libraries/victory 439241424 ns/iter (± 3268040) 461679321 ns/iter (± 4176874) 0.95
es/minify/libraries/vue 100779880 ns/iter (± 492314) 100670436 ns/iter (± 432000) 1.00
es/visitor/compare/clone 1996976 ns/iter (± 5140) 2016809 ns/iter (± 3989) 0.99
es/visitor/compare/visit_mut_span 2328264 ns/iter (± 1582) 2350596 ns/iter (± 2472) 0.99
es/visitor/compare/visit_mut_span_panic 2380152 ns/iter (± 2695) 2409314 ns/iter (± 2830) 0.99
es/visitor/compare/fold_span 3402995 ns/iter (± 4698) 3430909 ns/iter (± 4937) 0.99
es/visitor/compare/fold_span_panic 3544476 ns/iter (± 4302) 3565743 ns/iter (± 3340) 0.99
es/lexer/colors 11636 ns/iter (± 15) 11501 ns/iter (± 6) 1.01
es/lexer/angular 5643819 ns/iter (± 5535) 5689798 ns/iter (± 13076) 0.99
es/lexer/backbone 718171 ns/iter (± 1742) 731166 ns/iter (± 3227) 0.98
es/lexer/jquery 4041167 ns/iter (± 1337) 4092041 ns/iter (± 4310) 0.99
es/lexer/jquery mobile 6256846 ns/iter (± 11114) 6282331 ns/iter (± 3795) 1.00
es/lexer/mootools 3207482 ns/iter (± 1629) 3244644 ns/iter (± 907) 0.99
es/lexer/underscore 590211 ns/iter (± 1393) 603279 ns/iter (± 364) 0.98
es/lexer/three 19129693 ns/iter (± 8588) 19259424 ns/iter (± 24213) 0.99
es/lexer/yui 3531819 ns/iter (± 12102) 3514391 ns/iter (± 26595) 1.00
es/parser/colors 25607 ns/iter (± 65) 25624 ns/iter (± 57) 1.00
es/parser/angular 13039645 ns/iter (± 50413) 13173078 ns/iter (± 68775) 0.99
es/parser/backbone 1943160 ns/iter (± 10513) 1943729 ns/iter (± 6275) 1.00
es/parser/jquery 10518069 ns/iter (± 36331) 10667730 ns/iter (± 216945) 0.99
es/parser/jquery mobile 16222263 ns/iter (± 88149) 16276529 ns/iter (± 80169) 1.00
es/parser/mootools 8114008 ns/iter (± 12688) 8104265 ns/iter (± 146433) 1.00
es/parser/underscore 1662798 ns/iter (± 10002) 1659190 ns/iter (± 10852) 1.00
es/parser/three 45337975 ns/iter (± 155210) 46954920 ns/iter (± 245407) 0.97
es/parser/yui 8043391 ns/iter (± 43835) 8094190 ns/iter (± 43765) 0.99
es/preset-env/usage/builtin_type 146213 ns/iter (± 39620) 146733 ns/iter (± 40123) 1.00
es/preset-env/usage/property 15569 ns/iter (± 40) 15091 ns/iter (± 49) 1.03
es/resolver/typescript 90299073 ns/iter (± 1047880) 91541535 ns/iter (± 957182) 0.99
es/fixer/typescript 65482578 ns/iter (± 1174484) 67354908 ns/iter (± 312109) 0.97
es/hygiene/typescript 133171134 ns/iter (± 1319213) 137438837 ns/iter (± 1494119) 0.97
es/resolver_with_hygiene/typescript 232722111 ns/iter (± 973419) 240070803 ns/iter (± 1642770) 0.97
es/visitor/base-perf/module_clone 58902 ns/iter (± 187) 59133 ns/iter (± 461) 1.00
es/visitor/base-perf/fold_empty 63197 ns/iter (± 190) 63100 ns/iter (± 350) 1.00
es/visitor/base-perf/fold_noop_impl_all 63464 ns/iter (± 217) 63028 ns/iter (± 326) 1.01
es/visitor/base-perf/fold_noop_impl_vec 63470 ns/iter (± 237) 63354 ns/iter (± 353) 1.00
es/visitor/base-perf/boxing_boxed_clone 53 ns/iter (± 0) 69 ns/iter (± 9) 0.77
es/visitor/base-perf/boxing_unboxed_clone 36 ns/iter (± 0) 61 ns/iter (± 0) 0.59
es/visitor/base-perf/boxing_boxed 112 ns/iter (± 0) 117 ns/iter (± 2) 0.96
es/visitor/base-perf/boxing_unboxed 78 ns/iter (± 0) 78 ns/iter (± 0) 1
es/visitor/base-perf/visit_empty 0 ns/iter (± 0) 0 ns/iter (± 0) NaN
es/visitor/base-perf/visit_contains_this 2660 ns/iter (± 11) 2635 ns/iter (± 36) 1.01
es/base/parallel/resolver/typescript 3974713911 ns/iter (± 296483813) 3900500330 ns/iter (± 281054074) 1.02
es/base/parallel/hygiene/typescript 1423983835 ns/iter (± 18474203) 1462849993 ns/iter (± 17650767) 0.97
misc/visitors/time-complexity/time 5 105 ns/iter (± 1) 101 ns/iter (± 0) 1.04
misc/visitors/time-complexity/time 10 263 ns/iter (± 0) 386 ns/iter (± 3) 0.68
misc/visitors/time-complexity/time 15 719 ns/iter (± 5) 717 ns/iter (± 1) 1.00
misc/visitors/time-complexity/time 20 1137 ns/iter (± 72) 1094 ns/iter (± 5) 1.04
misc/visitors/time-complexity/time 40 3826 ns/iter (± 149) 3740 ns/iter (± 8) 1.02
misc/visitors/time-complexity/time 60 7745 ns/iter (± 59) 7742 ns/iter (± 9) 1.00
es/full-target/es2016 225429 ns/iter (± 407) 223877 ns/iter (± 1121) 1.01
es/full-target/es2017 214775 ns/iter (± 548) 213539 ns/iter (± 574) 1.01
es/full-target/es2018 202289 ns/iter (± 518) 202499 ns/iter (± 749) 1.00
es2020_nullish_coalescing 69559 ns/iter (± 315) 69209 ns/iter (± 422) 1.01
es2020_optional_chaining 94329 ns/iter (± 611) 94649 ns/iter (± 242) 1.00
es2022_class_properties 116083 ns/iter (± 254) 118607 ns/iter (± 323) 0.98
es2018_object_rest_spread 73825 ns/iter (± 513) 74109 ns/iter (± 256) 1.00
es2019_optional_catch_binding 63171 ns/iter (± 184) 63332 ns/iter (± 141) 1.00
es2017_async_to_generator 63126 ns/iter (± 153) 63463 ns/iter (± 186) 0.99
es2016_exponentiation 68100 ns/iter (± 275) 67947 ns/iter (± 240) 1.00
es2015_arrow 71111 ns/iter (± 795) 70798 ns/iter (± 171) 1.00
es2015_block_scoped_fn 67534 ns/iter (± 143) 67556 ns/iter (± 320) 1.00
es2015_block_scoping 118896 ns/iter (± 517) 119113 ns/iter (± 243) 1.00

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.