文档
概念
External

External

External (opens in a new tab) 与在 Class 内部中使用的 Object Wrap (opens in a new tab) 非常相似。

Object Wrap 附加一个原生值到一个 JavaScript 对象上,并且可以在这个对象被 GC 回收时通知你, External 创建一个空的 JavaScript 对象,它在内部保存了原生值。只会在将对象传回 Rust 时生效:

lib.rs
use napi::bindgen_prelude::*;
use napi_derive::napi;
 
#[napi]
fn create_source_map(length: u32) -> External<Buffer> {
  External::new(vec![0; length as usize].into())
}

⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️⬇️

index.d.ts
export class ExternalObject<T> {
  readonly '': {
    readonly '': unique symbol
    [K: symbol]: T
  }
}
 
export function createSourceMap(length: number): ExternalObject<Buffer>

当你想要返回一个包含一些与原生 Rust 代码交互的方法的 JavaScript 对象时,External 是非常有用的, 这里是一个真实的例子:

https://github.com/h-a-n-a/magic-string-rs/blob/v0.3.0/node/src/lib.rs#L96-L103 (opens in a new tab)

https://github.com/h-a-n-a/magic-string-rs/blob/v0.3.0/node/index.js#L7-L23 (opens in a new tab)

lib.rs
impl MagicString {
  #[napi(ts_return_type = "{ toString: () => string, toUrl: () => string }")]
  pub fn generate_map(
    &mut self,
    options: Option<magic_string::GenerateDecodedMapOptions>,
  ) -> Result<External<SourceMap>> {
    let external = create_external(self.0.generate_map(options.unwrap_or_default())?);
    Ok(external)
  }
 
  /// @internal
  #[napi]
  pub fn to_sourcemap_string(&mut self, sourcemap: External<SourceMap>) -> Result<String> {
    Ok((*sourcemap.as_ref()).to_string()?)
  }
 
  /// @internal
  #[napi]
  pub fn to_sourcemap_url(&mut self, sourcemap: External<SourceMap>) -> Result<String> {
    Ok((*sourcemap.as_ref()).to_url()?)
  }
}

首先,generate_map 方法返回一个 External 对象,然后 JavaScript 函数在闭包中保存 External 对象:

index.js
module.exports.MagicString = class MagicString extends MagicStringNative {
  generateMap(options) {
    const sourcemap = super.generateMap({
      file: null,
      source: null,
      sourceRoot: null,
      includeContent: false,
      ...options,
    })
 
    const toString = () => super.toSourcemapString(sourcemap)
    const toUrl = () => super.toSourcemapUrl(sourcemap)
 
    return {
      toString,
      toUrl,
    }
  }
}