feat(plugin/runner): Implement initial loading for wasm32 (#4151)

This commit is contained in:
OJ Kwon 2022-03-25 00:05:26 -07:00 committed by GitHub
parent 51dcfd8c5f
commit 161353cf25
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 137 additions and 91 deletions

29
Cargo.lock generated
View File

@ -1225,9 +1225,9 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
[[package]]
name = "js-sys"
version = "0.3.55"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84"
checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04"
dependencies = [
"wasm-bindgen",
]
@ -4504,6 +4504,7 @@ version = "1.2.160"
dependencies = [
"anyhow",
"console_error_panic_hook",
"js-sys",
"once_cell",
"parking_lot_core 0.9.1",
"path-clean",
@ -4522,9 +4523,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.78"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce"
checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06"
dependencies = [
"cfg-if 1.0.0",
"serde",
@ -4534,9 +4535,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-backend"
version = "0.2.78"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b"
checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca"
dependencies = [
"bumpalo",
"lazy_static",
@ -4561,9 +4562,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.78"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9"
checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@ -4571,9 +4572,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.78"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab"
checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc"
dependencies = [
"proc-macro2",
"quote",
@ -4584,9 +4585,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.78"
version = "0.2.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2"
[[package]]
name = "wasmer"
@ -4864,9 +4865,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.55"
version = "0.3.56"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb"
checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb"
dependencies = [
"js-sys",
"wasm-bindgen",

View File

@ -466,7 +466,7 @@ impl Options {
swc_plugin_runner::cache::init_plugin_module_cache_once(&experimental.cache_root);
}
crate::plugin::plugins(plugin_resolver, experimental, plugin_context)
crate::plugin::plugins(Some(plugin_resolver), experimental, plugin_context)
};
// Native runtime plugin target, based on assumption we have
@ -486,7 +486,8 @@ impl Options {
env_name: self.env_name.to_owned(),
};
crate::plugin::plugins(experimental, plugin_context)
swc_plugin_runner::cache::init_plugin_module_cache_once();
crate::plugin::plugins(None, experimental, plugin_context)
};
#[cfg(not(feature = "plugin"))]

View File

@ -41,9 +41,9 @@ pub struct PluginContext {
pub env_name: String,
}
#[cfg(all(feature = "plugin", not(target_arch = "wasm32")))]
#[cfg(feature = "plugin")]
pub fn plugins(
resolver: CachingResolver<NodeModulesResolver>,
resolver: Option<CachingResolver<NodeModulesResolver>>,
config: crate::config::JscExperimental,
plugin_context: PluginContext,
) -> impl Fold {
@ -56,18 +56,13 @@ pub fn plugins(
}
}
#[cfg(all(feature = "plugin", target_arch = "wasm32"))]
pub fn plugins(config: crate::config::JscExperimental, plugin_context: PluginContext) -> impl Fold {
swc_ecma_transforms::pass::noop()
}
#[cfg(not(feature = "plugin"))]
pub fn plugins() -> impl Fold {
noop()
}
struct RustPlugins {
resolver: CachingResolver<NodeModulesResolver>,
resolver: Option<CachingResolver<NodeModulesResolver>>,
plugins: Option<Vec<PluginConfig>>,
plugin_context: PluginContext,
}
@ -109,6 +104,8 @@ impl RustPlugins {
let resolved_path = self
.resolver
.as_ref()
.expect("filesystem_cache should provide resolver")
.resolve(&FileName::Real(PathBuf::from(&p.0)), &p.0)?;
let path = if let FileName::Real(value) = resolved_path {
@ -143,8 +140,36 @@ impl RustPlugins {
#[cfg(all(feature = "plugin", target_arch = "wasm32"))]
fn apply(&mut self, n: Program) -> Result<Program, anyhow::Error> {
//not implemented
Ok(n)
use std::{path::PathBuf, sync::Arc};
use anyhow::Context;
use swc_common::{plugin::Serialized, FileName};
use swc_ecma_loader::resolve::Resolve;
let mut serialized = Serialized::serialize(&n)?;
if let Some(plugins) = &self.plugins {
for p in plugins {
let config_json = serde_json::to_string(&p.1)
.context("Failed to serialize plugin config as json")
.and_then(|value| Serialized::serialize(&value))?;
let context_json = serde_json::to_string(&self.plugin_context)
.context("Failed to serialize plugin context as json")
.and_then(|value| Serialized::serialize(&value))?;
serialized = swc_plugin_runner::apply_transform_plugin(
&p.0,
&PathBuf::from(&p.0),
&swc_plugin_runner::cache::PLUGIN_MODULE_CACHE,
serialized,
config_json,
context_json,
)?;
}
}
Serialized::deserialize(&serialized)
}
}

View File

@ -92,16 +92,18 @@ fn create_filesystem_cache(filesystem_cache_root: &Option<String>) -> Option<Fil
///
/// If cache failed to initialize filesystem cache for given location
/// it'll be serve in-memory cache only.
#[cfg(feature = "filesystem_cache")]
pub fn init_plugin_module_cache_once(filesystem_cache_root: &Option<String>) {
#[cfg(feature = "filesystem_cache")]
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
Mutex::new(CacheInner {
fs_cache: create_filesystem_cache(filesystem_cache_root),
loaded_module_bytes: Default::default(),
})
});
}
#[cfg(target_arch = "wasm32")]
#[cfg(feature = "memory_cache")]
pub fn init_plugin_module_cache_once() {
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
Mutex::new(CacheInner {
loaded_module_bytes: Default::default(),
@ -185,22 +187,27 @@ impl PluginModuleCache {
Ok(module)
}
#[cfg(target_arch = "wasm32")]
#[cfg(feature = "memory_cache")]
pub fn load_module(&self, binary_path: &Path) -> Result<Module, Error> {
let binary_path = binary_path.to_path_buf();
let mut inner_cache = self.inner.get().expect("Cache should be available").lock();
// if constructed Module is available in-memory, directly return it.
// Note we do not invalidate in-memory cache currently: if wasm binary is
// replaced in-process lifecycle (i.e devserver) it won't be reflected.
let in_memory_module_bytes = inner_cache.loaded_module_bytes.get(&binary_path);
if let Some(module) = in_memory_module_bytes {
//TODO: In native runtime we have to reconstruct module using raw bytes in
// memory cache. requires https://github.com/wasmerio/wasmer/pull/2821
unimplemented!("Not implemented yet");
}
// In case of memory_cache, we do not have way to resolve / load modules
// externally. Bail out if cache doesn't have corresponding binary.
let in_memory_module_bytes = inner_cache
.loaded_module_bytes
.get(&binary_path)
.ok_or_else(|| {
anyhow::anyhow!("Could not locate plugin binary {}", binary_path.display())
})?;
unimplemented!("Not implemented yet");
//TODO: In native runtime we have to reconstruct module using raw bytes in
// memory cache. requires https://github.com/wasmerio/wasmer/pull/2821
let wasmer_store = Store::default();
let module = Module::new(&wasmer_store, in_memory_module_bytes)?;
Ok(module)
}
/// An experimental interface to store externally loaded module bytes into
@ -212,7 +219,7 @@ impl PluginModuleCache {
///
/// This interface is not a public, but also will likely change anytime
/// while stablizing plugin interface.
#[cfg(target_arch = "wasm32")]
#[cfg(feature = "memory_cache")]
pub fn store_once(&self, module_name: &str, module_bytes: Vec<u8>) {
// We use path as canonical id for the cache
let binary_path = PathBuf::from(module_name);

View File

@ -13,7 +13,6 @@ mod memory_interop;
mod transform_executor;
// entrypoint fn swc calls to perform its transform via plugin.
#[cfg(not(target_arch = "wasm32"))]
pub fn apply_transform_plugin(
plugin_name: &str,
path: &Path,
@ -35,8 +34,3 @@ pub fn apply_transform_plugin(
)
})
}
#[cfg(target_arch = "wasm32")]
pub fn apply_transform_plugin() -> Result<Serialized, Error> {
unimplemented!("Not implemented yet");
}

View File

@ -15,7 +15,6 @@ use crate::{
},
};
#[cfg(feature = "filesystem_cache")]
#[tracing::instrument(level = "info", skip_all)]
pub fn load_plugin(
plugin_path: &std::path::Path,
@ -99,6 +98,8 @@ pub fn load_plugin(
// Plugin binary can be either wasm32-wasi or wasm32-unknown-unknown.
// Wasi specific env need to be initialized if given module targets wasm32-wasi.
// TODO: wasm host native runtime throws 'Memory should be set on `WasiEnv`
// first'
let instance = if is_wasi_module(&module) {
// Create the `WasiEnv`.
let mut wasi_env = WasiState::new(
@ -124,11 +125,3 @@ pub fn load_plugin(
Err(err) => Err(err),
};
}
#[cfg(not(feature = "filesystem_cache"))]
pub fn load_plugin(
plugin_path: &std::path::Path,
cache: &once_cell::sync::Lazy<crate::cache::PluginModuleCache>,
) -> Result<(Instance, Arc<Mutex<Vec<u8>>>), Error> {
unimplemented!("not implemented");
}

View File

@ -23,24 +23,26 @@ plugin = [
"wasmer-wasi",
"wasmer/js-default",
"wasmer-wasi/js-default",
"js-sys",
]
[dependencies]
anyhow = "1.0.42"
console_error_panic_hook = "0.1.6"
js-sys = { version = "0.3.56", optional = true }
once_cell = "1.10.0"
parking_lot_core = "0.9.1"
path-clean = "0.1"
serde = {version = "1", features = ["derive"]}
serde = { version = "1", features = ["derive"] }
serde_json = "1"
swc = {path = "../swc"}
swc_common = {path = "../swc_common"}
swc_ecma_lints = {path = "../swc_ecma_lints", features = [
swc = { path = "../swc" }
swc_common = { path = "../swc_common" }
swc_ecma_lints = { path = "../swc_ecma_lints", features = [
"non_critical_lints",
]}
swc_ecmascript = {path = "../swc_ecmascript"}
swc_plugin_runner = {path = "../swc_plugin_runner", default-features = false, optional = true}
tracing = {version = "0.1.32", features = ["release_max_level_off"]}
wasm-bindgen = {version = "0.2", features = ["serde-serialize"]}
wasmer = {version = "2.2.1", optional = true, default-features = false}
wasmer-wasi = {version = "2.2.1", optional = true, default-features = false}
] }
swc_ecmascript = { path = "../swc_ecmascript" }
swc_plugin_runner = { path = "../swc_plugin_runner", default-features = false, optional = true }
tracing = { version = "0.1.32", features = ["release_max_level_off"] }
wasm-bindgen = { version = "0.2", features = ["serde-serialize"] }
wasmer = { version = "2.2.1", optional = true, default-features = false }
wasmer-wasi = { version = "2.2.1", optional = true, default-features = false }

View File

@ -8,7 +8,7 @@ use swc::{
};
use swc_common::{comments::Comments, FileName, FilePathMapping, SourceMap};
use swc_ecmascript::ast::{EsVersion, Program};
use wasm_bindgen::prelude::*;
use wasm_bindgen::{prelude::*, JsCast};
fn convert_err(err: Error) -> JsValue {
format!("{:?}", err).into()
@ -154,23 +154,46 @@ pub fn transform_sync(
#[cfg(feature = "plugin")]
{
// TODO: This is probably very inefficient, including each transform
// deserializes plugin bytes.
let plugin_bytes = if experimental_plugin_bytes_resolver.is_object() {
JsValue::into_serde::<std::collections::HashMap<String, Vec<u8>>>(
&experimental_plugin_bytes_resolver,
)
.expect("Object should be available")
} else {
Default::default()
};
if experimental_plugin_bytes_resolver.is_object() {
use js_sys::{Array, Object, Uint8Array};
// In here we 'inject' externally loaded bytes into the cache, so remaining
// plugin_runner execution path works as much as similar between embedded
// runtime.
plugin_bytes.into_iter().for_each(|(key, bytes)| {
swc_plugin_runner::cache::PLUGIN_MODULE_CACHE.store_once(&key, bytes.clone())
});
// TODO: This is probably very inefficient, including each transform
// deserializes plugin bytes.
let plugin_bytes_resolver_object: Object = experimental_plugin_bytes_resolver
.try_into()
.expect("Resolver should be a js object");
swc_plugin_runner::cache::init_plugin_module_cache_once();
let entries = Object::entries(&plugin_bytes_resolver_object);
for entry in entries.iter() {
let entry: Array = entry
.try_into()
.expect("Resolver object missing either key or value");
let name: String = entry
.get(0)
.as_string()
.expect("Resolver key should be a string");
let buffer = entry.get(1);
//https://github.com/rustwasm/wasm-bindgen/issues/2017#issue-573013044
//We may use https://github.com/cloudflare/serde-wasm-bindgen instead later
let data = if JsCast::is_instance_of::<Uint8Array>(&buffer) {
JsValue::from(Array::from(&buffer))
} else {
buffer
};
let bytes: Vec<u8> = data
.into_serde()
.expect("Could not read byte from plugin resolver");
// In here we 'inject' externally loaded bytes into the cache, so
// remaining plugin_runner execution path works as much as
// similar between embedded runtime.
swc_plugin_runner::cache::PLUGIN_MODULE_CACHE.store_once(&name, bytes);
}
}
}
try_with_handler(

View File

@ -768,7 +768,7 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "swc_atoms"
version = "0.2.9"
version = "0.2.10"
dependencies = [
"string_cache",
"string_cache_codegen",
@ -802,7 +802,7 @@ dependencies = [
[[package]]
name = "swc_ecma_ast"
version = "0.71.0"
version = "0.73.0"
dependencies = [
"is-macro",
"num-bigint",
@ -816,7 +816,7 @@ dependencies = [
[[package]]
name = "swc_ecma_parser"
version = "0.95.2"
version = "0.97.2"
dependencies = [
"either",
"enum_kind",
@ -834,7 +834,7 @@ dependencies = [
[[package]]
name = "swc_ecma_quote"
version = "0.6.0"
version = "0.8.0"
dependencies = [
"swc_atoms",
"swc_common",
@ -845,7 +845,7 @@ dependencies = [
[[package]]
name = "swc_ecma_quote_macros"
version = "0.5.0"
version = "0.7.0"
dependencies = [
"anyhow",
"pmutil",
@ -861,7 +861,7 @@ dependencies = [
[[package]]
name = "swc_ecma_utils"
version = "0.74.0"
version = "0.76.0"
dependencies = [
"indexmap",
"once_cell",
@ -874,7 +874,7 @@ dependencies = [
[[package]]
name = "swc_ecma_visit"
version = "0.57.0"
version = "0.59.0"
dependencies = [
"num-bigint",
"swc_atoms",
@ -914,7 +914,7 @@ dependencies = [
[[package]]
name = "swc_plugin"
version = "0.35.0"
version = "0.37.0"
dependencies = [
"swc_atoms",
"swc_common",