mirror of
https://github.com/swc-project/swc.git
synced 2024-12-23 13:51:19 +03:00
refactor(plugin/runner): Reuse wasmer
This commit is contained in:
parent
c3895ca9aa
commit
28ff0592a4
952
Cargo.lock
generated
952
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -21,10 +21,8 @@ swc_common = {version = "0.16.0", path = "../swc_common", features = ["plugin-rt
|
||||
swc_ecma_ast = {version = "0.62.0", path = "../swc_ecma_ast"}
|
||||
swc_ecma_parser = {version = "0.84.0", path = "../swc_ecma_parser"}
|
||||
swc_plugin_js_api = {version = "0.8.0", path = "../swc_plugin_js_api"}
|
||||
wasmtime = "0.32.1"
|
||||
wasmtime-wasi = "0.32.1"
|
||||
wasmer = "2.1.1"
|
||||
wasmer-cache = "2.1.1"
|
||||
|
||||
[dev-dependencies]
|
||||
testing = {version = "0.17.0", path = "../testing"}
|
||||
|
||||
[features]
|
||||
|
@ -9,10 +9,8 @@ use parking_lot::Mutex;
|
||||
use resolve::PluginCache;
|
||||
use swc_common::collections::AHashMap;
|
||||
use swc_ecma_ast::Program;
|
||||
// we have few targets wasmer does not supports yet
|
||||
// https://github.com/wasmerio/wasmer/issues/2324
|
||||
use wasmtime::{Engine, Linker, Store};
|
||||
use wasmtime_wasi::WasiCtxBuilder;
|
||||
use wasmer::{imports, Instance, Module, Store};
|
||||
use wasmer_cache::{Cache, Hash};
|
||||
|
||||
pub mod resolve;
|
||||
|
||||
@ -29,7 +27,7 @@ pub mod resolve;
|
||||
/// [This code](https://github.com/swc-project/swc/blob/fc4c6708f24cda39640fbbfe56123f2f6eeb2474/crates/swc/src/plugin.rs#L19-L44)
|
||||
/// includes previous incorrect attempt to workaround file read issues.
|
||||
/// In actual transform, `plugins` is also being called per each transform.
|
||||
fn load_plugin(plugin_path: &Path, _cache: &mut Option<PluginCache>) -> Result<(), Error> {
|
||||
fn load_plugin(plugin_path: &Path, cache: &mut Option<PluginCache>) -> Result<Instance, Error> {
|
||||
static BYTE_CACHE: Lazy<Mutex<AHashMap<PathBuf, Arc<Vec<u8>>>>> =
|
||||
Lazy::new(|| Default::default());
|
||||
|
||||
@ -38,33 +36,72 @@ fn load_plugin(plugin_path: &Path, _cache: &mut Option<PluginCache>) -> Result<(
|
||||
// process won't be reflected.
|
||||
// 2. If reading binary fails somehow it won't bail out but keep retry.
|
||||
let module_bytes_key = plugin_path.to_path_buf();
|
||||
let _module_bytes =
|
||||
if let Some(cached_bytes) = BYTE_CACHE.lock().get(&module_bytes_key).cloned() {
|
||||
cached_bytes
|
||||
} else {
|
||||
let fresh_module_bytes = std::fs::read(plugin_path)
|
||||
.map(Arc::new)
|
||||
.context("Cannot read plugin from specified path")?;
|
||||
BYTE_CACHE
|
||||
.lock()
|
||||
.insert(module_bytes_key, fresh_module_bytes.clone());
|
||||
let module_bytes = if let Some(cached_bytes) = BYTE_CACHE.lock().get(&module_bytes_key).cloned()
|
||||
{
|
||||
cached_bytes
|
||||
} else {
|
||||
let fresh_module_bytes = std::fs::read(plugin_path)
|
||||
.map(Arc::new)
|
||||
.context("Cannot read plugin from specified path")?;
|
||||
BYTE_CACHE
|
||||
.lock()
|
||||
.insert(module_bytes_key, fresh_module_bytes.clone());
|
||||
|
||||
fresh_module_bytes
|
||||
};
|
||||
fresh_module_bytes
|
||||
};
|
||||
|
||||
// TODO: can we share store instances across each plugin binaries?
|
||||
let engine = Engine::default();
|
||||
let wasmer_store = Store::default();
|
||||
|
||||
let mut linker = Linker::new(&engine);
|
||||
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
|
||||
let load_from_cache = |c: &mut PluginCache, hash: Hash| match c {
|
||||
PluginCache::File(filesystem_cache) => unsafe {
|
||||
filesystem_cache.load(&wasmer_store, hash)
|
||||
},
|
||||
};
|
||||
|
||||
let wasi = WasiCtxBuilder::new()
|
||||
.inherit_stdio()
|
||||
.inherit_args()?
|
||||
.build();
|
||||
let mut _store = Store::new(&engine, wasi);
|
||||
let store_into_cache = |c: &mut PluginCache, hash: Hash, module: &Module| match c {
|
||||
PluginCache::File(filesystem_cache) => filesystem_cache.store(hash, module),
|
||||
};
|
||||
|
||||
Ok(())
|
||||
let hash = Hash::generate(&module_bytes);
|
||||
|
||||
let load_cold_wasm_bytes =
|
||||
|| Module::new(&wasmer_store, module_bytes.as_ref()).context("Cannot compile plugin");
|
||||
|
||||
let module = if let Some(cache) = cache {
|
||||
let cached_module =
|
||||
load_from_cache(cache, hash).context("Failed to load plugin from cache");
|
||||
|
||||
match cached_module {
|
||||
Ok(module) => Ok(module),
|
||||
Err(err) => {
|
||||
let loaded_module = load_cold_wasm_bytes().map_err(|_| err);
|
||||
match &loaded_module {
|
||||
Ok(module) => {
|
||||
if let Err(err) = store_into_cache(cache, hash, &module) {
|
||||
loaded_module
|
||||
.map_err(|_| err)
|
||||
.context("Failed to store compiled plugin into cache")
|
||||
} else {
|
||||
loaded_module
|
||||
}
|
||||
}
|
||||
Err(..) => loaded_module,
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
load_cold_wasm_bytes()
|
||||
};
|
||||
|
||||
return match module {
|
||||
Ok(module) => {
|
||||
let import_object = imports! {};
|
||||
|
||||
Instance::new(&module, &import_object).context("Failed to create plugin instance")
|
||||
}
|
||||
Err(err) => Err(err.into()),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn apply_js_plugin(
|
||||
@ -75,7 +112,7 @@ pub fn apply_js_plugin(
|
||||
program: Program,
|
||||
) -> Result<Program, Error> {
|
||||
(|| -> Result<_, Error> {
|
||||
load_plugin(path, cache)?;
|
||||
let _instance = load_plugin(path, cache)?;
|
||||
// TODO: actually apply transform from plugin
|
||||
Ok(program)
|
||||
})()
|
||||
|
@ -9,12 +9,13 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
use swc_common::collections::AHashMap;
|
||||
use wasmer_cache::FileSystemCache;
|
||||
|
||||
/// Type of cache to store compiled bytecodes of plugins.
|
||||
/// Currently only supports filesystem, but _may_ supports
|
||||
/// other type (in-memory, etcs) for the long-running processes like devserver.
|
||||
pub enum PluginCache {
|
||||
File,
|
||||
File(FileSystemCache),
|
||||
}
|
||||
|
||||
/// TODO: Cache
|
||||
@ -59,7 +60,7 @@ pub fn resolve(name: &str) -> Result<Arc<PathBuf>, Error> {
|
||||
/// Note SWC's plugin should not fail to load when cache location is not
|
||||
/// available. It'll make each invocation to cold start.
|
||||
pub fn resolve_plugin_cache_root(root: Option<String>) -> Result<PluginCache, Error> {
|
||||
let _root_path = match root {
|
||||
let root_path = match root {
|
||||
Some(root) => {
|
||||
let mut root = PathBuf::from(root);
|
||||
root.push("plugins");
|
||||
@ -73,7 +74,9 @@ pub fn resolve_plugin_cache_root(root: Option<String>) -> Result<PluginCache, Er
|
||||
}
|
||||
};
|
||||
|
||||
Ok(PluginCache::File)
|
||||
FileSystemCache::new(root_path)
|
||||
.map(|cache| PluginCache::File(cache))
|
||||
.context("Failed to create cache location for the plugins")
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
|
@ -1 +1 @@
|
||||
nightly-2021-12-15
|
||||
nightly-2022-01-02
|
Loading…
Reference in New Issue
Block a user