@nx-lang/sdk-wasm

中文文档
0.10.0发布于 2026/11/02MITTypeScriptES Module构建来源已验证

Browser and Node SDK for NX compilation, NX IR generation and the language service, over a WebAssembly module.

原始使用文档
文档目录16 节
  1. Scope
  2. Toolchain
  3. Loading: compile once, host many
  4. Language snapshots
  5. Workspace builds
  6. Libraries
  7. Standard libraries
  8. Declaration schemas
  9. Spelling a runtime value
  10. The image
  11. A trap ends the host; the caller replaces it
  12. Errors
  13. ABI
  14. Layout
  15. Experimental graphics preparation
  16. Execution migration

@nx-lang/sdk-wasm

Browser and Node access to the NX compiler, NX IR generation, and the language service, through one WebAssembly module. No server, no native addon.

This package is separate from @nx-lang/ir-runtime under runtime/typescript: use @nx-lang/sdk-wasm when JavaScript needs to compile NX source or answer editor queries over it, and the IR runtime when JavaScript only needs to execute an already persisted NX IR image. It also evaluates a program's root() to NX text, the form nxlang run prints, for showing a value to a person. Filesystem-backed workflows — library registries loaded from disk, workspace directories, root() evaluation to JSON values — belong to @nx-lang/sdk-node; this package sees only the source text it is handed, including the sources of the libraries a host loads into a registry.

Scope

ProvidedNot provided
Build a program artifact from in-memory modulesLibraries and workspaces read from directories
Library registries loaded from in-memory modulesEvaluating NX to JSON values (use the IR runtime)
Validate a workspace, answering diagnostics as data
Emit one NX IR artifact per module, library modules too
Format canonical values as annotated NX text
JSON Schema and documentation for a function or a typeDeriving schemas from an NX IR image
Hover, completions, diagnostics, document symbolsThreads, streaming, incremental analysis
An in-process NxLanguageService over host documents

Everything here answers over in-memory documents. Nothing needs a file to exist.

Toolchain

The module targets wasm32-wasip1, whose standard library bundles wasi-libc, so tree-sitter's C runtime and the NX grammar link with no shims. Building it needs:

  • The wasm32-wasip1 rustup target — listed in rust-toolchain.toml, so rustup installs it with the toolchain.
  • clang, to compile the C sources for that target.
  • The pinned wasi-sdk wasi-sysroot, which scripts/fetch-wasi-sysroot.mjs downloads into a gitignored .cache/ under the repository, verifies by SHA-256, and reuses afterwards.

pnpm --filter @nx-lang/sdk-wasm build runs all of that: the fetch, cargo for the wasm target under the wasm-release profile, and a copy of the module to dist/nx.wasm. There is no emscripten, no wasm-bindgen and no wasm-pack; the ABI is JSON in and JSON out over a hand-written loader, except the NX IR calls, which carry an image's bytes (see ABI below).

pnpm install
pnpm --filter @nx-lang/sdk-wasm build
pnpm --filter @nx-lang/sdk-wasm test

Loading: compile once, host many

The two halves of loading are separate on purpose. compileNxModule produces a WebAssembly.Module — the expensive, cacheable half — and createNxHost instantiates it, which takes tens of milliseconds. A caller keeps the module and creates hosts from it as often as it needs to.

import { compileNxModule, createNxHost } from "@nx-lang/sdk-wasm";

// In a browser: stream the module straight from the network.
const module = await compileNxModule(fetch(nxModuleUrl));
const host = createNxHost(module);

const artifact = host.buildProgramArtifact(source, { fileName: "input.nx" });
try {
  const [{ bytes, metadata }] = artifact.generateNxIr();
  console.log(metadata.identity, metadata.fingerprint, bytes.byteLength);
} finally {
  artifact.dispose();
}

buildProgramArtifact is the one-module case of a workspace build; see Workspace builds below. A build that reports an error throws NxEvaluationError. One that succeeds can still have warnings, such as a doc link that names nothing; artifact.diagnostics() returns them, with info and hints, in the same shape.

compileNxModule also accepts the module's bytes or an already-compiled WebAssembly.Module, so a caller that has one already can pass it through without a special case.

Two entry points are selected by the package's exports conditions, and both expose the same createNxHost:

  • the default entry supplies WASI through @bjorn3/browser_wasi_shim;
  • the node entry supplies it through node:wasi, and adds loadNxModule() for callers reading the module from the filesystem. Node marks node:wasi experimental and warns on import; the package's own tests and the playground's example check run with --no-warnings.

Language snapshots

const uri = "nx://tenant/form.nx";
const snapshot = host.createLanguageSnapshot([{ uri, version: 1, source }]);
try {
  const hover = snapshot.hover(uri, { line: 2, character: 3 });
  const completions = snapshot.completions(uri, { line: 2, character: 7 });
  const report = snapshot.diagnostics();
  const symbols = snapshot.documentSymbols(uri);
  const tree = snapshot.sourceTree(uri); // unstable
  // The value of `let greeting = "Hello"`, by its key in the source tree.
  const answer = snapshot.sourceEdit(uri, "greeting.value", {
    kind: "setValue",
    value: { kind: "string", value: "Hi" },
  }); // unstable
} finally {
  snapshot.dispose();
}

A snapshot is immutable: build a new one when a document changes. Analysis runs on the first query and is cached for the snapshot's lifetime, so several queries against unchanged text cost one analysis. Positions count UTF-16 code units, the way JavaScript strings and browser editors count, and results are the @nx-lang/language-protocol shapes, re-exported here.

sourceTree(uri) answers every piece of a document as a typed node, with the declarations the nodes refer to; the protocol's README describes the answer. It is unstable: its shape may change in any release until a later one commits to it. sourceEdit(uri, key, edit), unstable too, answers the text edits that set a value, set a line of text or remove an attribute at the node with that key, or why it cannot.

createLanguageService(host, options) implements the protocol's NxLanguageService over these snapshots, with a bounded cache of analyses. A host whose context declarations live in a catalog passes the catalog as a document of its own and names it as an implicit import:

const service = createLanguageService(host, {
  documents: [{ uri: "nx://host/drawnui.nx", identity: "drawnui.nx", source: catalog }],
  implicitImports: ["drawnui.nx"]
});

Every queried document then sees the catalog's exported declarations without an import line, and because its text is analyzed as written, every answer is already in its own coordinates. A diagnostic inside the catalog is reported against the catalog's URI, never the visitor's. The answering and the cache are @nx-lang/language-core, the same code the HTTP handler runs.

Workspace builds

A program can span several in-memory modules. The build takes them with an entry and, optionally, identities every other module imports implicitly, as if it began with import "<identity>":

const artifact = host.buildWorkspaceArtifact({
  modules: [
    { identity: "drawnui.nx", source: catalog, version: "9" },
    { identity: "input.nx", source }
  ],
  entry: "input.nx",
  implicitImports: ["drawnui.nx"]
});
try {
  const [snippet] = artifact.generateNxIr();
  // snippet.bytes names drawnui.nx at version "9" in its module table and carries none of it.
} finally {
  artifact.dispose();
}

An implicit import behaves exactly as the written wildcard import would, which means it sees what the module exports; a catalog declares its controls with export. A build failure is an NxEvaluationError whose diagnostics each carry a label against the identity of the module they belong to, in that module's own lines and bytes.

generateNxIr(options) emits one image per requested module, the entry alone by default: { modules: [] } emits every module of the program, entry first, and { modules: ["drawnui.nx"] } emits the catalog on its own. Each artifact's module table records the version each module was given in modules[].version, or "" for one given none. The debug section, spans and source text, is left out unless { debug: true } is passed; with it, the artifact differs from the one without only in that section. The metadata beside each artifact names the module, its fingerprint, the schema and ABI, the required features, and the module's function and component entrypoints by name.

Libraries

A server that compiles many tenants' NX against the same libraries loads them once per host into a registry, then builds and validates every tenant's workspace against a build context from it. A library is a logical root, an optional version, and its modules named relative to the root; one library imports another by a relative path to its root, exactly as a directory library would:

const registry = host.createLibraryRegistry();
const libraryWarnings = registry.loadLibraries([
  { root: "libraries/chat-link", modules: [{ identity: "ChatLinkConfig.nx", source: chatLinkSource }] },
  { root: "libraries/question-flow", version: "3", modules: questionFlowModules }
]);
const context = registry.createBuildContext({
  implicitImports: ["libraries/chat-link", "libraries/question-flow"]
});

const diagnostics = host.validateWorkspace({ modules: tenantModules, buildContext: context });
const artifact = host.buildWorkspaceArtifact({
  modules: tenantModules,
  entry: "chat-link.nx",
  buildContext: context
});

loadLibraries loads a list in dependency order, whatever order it is given in; loadLibrary loads one whose dependencies are already loaded. A library whose analysis reports errors, or that imports a root nothing loaded, is not retained, and the call throws NxEvaluationError with the diagnostics. A library that loads answers with its own warnings, info and hints, rendered against its source; this is the one place a host sees them, since validation and builds of a workspace leave them out. A root is immutable for the registry's life: loading it again with the same modules and version does nothing, and loading it with different ones throws naming the root. A build context holds the libraries it sees, so it stays usable after its registry is disposed; one created with visibleRoots sees only those libraries and what they depend on, and a visible root that is not a loaded library throws naming it.

An implicit import may name a loaded library's root as well as a workspace module, with the meaning of a written wildcard import of the library, so tenant source uses the libraries' declarations with no import line. An identity that is both a workspace module and exactly a library's root is refused as ambiguous. implicitImports given to a build or validation replaces the context's own, so implicitImports: [] builds without them.

A library's root names its modules, so it reserves its whole namespace: a workspace module whose identity lies under a visible or linked library's root, such as libraries/question-flow/Step.nx, fails validation and the build with workspace-module-in-library-root rather than standing in for the library's module.

validateWorkspace analyzes a workspace without building it and answers with every diagnostic of the submitted modules — errors, warnings, info and hints — as data, never throwing for NX diagnostics. An in-memory library's own warnings are not among them; its errors, which fail a build, are. It is what an editor or an authoring API reports to the person writing the source; a build then throws only for what validation already said, with the same diagnostics.

Every module of a library a program links is a module of the program: generateNxIr({ modules: [] }) emits an image for each, named <root>/<module> (for example libraries/question-flow/QuestionFlow.nx) and recording the library's version. A library module's image is the same bytes whichever tenant's program emitted it — it carries every declaration a using image could reach, derived ones included — so a runtime prepares it once with @nx-lang/ir-runtime and links every tenant's entry image against it:

const prepared = new Map(libraryImages.map((image) => [image.identity, prepareNxIrModule(image.bytes)]));
const program = linkNxIrProgram(prepareNxIrModule(entry.bytes), {
  resolve: (identity) => prepared.get(identity)
});

Standard libraries

A standard library is NX source the module itself carries, imported by a reserved name: import "@nx/agent". Nothing is loaded for it. Every entry point that analyzes or builds NX resolves it with no registry, build context or option, and a loadLibrary whose root lies under @nx/ is refused with library-root-reserved. A path under @nx/ that names no standard library is reported as unknown-standard-library, listing those that exist.

@nx/agent is the first: product-neutral types for declaring an AI agent, its documents and its tools. It is unstable, so its declarations may change incompatibly in any release, including a patch release; a host gets a change only by moving its pin of the NX packages.

const registry = host.createLibraryRegistry();
// A host library that names an agent type writes the import itself: a module of an implicitly
// imported library receives no implicit imports.
registry.loadLibrary({
  root: "libraries/chat-link",
  modules: [{ identity: "ChatLink.nx", source: 'import "@nx/agent"\nexport type AssistantConfig = { agent?:Agent }' }]
});
// Naming the standard library's root as an implicit import puts it in scope for tenant source, so
// an authored config needs no import line.
const context = registry.createBuildContext({ implicitImports: ["libraries/chat-link", "@nx/agent"] });
const artifact = host.buildWorkspaceArtifact({ modules: tenantModules, entry: "main.nx", buildContext: context });

// The library's image is emitted like any library module's and stored with the program's others;
// no runtime carries it.
const images = artifact.generateNxIr({ modules: [] });
const library = prepareNxIrModule(images.find((image) => image.identity === "@nx/agent/agent.nx")!.bytes);
const version = library.version; // 16 hex digits derived from the library's source

A program links @nx/agent/agent.nx only if something it uses imports the library, and the image is the same bytes whichever program emitted it. Its version is read from that image; a host that needs it before any tenant compiles builds the one-line source import "@nx/agent" and emits the library image from it. The library image lists the required feature function-reference-type-v1, so the runtime that links it must be a release that supports that feature.

Declaration schemas

A host that hands an NX function to a system that speaks JSON Schema — a language model's tool interface, an MCP client — asks the artifact for it while it compiles. functionSchema answers with JSON Schema (draft 2020-12) for the function's arguments and for its result, its /// documentation, and one entry per parameter:

const artifact = host.buildWorkspaceArtifact({
  modules: [{ identity: "tools.nx", source }],
  entry: "tools.nx"
});
try {
  const tool = artifact.functionSchema({ name: "findPlans" });
  tool.description;  // "Finds the plans that fit a team.\n\nPlans are sorted by price."
  tool.summary;      // "Finds the plans that fit a team."
  tool.inputSchema;  // { $schema, type: "object", properties: { teamSize: { type: "integer", … } }, … }
  tool.outputSchema; // { $schema, type: "array", items: { $ref: "#/$defs/Plan" }, $defs: { Plan: … } }
  tool.parameters;   // [{ name: "teamSize", type: "int", required: true, description: "…" }, …]

  const images = artifact.generateNxIr(); // the image a runtime calls the function from
  store(tool, images);
} finally {
  artifact.dispose();
}

with tools.nx:

/// A plan a team can buy.
type Plan = {
  name:string   /// The plan's display name.
}

/// Finds the plans that fit a team.
///
/// Plans are sorted by price.
let findPlans(
  teamSize:int,   /// Number of people who need a seat.
  maxMonthlyPrice?:int
): Plan* = { <Plan name="Team" /> }

These two queries are the supported way to read a program's types and documentation. The NX IR image holds neither — it erases generic arguments, records no alias targets, and carries no doc comments — so a host that only executes images, with @nx-lang/ir-runtime, derives the schemas when it compiles and stores them beside the images. Doc comments and these queries first ship together in release 0.6.0, the minimum version for both.

A function is named by the identity of its module and its name, the pair a Function record carries, so a host holding one from an evaluated value asks for its schema directly. The module defaults to the entry; a library module is named <root>/<module>, @nx/agent/agent.nx for the agent library. Any function qualifies, exported or not. typeSchema(reference, { direction }) answers for a record, action, union, type alias, <Target>.Update or <Target>.Property.

OptionQueryMeaning
hostSuppliedTypesfunctionSchemaTypes whose parameters the host fills in itself, such as { module: "@nx/agent/agent.nx", name: "ToolContext" }. A parameter declared with one, with a record extending one, or with a type alias of either, is left out of inputSchema and its entry names the type as hostSupplied. A parameter whose type holds one without being one, under + or as a field of a record at any depth, stays in inputSchema and its entry lists the types it holds as hostSuppliedWithin. A type the program does not declare matches nothing. An entry's typeRef names the record or union the parameter is declared with, and through a type alias what the alias denotes.
directiontypeSchemaoutput (the default) describes a value a runtime returns: every record carries $type. input describes a value a host supplies: $type is asked for only where a runtime needs it to choose a shape, at an abstract record or a payload union case.

A schema describes the canonical JSON encoding and nothing wider: a value valid against inputSchema is accepted as the function's arguments by a runtime running the image from the same artifact, and a value the function returns is valid against outputSchema; the package's tests hold both against @nx-lang/ir-runtime. Objects are closed (additionalProperties: false), an optional field or parameter is left out of required rather than made nullable, and object is { "not": { "type": "null" } }, any value but null. Records, unions and applied generic records are $defs entries the document refers to by $ref, so a recursive type is described once. The mapping for every type form is on the website's Declaration schemas reference page.

A type with no JSON form is reported, never approximated, and the answer is still returned: the affected schema is absent and diagnostics says why, while the other side is answered.

CodeMeaning
schema-inexpressible-typeA parameter, field or result has a function type, a function reference type (FunctionTool.function), a component type, markup, an abstract record nothing in the program extends, or a result the checker could not infer. Labeled at the member.
schema-ambiguous-discriminatorTwo shapes at one abstract-record site share a $type, which a runtime refuses as ambiguous.
schema-unknown-declarationThe reference names nothing in the program. Thrown as NxEvaluationError, not answered.

Spelling a runtime value

The IR runtimes return values in canonical JSON. artifact.formatValue(value, options) spells such a value as { text, nodes } against the artifact's program, from the formatter formatValue(value) uses, so a host that runs a program on @nx-lang/ir-runtime shows its values as the command line would. The program is not evaluated.

const artifact = host.buildProgramArtifact(`external component <Button label:string emits { Tapped { } } />
type Size = { width:float64 }`);
try {
  artifact.formatValue({ $type: "Size", width: 3 }).text; // <Size width=3.0 />
  artifact.formatValue({
    $type: "Button",
    label: "Add",
    onTapped: { $type: "ActionHandler", action: "Button.Tapped", token: "h1-1" }
  }).text;
  // <Button
  //   label="Add"
  //   onTapped=<ActionHandler action="Button.Tapped" token="h1-1" />
  // />
} finally {
  artifact.dispose();
}

An ActionHandler record, which the runtimes return where a handler is bound, is spelled as that record; formatValue(value) refuses one, since an interpreter handler has no token. Canonical JSON writes a whole float64 as it writes an int, and a constant union case as a bare string, so each number and string is read by the type its record declares for it: width=3.0 above. For a value with no record around it, options.type gives its type (formatValue(3, { type: "float64" }) is 3.0). The records may be declared in the entry module or in a library the program links. A field typed by a type parameter is read as an int when whole, since the value does not carry the type argument. options.state names a component, and the value is that component's state, spelled one name=value per line in declaration order, each declared at its state field.

A value outside the canonical format throws NxEvaluationError with code nx-value-invalid, and one with no NX spelling, a sequence directly in a sequence, nx-text-unspellable; either names the pointer of the value at fault. The artifact stays usable. undefined, which JSON cannot carry, throws TypeError; the empty value is null or [].

The image

NxGeneratedNxIr.bytes is the artifact as an NX IR image: a binary of 32-bit cells that @nx-lang/ir-runtime reads in place, copied out of the module's memory so it outlives the artifact and the host. It is byte for byte what the Node SDK, the .NET SDK and the CLI emit for the same input, and no debug section unless asked for. host.explainNxIr(bytes) renders an image as the text nxlang ir explain prints, with every table index resolved, and throws NxEvaluationError for bytes that are not an image this build reads. The layout is documented in docs/nx-ir-format.md.

A trap ends the host; the caller replaces it

The module targets wasm32-wasip1, where a panic aborts rather than unwinds. A panic or an out-of-bounds access inside the module therefore ends the instance and its memory — there is no catch_unwind that could hide it, and the request that trapped is lost.

The SDK makes that explicit rather than papering over it:

  • the call that trapped throws NxHostCrashedError, naming the operation;
  • every later call on that host throws the same error without entering the module, and host.crashed is true;
  • dispose() on resources from a crashed host is tolerated, so cleanup paths never mask the crash;
  • the caller recovers by calling createNxHost again on the compiled module it already has. That costs an instantiation, not a download or a recompilation.
try {
  return compile(host, source);
} catch (error) {
  if (error instanceof NxHostCrashedError) {
    host = createNxHost(module); // same module; no fetch
  }
  throw error;
}

The playground does exactly this inside its worker, so a compiler crash costs one request and the editor stays live.

Errors

ErrorThrown when
NxEvaluationErrorNX reports diagnostics: source that does not compile, a root that is missing, fails or has no NX spelling, an unparseable snapshot URI, duplicate identities, a library that cannot be loaded, a schema query for a declaration the program does not have. Carries diagnostics.
NxDisposedResourceErrorAn operation is attempted on a disposed artifact, snapshot, registry, build context or host. Disposing twice is allowed.
NxHostCrashedErrorThe module trapped, and on every later call to that host. Carries operation.
NxWasmErrorThe module's ABI version is not the loader's, or it answered in a shape the loader cannot read.

The names and shapes match @nx-lang/sdk-node, so code can move between the two bindings.

ABI

The module exports nx_wasm_abi_version, which the loader checks before any other call and refuses when it disagrees, naming both versions. The current version is 9. Version 4 added library registries (nx_wasm_registry_new, nx_wasm_registry_load, nx_wasm_registry_free), build contexts (nx_wasm_build_context_new, nx_wasm_build_context_free) and nx_wasm_workspace_validate, and gave nx_wasm_workspace_build a build-context handle argument (null for none); 5 added nx_wasm_program_diagnostics; 6 added nx_wasm_program_function_schema and nx_wasm_program_type_schema; 7 added nx_wasm_snapshot_source_tree; 8 added nx_wasm_program_format_value and a pointer on every value node; 9 added nx_wasm_snapshot_source_edit.

ExportsPurpose
nx_wasm_abi_version, nx_wasm_alloc, nx_wasm_free, nx_wasm_result_freeThe version check and the module's memory
nx_wasm_program_build, nx_wasm_workspace_build, nx_wasm_workspace_validateBuilding and validating programs
nx_wasm_registry_new, nx_wasm_registry_load, nx_wasm_registry_free, nx_wasm_build_context_new, nx_wasm_build_context_freeLibrary registries and build contexts
nx_wasm_snapshot_new, nx_wasm_snapshot_hover, nx_wasm_snapshot_completions, nx_wasm_snapshot_diagnostics, nx_wasm_snapshot_document_symbols, nx_wasm_snapshot_source_tree, nx_wasm_snapshot_freeLanguage snapshots
nx_wasm_ir_explainExplaining an image

Arguments cross as UTF-8 JSON in buffers from nx_wasm_alloc, or as an image's bytes for nx_wasm_ir_explain; every operation answers with a pointer to a { status, ptr, len } record whose payload is UTF-8 JSON, except that nx_wasm_program_nx_ir answers with an NX IR bundle (a u32 header length, a JSON header [{ identity, metadata, offset, length }], padding to four bytes, then the images), released through nx_wasm_result_free before the call returns. Handles to artifacts, snapshots, registries and build contexts are opaque to the loader, and a build context is refused by any host but the one that created it.

The Rust side is bindings/wasm/native (crate nx-sdk-wasm-native), over nx-api, nx-codegen and nx-language-service. Its NX IR, diagnostic and schema payloads are the ones the Node binding serializes, and the package's parity tests compare the two bindings' answers on every test run, so a divergence fails the build rather than reaching a site.

Layout

PathWhat it holds
native/The Rust crate and its ABI
src/The loader, the two WASI entry points, the language service, errors and types
scripts/The wasm build and clean scripts
test/Loader, SDK, language service, trap, entry-point, schema agreement and Node-SDK parity tests
test/fixtures/schema/The schema corpus: one NX source per mapping, with the documents the export answers and argument cases
dist/nx.wasmThe built module (gitignored; produced by pnpm run build)

Experimental graphics preparation

artifact.prepareGraphics(request) validates IR-evaluated graphics values using the shared nx-graphics core and declaration identities resolved from this artifact. Its public unstable NxGraphicsPreparationRequest / NxGraphicsPreparation interfaces describe values, construction origins, viewport/resource limits and supplied text measurements. Origins/measurements are trusted host reports, not an authentication boundary for arbitrary callers. No Skia is linked into the SDK.

Use preflight: true first: it validates identities and geometry/limits and returns deduplicated textRequests (each with its request, first requesting element ID and provenance), with scene: null. Measure those requests using the destination's supplied-font service, then call again with measurements to obtain a prepared scene. A preflight never publishes a scene with placeholder metrics. Diagnostics carry construction provenance and optional authored call sites. Graphics numbers are checked for finiteness before JSON encoding; malformed requests throw, and supported-profile preparation failures return structured diagnostics.

Execution migration

evaluateNx() has been removed. Compile to IR and execute with @nx-lang/ir-runtime, then pass its canonical value to artifact.formatValue(value, options). Formatting does not execute source. See the migration guide.

版本与发布记录

@nx-lang/sdk-wasm 共发布 10 个版本,首次发布于 2026/09/15;过去 12 个月发布了 10 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
0.10.0latest2026/11/021 天前
0.9.02026/10/268 天前
0.8.02026/10/1816 天前
0.7.02026/10/1024 天前
0.6.02026/10/0628 天前
0.5.02026/09/291 个月前

关于 @nx-lang/sdk-wasm 的常见问题

@nx-lang/sdk-wasm 是什么?

浏览器和Node SDK用于NX编译、NX IR生成和语言服务,通过WebAssembly模块实现。

如何安装 @nx-lang/sdk-wasm?

在项目目录运行 npm install @nx-lang/sdk-wasm,或使用 pnpm add / yarn add / bun add。

@nx-lang/sdk-wasm 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@nx-lang/sdk-wasm 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@nx-lang/sdk-wasm 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@nx-lang/sdk-wasm 可以商用吗?

@nx-lang/sdk-wasm 使用 MIT 许可。宽松许可:允许商业使用、修改和再分发,通常只需在分发时保留原版权与许可声明。以上为概括,不构成法律意见,请以许可原文为准。

@nx-lang/sdk-wasm 还在维护吗?

最新版本 0.10.0 发布于 2026/11/02(1 天前);至今共发布 10 个版本,其中过去 12 个月发布了 10 个;首次发布于 2026/09/15。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。