Repository: swc-project/swc
File: crates/swc/src/plugin.rs (Rust)

Code before:
use std::{path::PathBuf, sync::Arc};

use anyhow::{Context, Result};
use atoms::Atom;
use common::FileName;
use serde::{Deserialize, Serialize};
use swc_common::errors::{DiagnosticId, 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};
#[cfg(feature = "plugin")]
use swc_plugin_runner::runtime::Runtime as PluginRuntime;

/// A tuple represents a plugin.
///
/// First element is a resolvable name to the plugin, second is a JSON object
/// that represents configuration option for those plugin.
/// Type of plugin's configuration is up to each plugin - swc/core does not have
/// strong type and it'll be serialized into plain string when it's passed to
/// plugin's entrypoint function.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct PluginConfig(pub String, pub serde_json::Value);

#[cfg(feature = "plugin")]
pub(crate) fn plugins(
    configured_plugins: Option<Vec<PluginConfig>>,
    plugin_env_vars: Option<Vec<Atom>>,
    metadata_context: std::sync::Arc<swc_common::plugin::metadata::TransformPluginMetadataContext>,
    comments: Option<swc_common::comments::SingleThreadedComments>,
    source_map: std::sync::Arc<swc_common::SourceMap>,
    unresolved_mark: swc_common::Mark,
    plugin_runtime: Arc<dyn PluginRuntime>,
) -> impl Pass {
    fold_pass(RustPlugins {
        plugins: configured_plugins,
        plugin_env_vars: plugin_env_vars.map(std::sync::Arc::new),
        metadata_context,
        comments,
        source_map,
        unresolved_mark,
        plugin_runtime,
    })
}

#[cfg(feature = "plugin")]

Review comment (bug):
[nitpick] The `Runtime::new()` constructor creates a multi-threaded runtime by default when the "rt-multi-thread" feature is enabled. However, for clarity and explicitness, consider using `Runtime::new()` with explicit builder configuration. For example:

```rust
tokio::runtime::Builder::new_multi_thread()
    .enable_all()
    .build()
    .expect("Failed to create shared tokio runtime for plugin execution")
```

This makes it explicit that a multi-threaded runtime is being created and ensures the I/O and time drivers are enabled, which aligns with the documented performance improvements in the PR description.
```suggestion
    tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
```

Code after:
use std::{path::PathBuf, sync::Arc};

use anyhow::{Context, Result};
use atoms::Atom;
use common::FileName;
#[cfg(all(feature = "plugin", not(feature = "manual-tokio-runtime")))]
use once_cell::sync::Lazy;
use serde::{Deserialize, Serialize};
use swc_common::errors::{DiagnosticId, 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};
#[cfg(feature = "plugin")]
use swc_plugin_runner::runtime::Runtime as PluginRuntime;

/// Shared tokio runtime for plugin execution.
/// This avoids the expensive overhead of creating a new runtime for each plugin
/// call.
#[cfg(all(feature = "plugin", not(feature = "manual-tokio-runtime")))]
static SHARED_RUNTIME: Lazy<tokio::runtime::Runtime> = Lazy::new(|| {
    tokio::runtime::Runtime::new()
        .expect("Failed to create shared tokio runtime for plugin execution")
});

/// A tuple represents a plugin.
///
/// First element is a resolvable name to the plugin, second is a JSON object
/// that represents configuration option for those plugin.
/// Type of plugin's configuration is up to each plugin - swc/core does not have
/// strong type and it'll be serialized into plain string when it's passed to
/// plugin's entrypoint function.
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields, rename_all = "camelCase")]
pub struct PluginConfig(pub String, pub serde_json::Value);

#[cfg(feature = "plugin")]
pub(crate) fn plugins(
    configured_plugins: Option<Vec<PluginConfig>>,
    plugin_env_vars: Option<Vec<Atom>>,
    metadata_context: std::sync::Arc<swc_common::plugin::metadata::TransformPluginMetadataContext>,
    comments: Option<swc_common::comments::SingleThreadedComments>,
    source_map: std::sync::Arc<swc_common::SourceMap>,
    unresolved_mark: swc_common::Mark,
    plugin_runtime: Arc<dyn PluginRuntime>,
) -> impl Pass {
    fold_pass(RustPlugins {