From 92682003c16f5e3307943662498cd9eb81dbbd00 Mon Sep 17 00:00:00 2001 From: OJ Kwon <1210596+kwonoj@users.noreply.github.com> Date: Tue, 6 Jun 2023 15:43:54 -0700 Subject: [PATCH] wip --- packages/next-swc/crates/napi/Cargo.toml | 2 +- packages/next-swc/crates/next-core/Cargo.toml | 1 + .../crates/next-core/src/next_config.rs | 2 +- .../next-core/src/next_server/context.rs | 2 + .../src/next_shared/transforms/mod.rs | 1 + .../transforms/swc_ecma_transform_plugins.rs | 104 ++++++++++++++++++ 6 files changed, 110 insertions(+), 2 deletions(-) create mode 100644 packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs diff --git a/packages/next-swc/crates/napi/Cargo.toml b/packages/next-swc/crates/napi/Cargo.toml index 6bc95d46acd58..66bb1473e15ef 100644 --- a/packages/next-swc/crates/napi/Cargo.toml +++ b/packages/next-swc/crates/napi/Cargo.toml @@ -13,7 +13,7 @@ default = ["rustls-tls"] # when build (i.e napi --build --features plugin), same for the wasm as well. # this is due to some of transitive dependencies have features cannot be enabled at the same time # (i.e wasmer/default vs wasmer/js-default) while cargo merges all the features at once. -plugin = ["turbopack-binding/__swc_core_binding_napi_plugin", "turbopack-binding/__swc_core_binding_napi_plugin_filesystem_cache", "next-swc/plugin"] +plugin = ["turbopack-binding/__swc_core_binding_napi_plugin", "turbopack-binding/__swc_core_binding_napi_plugin_filesystem_cache", "next-swc/plugin", "next-core/plugin"] sentry_native_tls = ["sentry", "sentry/native-tls", "native-tls"] sentry_rustls = ["sentry", "sentry/rustls", "rustls-tls"] diff --git a/packages/next-swc/crates/next-core/Cargo.toml b/packages/next-swc/crates/next-core/Cargo.toml index 59120a6ec7843..6252f0a6d7ccb 100644 --- a/packages/next-swc/crates/next-core/Cargo.toml +++ b/packages/next-swc/crates/next-core/Cargo.toml @@ -65,6 +65,7 @@ turbopack-binding = { workspace = true, features = ["__turbo_tasks_build"] } next-font-local = [] native-tls = ["turbopack-binding/__turbo_tasks_fetch_native-tls"] rustls-tls = ["turbopack-binding/__turbo_tasks_fetch_rustls-tls"] +plugin = ["turbopack-binding/__swc_core_binding_napi_plugin"] # enable "HMR" for embedded assets dynamic_embed_contents = [ "turbopack-binding/__turbo_tasks_fs_dynamic_embed_contents", diff --git a/packages/next-swc/crates/next-core/src/next_config.rs b/packages/next-swc/crates/next-core/src/next_config.rs index 57eebad31f4f3..ca3cd2e9426f4 100644 --- a/packages/next-swc/crates/next-core/src/next_config.rs +++ b/packages/next-swc/crates/next-core/src/next_config.rs @@ -384,6 +384,7 @@ pub struct ExperimentalConfig { pub server_components_external_packages: Option>, pub turbo: Option, mdx_rs: Option, + pub swc_plugins: Option>, // unsupported adjust_font_fallbacks: Option, @@ -428,7 +429,6 @@ pub struct ExperimentalConfig { swc_file_reading: Option, swc_minify: Option, swc_minify_debug_options: Option, - swc_plugins: Option, swc_trace_profiling: Option, transpile_packages: Option>, turbotrace: Option, diff --git a/packages/next-swc/crates/next-core/src/next_server/context.rs b/packages/next-swc/crates/next-core/src/next_server/context.rs index beedcb31a7fee..7a856e126c415 100644 --- a/packages/next-swc/crates/next-core/src/next_server/context.rs +++ b/packages/next-swc/crates/next-core/src/next_server/context.rs @@ -51,6 +51,7 @@ use crate::{ emotion::get_emotion_transform_plugin, get_relay_transform_plugin, styled_components::get_styled_components_transform_plugin, styled_jsx::get_styled_jsx_transform_plugin, + swc_ecma_transform_plugins::get_swc_ecma_transform_plugin, }, }, sass::maybe_add_sass_loader, @@ -330,6 +331,7 @@ pub async fn get_server_module_options_context( let source_transforms: Vec = vec![ *get_relay_transform_plugin(next_config).await?, *get_emotion_transform_plugin(next_config).await?, + *get_swc_ecma_transform_plugin(project_path, next_config).await?, ] .into_iter() .flatten() diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs index 6797b6054acb9..7611b7043b563 100644 --- a/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/mod.rs @@ -6,6 +6,7 @@ pub(crate) mod next_strip_page_exports; pub(crate) mod relay; pub(crate) mod styled_components; pub(crate) mod styled_jsx; +pub(crate) mod swc_ecma_transform_plugins; pub use modularize_imports::{get_next_modularize_imports_rule, ModularizeImportPackageConfig}; pub use next_dynamic::get_next_dynamic_transform_rule; diff --git a/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs b/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs new file mode 100644 index 0000000000000..99d615535509f --- /dev/null +++ b/packages/next-swc/crates/next-core/src/next_shared/transforms/swc_ecma_transform_plugins.rs @@ -0,0 +1,104 @@ +use anyhow::Result; +use turbo_tasks_fs::FileSystemPathVc; +use turbopack_binding::turbopack::ecmascript::OptionTransformPluginVc; + +use crate::next_config::NextConfigVc; + +#[turbo_tasks::function] +pub async fn get_swc_ecma_transform_plugin( + #[cfg_attr(not(feature = "plugin"), allow(unused))] project_path: FileSystemPathVc, + next_config: NextConfigVc, +) -> Result { + let config = next_config.await?; + match config.experimental.swc_plugins.as_ref() { + Some(plugin_configs) if !plugin_configs.is_empty() => { + #[cfg(feature = "plugin")] + { + use anyhow::{bail, Context}; + use turbo_tasks::Value; + use turbo_tasks_fs::FileContent; + use turbopack_binding::turbopack::{ + core::{ + asset::Asset, + issue::{IssueSeverity, OptionIssueSourceVc}, + reference_type::ReferenceType, + resolve::{ + handle_resolve_error, parse::RequestVc, pattern::Pattern, resolve, + PrimaryResolveResult, + }, + }, + ecmascript::{OptionTransformPluginVc, TransformPluginVc}, + ecmascript_plugin::transform::swc_ecma_transform_plugins::{ + SwcEcmaTransformPluginsTransformer, SwcPluginModule, SwcPluginModuleVc, + }, + turbopack::{resolve_options, resolve_options_context::ResolveOptionsContext}, + }; + + let mut plugins = vec![]; + for (name, config) in plugin_configs.iter() { + // [TODO]: SWC's current experimental config supports + // two forms of plugin path, + // one for implicit package name resolves to node_modules, + // and one for explicit path to a .wasm binary. + // Current resolve will fail with latter. + let request = RequestVc::parse(Value::new(Pattern::Constant(name.to_string()))); + let resolve_options = resolve_options( + project_path, + ResolveOptionsContext { + enable_node_modules: Some(project_path.root().resolve().await?), + enable_node_native_modules: true, + ..Default::default() + } + .cell(), + ); + + let plugin_wasm_module_resolve_result = handle_resolve_error( + resolve(project_path, request, resolve_options), + Value::new(ReferenceType::Undefined), + project_path, + request, + resolve_options, + OptionIssueSourceVc::none(), + IssueSeverity::Error.cell(), + ) + .await?; + let plugin_wasm_module_resolve_result = + &*plugin_wasm_module_resolve_result.await?; + + let primary = plugin_wasm_module_resolve_result + .primary + .first() + .context("Unable to resolve primary context")?; + + let PrimaryResolveResult::Asset(plugin_module_asset) = primary else { + bail!("Expected to find asset"); + }; + + let content = &*plugin_module_asset.content().file_content().await?; + + let FileContent::Content(file) = content else { + bail!("Expected file content for plugin module"); + }; + + plugins.push(( + SwcPluginModuleVc::cell(SwcPluginModule::new( + name, + file.content().to_bytes()?.to_vec(), + )), + config.clone(), + )); + } + + return Ok(OptionTransformPluginVc::cell(Some( + TransformPluginVc::cell(Box::new(SwcEcmaTransformPluginsTransformer::new( + plugins, + ))), + ))); + } + + #[cfg(not(feature = "plugin"))] + Ok(OptionTransformPluginVc::cell(None)) + } + _ => Ok(OptionTransformPluginVc::cell(None)), + } +}