diff --git a/cli/src/api/build.ts b/cli/src/api/build.ts index 2ee803cd..83307b22 100644 --- a/cli/src/api/build.ts +++ b/cli/src/api/build.ts @@ -940,11 +940,14 @@ class Builder { const workerPath = join(dir, 'wasi-worker.mjs') const browserWorkerPath = join(dir, 'wasi-worker-browser.mjs') const browserEntryPath = join(dir, 'browser.js') - const exportsCode = idents - .map( - (ident) => `module.exports.${ident} = __napiModule.exports.${ident}`, - ) - .join('\n') + const exportsCode = + `module.exports = __napiModule.exports\n` + + idents + .map( + (ident) => + `module.exports.${ident} = __napiModule.exports.${ident}`, + ) + .join('\n') await writeFileAsync( bindingPath, createWasiBinding( @@ -966,6 +969,7 @@ class Builder { this.config.wasm?.browser?.fs, this.config.wasm?.browser?.asyncInit, ) + + `export default __napiModule.exports\n` + idents .map( (ident) => diff --git a/crates/napi/src/bindgen_runtime/js_values/symbol.rs b/crates/napi/src/bindgen_runtime/js_values/symbol.rs index be308cba..b6789398 100644 --- a/crates/napi/src/bindgen_runtime/js_values/symbol.rs +++ b/crates/napi/src/bindgen_runtime/js_values/symbol.rs @@ -40,10 +40,10 @@ impl Symbol { } #[cfg(feature = "napi9")] - pub fn for_desc(desc: String) -> Self { + pub fn for_desc>(desc: S) -> Self { Self { desc: None, - for_desc: Some(desc.to_owned()), + for_desc: Some(desc.as_ref().to_owned()), } } } diff --git a/crates/napi/src/bindgen_runtime/module_register.rs b/crates/napi/src/bindgen_runtime/module_register.rs index 12b5436c..d1266b54 100644 --- a/crates/napi/src/bindgen_runtime/module_register.rs +++ b/crates/napi/src/bindgen_runtime/module_register.rs @@ -60,9 +60,6 @@ impl Default for PersistedPerInstanceHashMap { type ModuleRegisterCallback = RwLock, (&'static str, ExportRegisterCallback))>>; -#[cfg(not(feature = "noop"))] -type ModuleRegisterHookCallback = PersistedPerInstanceHashMap; - #[cfg(not(feature = "noop"))] type ModuleClassProperty = PersistedPerInstanceHashMap, (&'static str, Vec)>>; @@ -77,7 +74,7 @@ type RegisteredClassesMap = PersistedPerInstanceHashMap = LazyLock::new(Default::default); #[cfg(not(feature = "noop"))] -static MODULE_REGISTER_HOOK_CALLBACK: LazyLock = +static MODULE_REGISTER_HOOK_CALLBACK: LazyLock>> = LazyLock::new(Default::default); #[cfg(not(feature = "noop"))] static MODULE_CLASS_PROPERTIES: LazyLock = LazyLock::new(Default::default); @@ -152,10 +149,10 @@ pub fn register_module_export( #[cfg(not(feature = "noop"))] #[doc(hidden)] pub fn register_module_export_hook(cb: ExportRegisterHookCallback) { - let current_id = std::thread::current().id(); - MODULE_REGISTER_HOOK_CALLBACK.borrow_mut(|inner| { - inner.insert(current_id, cb); - }); + let mut inner = MODULE_REGISTER_HOOK_CALLBACK + .write() + .expect("Write MODULE_REGISTER_HOOK_CALLBACK failed"); + *inner = Some(cb); } #[cfg(feature = "noop")] @@ -465,13 +462,14 @@ pub unsafe extern "C" fn napi_register_module_v1( ) }); - MODULE_REGISTER_HOOK_CALLBACK.borrow_mut(|inner| { - if let Some(cb) = inner.get(¤t_thread_id) { - if let Err(e) = cb(env, exports) { - JsError::from(e).throw_into(env); - } + let module_register_hook_callback = MODULE_REGISTER_HOOK_CALLBACK + .read() + .expect("Read MODULE_REGISTER_HOOK_CALLBACK failed"); + if let Some(cb) = module_register_hook_callback.as_ref() { + if let Err(e) = cb(env, exports) { + JsError::from(e).throw_into(env); } - }); + } #[cfg(feature = "compat-mode")] { diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.md b/examples/napi/__tests__/__snapshots__/values.spec.ts.md index f88164f3..a03296e4 100644 --- a/examples/napi/__tests__/__snapshots__/values.spec.ts.md +++ b/examples/napi/__tests__/__snapshots__/values.spec.ts.md @@ -41,6 +41,8 @@ Generated by [AVA](https://avajs.dev). ␊ type MaybePromise = T | Promise␊ ␊ + export declare const NAPI_RS_SYMBOL: symbol␊ + ␊ export declare class ExternalObject {␊ readonly '': {␊ readonly '': unique symbol␊ diff --git a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap index 260f3735..cfd2ad44 100644 Binary files a/examples/napi/__tests__/__snapshots__/values.spec.ts.snap and b/examples/napi/__tests__/__snapshots__/values.spec.ts.snap differ diff --git a/examples/napi/__tests__/values.spec.ts b/examples/napi/__tests__/values.spec.ts index 925b63b5..a9d6f47d 100644 --- a/examples/napi/__tests__/values.spec.ts +++ b/examples/napi/__tests__/values.spec.ts @@ -233,6 +233,8 @@ import { shutdownRuntime, callAsyncWithUnknownReturnValue, } from '../index.cjs' +// import other stuff in `#[napi(module_exports)]` +import nativeAddon from '../index.cjs' import { test } from './test.framework.js' @@ -1634,3 +1636,7 @@ test('extends javascript error', (t) => { t.true(typeof e.nativeStackTrace === 'string') } }) + +test('module exports', (t) => { + t.is(nativeAddon.NAPI_RS_SYMBOL, Symbol.for('NAPI_RS_SYMBOL')) +}) diff --git a/examples/napi/dts-header.d.ts b/examples/napi/dts-header.d.ts index 3986614f..f1295bd8 100644 --- a/examples/napi/dts-header.d.ts +++ b/examples/napi/dts-header.d.ts @@ -2,3 +2,5 @@ /* eslint-disable */ type MaybePromise = T | Promise + +export declare const NAPI_RS_SYMBOL: symbol diff --git a/examples/napi/example.wasi-browser.js b/examples/napi/example.wasi-browser.js index d8a35933..e7f885c6 100644 --- a/examples/napi/example.wasi-browser.js +++ b/examples/napi/example.wasi-browser.js @@ -60,6 +60,7 @@ const { } }, }) +export default __napiModule.exports export const Animal = __napiModule.exports.Animal export const AnimalWithDefaultConstructor = __napiModule.exports.AnimalWithDefaultConstructor export const AnotherClassForEither = __napiModule.exports.AnotherClassForEither diff --git a/examples/napi/example.wasi.cjs b/examples/napi/example.wasi.cjs index ac48974e..e94d7b69 100644 --- a/examples/napi/example.wasi.cjs +++ b/examples/napi/example.wasi.cjs @@ -84,6 +84,7 @@ const { instance: __napiInstance, module: __wasiModule, napiModule: __napiModule } }, }) +module.exports = __napiModule.exports module.exports.Animal = __napiModule.exports.Animal module.exports.AnimalWithDefaultConstructor = __napiModule.exports.AnimalWithDefaultConstructor module.exports.AnotherClassForEither = __napiModule.exports.AnotherClassForEither diff --git a/examples/napi/index.d.cts b/examples/napi/index.d.cts index 07a767fe..027c4529 100644 --- a/examples/napi/index.d.cts +++ b/examples/napi/index.d.cts @@ -3,6 +3,8 @@ type MaybePromise = T | Promise +export declare const NAPI_RS_SYMBOL: symbol + export declare class ExternalObject { readonly '': { readonly '': unique symbol diff --git a/examples/napi/package.json b/examples/napi/package.json index 2bd0996e..805dd855 100644 --- a/examples/napi/package.json +++ b/examples/napi/package.json @@ -8,8 +8,8 @@ "scripts": { "browser": "vite", "build": "napi-raw build --platform --js index.cjs --dts index.d.cts", - "test": "cross-env TS_NODE_PROJECT=./tsconfig.json node --import @oxc-node/core/register ../../node_modules/ava/entrypoints/cli.mjs", - "test-js": "ava" + "test": "ava reset-cache && cross-env TS_NODE_PROJECT=./tsconfig.json node --import @oxc-node/core/register ../../node_modules/ava/entrypoints/cli.mjs", + "test-js": "ava reset-cache && ava" }, "napi": { "binaryName": "example", diff --git a/examples/napi/src/lib.rs b/examples/napi/src/lib.rs index 39f19de4..516b47fb 100644 --- a/examples/napi/src/lib.rs +++ b/examples/napi/src/lib.rs @@ -8,7 +8,7 @@ #[cfg(not(target_family = "wasm"))] use napi::bindgen_prelude::create_custom_tokio_runtime; use napi::{ - bindgen_prelude::{Env, Object, Result}, + bindgen_prelude::{Object, Result, Symbol}, JsObjectValue, }; @@ -53,8 +53,8 @@ pub fn shutdown_runtime() { } #[napi(module_exports)] -pub fn exports(env: Env, mut export: Object) -> Result<()> { - let symbol = env.create_symbol(Some("NAPI_RS_SYMBOL"))?; +pub fn exports(mut export: Object) -> Result<()> { + let symbol = Symbol::for_desc("NAPI_RS_SYMBOL"); export.set_named_property("NAPI_RS_SYMBOL", symbol)?; Ok(()) }