diff --git a/crates/node_binding/napi-binding.d.ts b/crates/node_binding/napi-binding.d.ts index bdc3a3ff8484..7474c18b2ed7 100644 --- a/crates/node_binding/napi-binding.d.ts +++ b/crates/node_binding/napi-binding.d.ts @@ -321,7 +321,7 @@ export declare class JsCompilation { } export declare class JsCompiler { - constructor(compilerPath: string, options: RawOptions, builtinPlugins: Array, registerJsTaps: RegisterJsTaps, outputFilesystem: ThreadsafeNodeFS, intermediateFilesystem: ThreadsafeNodeFS | undefined | null, inputFilesystem: ThreadsafeNodeFS | undefined | null, resolverFactoryReference: JsResolverFactory) + constructor(compilerPath: string, options: RawOptions, builtinPlugins: Array, registerJsTaps: RegisterJsTaps, outputFilesystem: ThreadsafeNodeFS, intermediateFilesystem: ThreadsafeNodeFS | undefined | null, inputFilesystem: ThreadsafeNodeFS | undefined | null, resolverFactoryReference: JsResolverFactory, unsafeFastDrop: boolean) setNonSkippableRegisters(kinds: Array): void /** Build with the given option passed to the constructor */ build(callback: (err: null | Error) => void): void diff --git a/crates/rspack_binding_api/src/lib.rs b/crates/rspack_binding_api/src/lib.rs index daa3dae13ebe..c4bca5e3d6e5 100644 --- a/crates/rspack_binding_api/src/lib.rs +++ b/crates/rspack_binding_api/src/lib.rs @@ -101,6 +101,7 @@ mod virtual_modules; use std::{ cell::RefCell, + mem::ManuallyDrop, sync::{Arc, RwLock}, }; @@ -159,8 +160,11 @@ fn cleanup_revoked_modules(ctx: CallContext) -> Result<()> { #[napi(custom_finalize)] struct JsCompiler { + // whether to skip drop compiler in finalize + unsafe_fast_drop: bool, js_hooks_plugin: JsHooksAdapterPlugin, - compiler: Compiler, + // call drop manually to avoid unnecessary drop overhead in cli build + compiler: ManuallyDrop, state: CompilerState, include_dependencies_map: FxHashMap>, entry_dependencies_map: FxHashMap>, @@ -183,6 +187,7 @@ impl JsCompiler { intermediate_filesystem: Option, input_filesystem: Option, mut resolver_factory_reference: Reference, + unsafe_fast_drop: bool, ) -> Result { tracing::info!(name:"rspack_version", version = rspack_workspace::rspack_pkg_version!()); tracing::info!(name:"raw_options", options=?&options); @@ -309,17 +314,17 @@ impl JsCompiler { ); Ok(Self { - compiler: Compiler::from(rspack), + compiler: ManuallyDrop::new(Compiler::from(rspack)), state: CompilerState::init(), js_hooks_plugin, include_dependencies_map: Default::default(), entry_dependencies_map: Default::default(), compiler_context, virtual_file_store, + unsafe_fast_drop, }) }) } - #[napi] pub fn set_non_skippable_registers(&self, kinds: Vec) { self.js_hooks_plugin.set_non_skippable_registers(kinds) @@ -460,7 +465,7 @@ impl JsCompiler { } impl ObjectFinalize for JsCompiler { - fn finalize(self, _env: Env) -> Result<()> { + fn finalize(mut self, _env: Env) -> Result<()> { let compiler_id = self.compiler.id(); COMPILER_REFERENCES.with(|ref_cell| { @@ -469,6 +474,11 @@ impl ObjectFinalize for JsCompiler { }); ModuleObject::cleanup_by_compiler_id(&compiler_id); + if (!self.unsafe_fast_drop) { + unsafe { + ManuallyDrop::drop(&mut self.compiler); + } + } Ok(()) } } diff --git a/packages/rspack-cli/src/cli.ts b/packages/rspack-cli/src/cli.ts index 36d26be39466..884c12882929 100644 --- a/packages/rspack-cli/src/cli.ts +++ b/packages/rspack-cli/src/cli.ts @@ -56,6 +56,10 @@ export class RspackCLI { let compiler: MultiCompiler | Compiler | null; try { compiler = rspack(config, isWatch ? callback : undefined); + if (!isWatch && compiler) { + // unsafeFastDrop is an internal option api and not shown in types + compiler.unsafeFastDrop = true; + } } catch (e) { // Aligned with webpack-cli // See: https://github.com/webpack/webpack-cli/blob/eea6adf7d34dfbfd3b5b784ece4a4664834f5a6a/packages/webpack-cli/src/webpack-cli.ts#L2394 diff --git a/packages/rspack/etc/core.api.md b/packages/rspack/etc/core.api.md index 87c05cad69e4..b3970917cf88 100644 --- a/packages/rspack/etc/core.api.md +++ b/packages/rspack/etc/core.api.md @@ -1181,6 +1181,8 @@ export class Compiler { runAsChild(callback: (err?: null | Error, entries?: Chunk[], compilation?: Compilation) => any): void; // (undocumented) running: boolean; + // @internal + unsafeFastDrop: boolean; // (undocumented) watch(watchOptions: Watchpack.WatchOptions, handler: liteTapable.Callback): Watching; // (undocumented) @@ -4823,6 +4825,8 @@ export class MultiCompiler { // (undocumented) setDependencies(compiler: Compiler, dependencies: string[]): void; // (undocumented) + set unsafeFastDrop(value: boolean); + // (undocumented) validateDependencies(callback: liteTapable.Callback): boolean; // (undocumented) watch(watchOptions: WatchOptions | WatchOptions[], handler: liteTapable.Callback): MultiWatching; diff --git a/packages/rspack/src/Compiler.ts b/packages/rspack/src/Compiler.ts index 0b71c602ebfc..e2a0a938bc75 100644 --- a/packages/rspack/src/Compiler.ts +++ b/packages/rspack/src/Compiler.ts @@ -174,6 +174,14 @@ class Compiler { cache: Cache; compilerPath: string; options: RspackOptionsNormalized; + /** + * Whether to skip dropping Rust compiler instance to improve performance. + * This is an internal option api and could be removed or changed at any time. + * @internal + * true: Skip dropping Rust compiler instance. + * false: Drop Rust compiler instance when Compiler is garbage collected. + */ + unsafeFastDrop: boolean = false; /** * Note: This is not a webpack public API, maybe removed in future. @@ -881,7 +889,8 @@ class Compiler { ) : undefined, inputFileSystem, - ResolverFactory.__to_binding(this.resolverFactory) + ResolverFactory.__to_binding(this.resolverFactory), + this.unsafeFastDrop ); callback(null, this.#instance); diff --git a/packages/rspack/src/MultiCompiler.ts b/packages/rspack/src/MultiCompiler.ts index fb198e24b5e7..9f60bc67626c 100644 --- a/packages/rspack/src/MultiCompiler.ts +++ b/packages/rspack/src/MultiCompiler.ts @@ -147,7 +147,11 @@ export class MultiCompiler { }); } } - + set unsafeFastDrop(value: boolean) { + for (const compiler of this.compilers) { + compiler.unsafeFastDrop = value; + } + } get options() { return Object.assign( this.compilers.map(c => c.options),