Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/slow-bees-hope.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
swc_core: minor
swc_transform_common: major
---

feat(plugin): Refactor extra output API and expose it to Wasm plugin
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions bindings/binding_core_node/src/analyze.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use std::sync::Arc;

use napi::{
bindgen_prelude::{AbortSignal, AsyncTask},
Env, JsBuffer, JsBufferValue, Ref, Task,
};
use swc_core::{
base::{wasm_analysis::WasmAnalysisOptions, Compiler},
common::{comments::SingleThreadedComments, FileName},
node::MapErr,
};
use tracing::instrument;

use crate::{get_fresh_compiler, util::try_with};

pub struct AnalyzeTask {
pub c: Arc<Compiler>,
pub input: Option<String>,
pub options: Ref<JsBufferValue>,
}

#[napi]
impl Task for AnalyzeTask {
type JsValue = String;
type Output = String;

#[instrument(level = "trace", skip_all)]
fn compute(&mut self) -> napi::Result<Self::Output> {
let options: WasmAnalysisOptions = serde_json::from_slice(self.options.as_ref())?;

try_with(self.c.cm.clone(), false, options.error_format, |handler| {
let comments = SingleThreadedComments::default();

let fm = self.c.cm.new_source_file(
if let Some(filename) = options.filename.as_deref() {
FileName::Real(filename.into()).into()
} else {
FileName::Anon.into()
},
self.input.take().unwrap(),
);

self.c.run_wasm_analysis(fm, handler, &options, &comments)
})
.convert_err()
}

fn resolve(&mut self, _env: Env, result: Self::Output) -> napi::Result<Self::JsValue> {
Ok(result)
}

fn finally(&mut self, env: Env) -> napi::Result<()> {
self.options.unref(env)?;
Ok(())
}
}

#[napi]
pub fn analyze(
src: String,
options: JsBuffer,
signal: Option<AbortSignal>,
) -> napi::Result<AsyncTask<AnalyzeTask>> {
crate::util::init_default_trace_subscriber();

let task = AnalyzeTask {
c: get_fresh_compiler(),
input: Some(src),
options: options.into_ref()?,
};
Ok(AsyncTask::with_optional_signal(task, signal))
}
1 change: 1 addition & 0 deletions bindings/binding_core_node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use swc_core::{
common::{sync::Lazy, FilePathMapping, SourceMap},
};

mod analyze;
mod bundle;
mod minify;
mod parse;
Expand Down
48 changes: 6 additions & 42 deletions crates/swc/src/config/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ pub static PLUGIN_MODULE_CACHE: Lazy<swc_plugin_runner::cache::PluginModuleCache
#[cfg(feature = "plugin")]
pub fn init_plugin_module_cache_once(
enable_fs_cache_store: bool,
fs_cache_store_root: &Option<String>,
fs_cache_store_root: Option<&str>,
) {
PLUGIN_MODULE_CACHE.inner.get_or_init(|| {
parking_lot::Mutex::new(swc_plugin_runner::cache::PluginModuleCache::create_inner(
Expand Down Expand Up @@ -598,48 +598,12 @@ impl Options {
// 2. embedded runtime can compiles & execute wasm
#[cfg(all(feature = "plugin", not(target_arch = "wasm32")))]
{
use swc_ecma_loader::resolve::Resolve;

let plugin_resolver = CachingResolver::new(
40,
NodeModulesResolver::new(
swc_ecma_loader::TargetEnv::Node,
Default::default(),
true,
),
);

if let Some(plugins) = &experimental.plugins {
// Currently swc enables filesystemcache by default on Embedded runtime plugin
// target.
init_plugin_module_cache_once(true, &experimental.cache_root);

let mut inner_cache = PLUGIN_MODULE_CACHE
.inner
.get()
.expect("Cache should be available")
.lock();

// Populate cache to the plugin modules if not loaded
for plugin_config in plugins.iter() {
let plugin_name = &plugin_config.0;

if !inner_cache.contains(plugin_name) {
let resolved_path = plugin_resolver.resolve(
&FileName::Real(PathBuf::from(plugin_name)),
plugin_name,
)?;

let path = if let FileName::Real(value) = resolved_path.filename {
value
} else {
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
};

inner_cache.store_bytes_from_path(&path, plugin_name)?;
tracing::debug!("Initialized WASM plugin {plugin_name}");
}
}
crate::plugin::compile_wasm_plugins(
experimental.cache_root.as_deref(),
plugins,
)
.context("Failed to compile wasm plugins")?;
}

Box::new(crate::plugin::plugins(
Expand Down
9 changes: 3 additions & 6 deletions crates/swc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ use swc_ecma_visit::{FoldWith, VisitMutWith, VisitWith};
pub use swc_error_reporters::handler::{try_with_handler, HandlerOpts};
pub use swc_node_comments::SwcComments;
use swc_timer::timer;
use swc_transform_common::output::emit;
use swc_transform_common::output::experimental_emit;
use swc_typescript::fast_dts::FastDts;
use tracing::warn;
use url::Url;
Expand All @@ -170,7 +170,7 @@ mod builder;
pub mod config;
mod dropped_comments_preserver;
mod plugin;
mod wasm_analysis;
pub mod wasm_analysis;
pub mod resolver {
use std::path::PathBuf;

Expand Down Expand Up @@ -1022,10 +1022,7 @@ impl Compiler {
let pass = config.pass;
let (program, output) = swc_transform_common::output::capture(|| {
if let Some(dts_code) = dts_code {
emit(
"__swc_isolated_declarations__".into(),
serde_json::Value::String(dts_code),
);
experimental_emit("__swc_isolated_declarations__".into(), dts_code);
}

helpers::HELPERS.set(&Helpers::new(config.external_helpers), || {
Expand Down
51 changes: 51 additions & 0 deletions crates/swc/src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@
allow(unused)
)]

use std::path::PathBuf;

use anyhow::{Context, Result};
use common::FileName;
use serde::{Deserialize, Serialize};
use swc_common::errors::HANDLER;
use swc_ecma_ast::Pass;
#[cfg(feature = "plugin")]
use swc_ecma_ast::*;
use swc_ecma_loader::{
resolve::Resolve,
resolvers::{lru::CachingResolver, node::NodeModulesResolver},
};
use swc_ecma_visit::{fold_pass, noop_fold_type, Fold};

/// A tuple represents a plugin.
Expand Down Expand Up @@ -190,3 +198,46 @@ impl Fold for RustPlugins {
}
}
}

#[cfg(feature = "plugin")]
pub(crate) fn compile_wasm_plugins(
cache_root: Option<&str>,
plugins: &[PluginConfig],
) -> Result<()> {
let plugin_resolver = CachingResolver::new(
40,
NodeModulesResolver::new(swc_ecma_loader::TargetEnv::Node, Default::default(), true),
);

// Currently swc enables filesystemcache by default on Embedded runtime plugin
// target.
crate::config::init_plugin_module_cache_once(true, cache_root);

let mut inner_cache = crate::config::PLUGIN_MODULE_CACHE
.inner
.get()
.expect("Cache should be available")
.lock();

// Populate cache to the plugin modules if not loaded
for plugin_config in plugins.iter() {
let plugin_name = &plugin_config.0;

if !inner_cache.contains(plugin_name) {
let resolved_path = plugin_resolver
.resolve(&FileName::Real(PathBuf::from(plugin_name)), plugin_name)
.with_context(|| format!("failed to resolve plugin path: {plugin_name}"))?;

let path = if let FileName::Real(value) = resolved_path.filename {
value
} else {
anyhow::bail!("Failed to resolve plugin path: {:?}", resolved_path);
};

inner_cache.store_bytes_from_path(&path, plugin_name)?;
tracing::debug!("Initialized WASM plugin {plugin_name}");
}
}

Ok(())
}
Loading
Loading