Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
37 changes: 35 additions & 2 deletions Cargo.lock

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

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dyn-clone = { version = "1.0.17", default-features = false }
either = { version = "1.15.0", default-features = false }
enum-tag = { version = "0.3.0", default-features = false }
fast-glob = { version = "1.0.0", default-features = false }
form_urlencoded = { version = "1.2.2", default-features = false }
futures = { version = "0.3.31", default-features = false, features = ["std"] }
glob = { version = "0.3.2", default-features = false }
hashlink = { version = "0.10.0", default-features = false }
Expand Down Expand Up @@ -219,6 +220,7 @@ rspack_plugin_progress = { version = "=0.6.3", path = "crates/rs
rspack_plugin_real_content_hash = { version = "=0.6.3", path = "crates/rspack_plugin_real_content_hash", default-features = false }
rspack_plugin_remove_duplicate_modules = { version = "=0.6.3", path = "crates/rspack_plugin_remove_duplicate_modules", default-features = false }
rspack_plugin_remove_empty_chunks = { version = "=0.6.3", path = "crates/rspack_plugin_remove_empty_chunks", default-features = false }
rspack_plugin_rsc = { version = "=0.6.3", path = "crates/rspack_plugin_rsc", default-features = false }
rspack_plugin_rsdoctor = { version = "=0.6.3", path = "crates/rspack_plugin_rsdoctor", default-features = false }
rspack_plugin_rslib = { version = "=0.6.3", path = "crates/rspack_plugin_rslib", default-features = false }
rspack_plugin_rstest = { version = "=0.6.3", path = "crates/rspack_plugin_rstest", default-features = false }
Expand Down
9 changes: 8 additions & 1 deletion crates/node_binding/napi-binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@ export declare class JsCompiler {
rebuild(changed_files: string[], removed_files: string[], callback: (err: null | Error) => void): void
close(): Promise<void>
getVirtualFileStore(): VirtualFileStore | null
getCompilerId(): ExternalObject<CompilerId>
}

export declare class JsContextModuleFactoryAfterResolveData {
Expand Down Expand Up @@ -602,7 +603,9 @@ export declare enum BuiltinPluginName {
LazyCompilationPlugin = 'LazyCompilationPlugin',
ModuleInfoHeaderPlugin = 'ModuleInfoHeaderPlugin',
HttpUriPlugin = 'HttpUriPlugin',
CssChunkingPlugin = 'CssChunkingPlugin'
CssChunkingPlugin = 'CssChunkingPlugin',
ReactServerComponentsPlugin = 'ReactServerComponentsPlugin',
ReactClientPlugin = 'ReactClientPlugin'
}

export declare function cleanupGlobalTrace(): void
Expand Down Expand Up @@ -758,6 +761,10 @@ export interface JsCleanOptions {
keep?: string | RegExp | ((path: string) => boolean)
}

export interface JsClientCompilerHandle {
compile: (() => Promise<undefined>)
}

export interface JsCodegenerationResult {
sources: Record<string, string>
}
Expand Down
1 change: 1 addition & 0 deletions crates/rspack_binding_api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ rspack_paths = { workspace = true }
rspack_plugin_esm_library = { workspace = true }
rspack_plugin_html = { workspace = true }
rspack_plugin_javascript = { workspace = true }
rspack_plugin_rsc = { workspace = true }
rspack_plugin_rsdoctor = { workspace = true }
rspack_plugin_rslib = { workspace = true }
rspack_plugin_rstest = { workspace = true }
Expand Down
6 changes: 6 additions & 0 deletions crates/rspack_binding_api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ impl JsCompiler {
rspack_loader_lightningcss::LightningcssLoaderPlugin::new(),
));
plugins.push(Box::new(rspack_loader_swc::SwcLoaderPlugin::new()));
plugins.push(Box::new(rspack_plugin_rsc::ClientEntryLoaderPlugin::new()));
plugins.push(Box::new(
rspack_loader_react_refresh::ReactRefreshLoaderPlugin::new(),
));
Expand Down Expand Up @@ -409,6 +410,11 @@ impl JsCompiler {
.as_ref()
.map(|store| JsVirtualFileStore::new(store.clone()))
}

#[napi]
pub fn get_compiler_id(&self) -> External<CompilerId> {
External::new(self.compiler.id())
}
}

struct RunGuard {
Expand Down
2 changes: 2 additions & 0 deletions crates/rspack_binding_api/src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ mod interceptor;
mod js_cleanup_plugin;
mod js_hooks_plugin;
mod js_loader;
mod rsc;

pub use js_cleanup_plugin::*;
pub use js_hooks_plugin::*;
pub(super) use js_loader::{JsLoaderItem, JsLoaderRspackPlugin, JsLoaderRunnerGetter};
pub mod buildtime_plugins;
pub use interceptor::*;
pub use rsc::{JsClientCompilerHandle, JsReactClientPluginOptions};
84 changes: 84 additions & 0 deletions crates/rspack_binding_api/src/plugins/rsc.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
use std::sync::Arc;

use napi::{
Env, Status,
bindgen_prelude::{
External, ExternalRef, FromNapiValue, Function, JsObjectValue, Object, Promise, Reference,
WeakReference,
},
threadsafe_function::ThreadsafeFunction,
};
use rspack_core::CompilerId;
use rspack_error::ToStringResultToRspackResultExt;
use rspack_plugin_rsc::{ClientCompilerHandle, ReactClientPluginOptions};

use crate::JsCompiler;

#[napi(object, object_to_js = false)]
pub struct JsClientCompilerHandle {
pub compile: ThreadsafeFunction<(), Promise<()>, (), Status, false, true, 0>,
}

impl From<JsClientCompilerHandle> for ClientCompilerHandle {
fn from(value: JsClientCompilerHandle) -> Self {
let ts_fn = Arc::new(value.compile);

ClientCompilerHandle::new(Box::new(move || {
let ts_fn = ts_fn.clone();
Box::pin(async move {
println!("Calling client compiler compile from JS");
let promise = ts_fn.call_async(()).await.to_rspack_result()?;
promise.await;
println!("Calling client compiler compile from JS end");
Ok(())
})
}))
}
}

type GetServerCompilerId = Box<dyn Fn() -> CompilerId + Sync + Send>;

pub struct JsReactClientPluginOptions {
pub get_server_compiler_id:
ThreadsafeFunction<(), &'static External<CompilerId>, (), Status, false, true, 0>,
}

impl FromNapiValue for JsReactClientPluginOptions {
unsafe fn from_napi_value(
env: napi::sys::napi_env,
napi_val: napi::sys::napi_value,
) -> napi::Result<Self> {
let obj = unsafe { Object::from_napi_value(env, napi_val)? };

let js_fn = obj.get_named_property::<Function<'static, (), &'static External<CompilerId>>>(
"getServerCompilerId",
)?;

let ts_fn = js_fn
.build_threadsafe_function::<()>()
.callee_handled::<false>()
.max_queue_size()
.weak::<true>()
.build()?;

Ok(Self {
get_server_compiler_id: ts_fn,
})
}
}

impl From<JsReactClientPluginOptions> for ReactClientPluginOptions {
fn from(value: JsReactClientPluginOptions) -> Self {
let ts_fn = Arc::new(value.get_server_compiler_id);

Self {
get_server_compiler_id: Box::new(move || {
let ts_fn = ts_fn.clone();
Box::pin(async move {
let external = ts_fn.call_async(()).await.to_rspack_result()?;
Ok(**external)
})
}),
}
}
}
22 changes: 18 additions & 4 deletions crates/rspack_binding_api/src/raw_options/raw_builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ use rspack_plugin_no_emit_on_errors::NoEmitOnErrorsPlugin;
use rspack_plugin_real_content_hash::RealContentHashPlugin;
use rspack_plugin_remove_duplicate_modules::RemoveDuplicateModulesPlugin;
use rspack_plugin_remove_empty_chunks::RemoveEmptyChunksPlugin;
use rspack_plugin_rsc::{ReactClientPlugin, ReactServerComponentsPlugin};
use rspack_plugin_rslib::RslibPlugin;
use rspack_plugin_runtime::{
ArrayPushCallbackChunkFormatPlugin, BundlerInfoPlugin, ChunkPrefetchPreloadPlugin,
Expand Down Expand Up @@ -126,7 +127,9 @@ use self::{
};
use crate::{
options::entry::JsEntryPluginOptions,
plugins::{JsLoaderRspackPlugin, JsLoaderRunnerGetter},
plugins::{
JsClientCompilerHandle, JsLoaderRspackPlugin, JsLoaderRunnerGetter, JsReactClientPluginOptions,
},
raw_options::{
RawDynamicEntryPluginOptions, RawEvalDevToolModulePluginOptions, RawExternalItemWrapper,
RawExternalsPluginOptions, RawHttpExternalsRspackPluginOptions, RawSplitChunksOptions,
Expand Down Expand Up @@ -236,6 +239,10 @@ pub enum BuiltinPluginName {
ModuleInfoHeaderPlugin,
HttpUriPlugin,
CssChunkingPlugin,

// react server components
ReactServerComponentsPlugin,
ReactClientPlugin,
}

#[doc(hidden)]
Expand Down Expand Up @@ -291,7 +298,6 @@ impl<'a> BuiltinPlugin<'a> {
}
};
match name {
// webpack also have these plugins
BuiltinPluginName::DefinePlugin => {
let plugin = DefinePlugin::new(
downcast_into(self.options)
Expand Down Expand Up @@ -649,8 +655,6 @@ impl<'a> BuiltinPlugin<'a> {
.boxed();
plugins.push(plugin)
}

// rspack specific plugins
BuiltinPluginName::HttpExternalsRspackPlugin => {
let plugin_options = downcast_into::<RawHttpExternalsRspackPluginOptions>(self.options)
.map_err(|report| napi::Error::from_reason(report.to_string()))?;
Expand Down Expand Up @@ -833,6 +837,16 @@ impl<'a> BuiltinPlugin<'a> {
.map_err(|report| napi::Error::from_reason(report.to_string()))?;
plugins.push(CssChunkingPlugin::new(options.into()).boxed());
}
BuiltinPluginName::ReactServerComponentsPlugin => {
let options = downcast_into::<JsClientCompilerHandle>(self.options)
.map_err(|report| napi::Error::from_reason(report.to_string()))?;
plugins.push(ReactServerComponentsPlugin::new(options.into()).boxed());
}
BuiltinPluginName::ReactClientPlugin => {
let options = downcast_into::<JsReactClientPluginOptions>(self.options)
.map_err(|report| napi::Error::from_reason(report.to_string()))?;
plugins.push(ReactClientPlugin::new(options.into()).boxed());
}
}
Ok(())
}
Expand Down
6 changes: 4 additions & 2 deletions crates/rspack_binding_api/src/swc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::sync::Arc;

use napi::bindgen_prelude::within_runtime_if_available;
use rspack_javascript_compiler::{
JavaScriptCompiler, TransformOutput as CompilerTransformOutput, minify::JsMinifyOptions,
Expand Down Expand Up @@ -57,9 +59,9 @@ fn _transform(source: String, options: String) -> napi::Result<TransformOutput>
compiler
.transform(
source,
Some(swc_core::common::FileName::Real(
Some(Arc::new(swc_core::common::FileName::Real(
options.filename.clone().into(),
)),
))),
options,
Some(module_source_map_kind),
|_, _| {},
Expand Down
36 changes: 34 additions & 2 deletions crates/rspack_cacheable/src/with/as_preset/swc.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use rkyv::{
Place,
rancor::{Fallible, Source},
ser::Writer,
ser::{Allocator, Writer},
string::{ArchivedString, StringResolver},
vec::{ArchivedVec, VecResolver},
with::{ArchiveWith, DeserializeWith, SerializeWith},
};
use swc_core::ecma::atoms::Atom;
use swc_core::{atoms::Wtf8Atom, ecma::atoms::Atom};

use super::AsPreset;

Expand Down Expand Up @@ -39,3 +40,34 @@ where
Ok(Atom::from(field.as_str()))
}
}

impl ArchiveWith<Wtf8Atom> for AsPreset {
type Archived = ArchivedVec<u8>;
type Resolver = VecResolver;

#[inline]
fn resolve_with(field: &Wtf8Atom, resolver: Self::Resolver, out: Place<Self::Archived>) {
ArchivedVec::resolve_from_len(field.as_bytes().len(), resolver, out);
}
}

impl<S> SerializeWith<Wtf8Atom, S> for AsPreset
where
S: Fallible + Allocator + Writer + ?Sized,
S::Error: Source,
{
#[inline]
fn serialize_with(field: &Wtf8Atom, serializer: &mut S) -> Result<Self::Resolver, S::Error> {
ArchivedVec::serialize_from_slice(field.as_bytes(), serializer)
}
}

impl<D> DeserializeWith<ArchivedVec<u8>, Wtf8Atom, D> for AsPreset
where
D: ?Sized + Fallible,
{
#[inline]
fn deserialize_with(field: &ArchivedVec<u8>, _: &mut D) -> Result<Wtf8Atom, D::Error> {
Ok(unsafe { Wtf8Atom::from_bytes_unchecked(field) })
}
}
3 changes: 3 additions & 0 deletions crates/rspack_core/src/dependency/dependency_category.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ pub enum DependencyCategory {
Wasm,
Worker,
LoaderImport,
ClientReference,
}

impl From<&str> for DependencyCategory {
Expand All @@ -35,6 +36,7 @@ impl From<&str> for DependencyCategory {
"loaderImport" => Self::LoaderImport,
"worker" => Self::Worker,
"unknown" => Self::Unknown,
"client-reference" => Self::Unknown,
_ => Self::Unknown,
}
}
Expand All @@ -55,6 +57,7 @@ impl DependencyCategory {
DependencyCategory::Wasm => "wasm",
DependencyCategory::Worker => "worker",
DependencyCategory::LoaderImport => "loaderImport",
DependencyCategory::ClientReference => "client-reference",
}
}
}
Expand Down
Loading