close

WebAssembly

Rslib can build libraries that reference WebAssembly (.wasm) files.

This feature is intended for library outputs that will be consumed by Node.js or by application bundlers such as Rsbuild, Vite, or other modern ESM-aware tools.

Warning

WASM support currently only works with format set to 'esm'.

This limitation only applies to Rslib's output format. Your source files can still be TypeScript or JavaScript as usual.

Enable WASM support

Set wasm: true in the lib configuration:

rslib.config.ts
import { defineConfig } from '@rslib/core';

export default defineConfig({
  lib: [
    {
      format: 'esm',
      wasm: true,
      source: {
        entry: {
          index: './src/index.ts',
        },
      },
    },
  ],
});

Supported input forms

Rslib supports the following input forms.

new URL() references

Use the standard new URL('./file.wasm', import.meta.url) pattern when your code needs a URL or file location for a .wasm file:

src/index.ts
export const wasmUrl = new URL('./add.wasm', import.meta.url);

By default, Rslib preserves this expression in the JavaScript output and emits the referenced .wasm file to the corresponding output location:

dist/index.js
const wasmUrl = new URL('./add.wasm', import.meta.url);
export { wasmUrl };
dist
dist/
  index.js
  add.wasm

This form is useful when you want to load or pass the wasm file yourself.

ESM .wasm imports

You can import exports from a .wasm file directly:

src/index.ts
import { add } from './add.wasm';

export const sum = add(1, 2);
export { add };

Rslib transforms the .wasm module into a JavaScript facade. The facade instantiates the WebAssembly module and re-exports the wasm exports as ESM exports.

By default, small .wasm files are inlined into the generated JavaScript facade:

dist/index.js
const __rslib_wasm_base64 = '...';
const { instance: __rslib_wasm_instance } = await WebAssembly.instantiate(...);
const __rslib_wasm_export_add = __rslib_wasm_instance.exports['add'];
export { __rslib_wasm_export_add as add };

The inline behavior avoids runtime asset path issues and works well for small wasm modules.

You can also re-export wasm modules:

src/index.ts
export { add } from './add.wasm';
export * from './add.wasm';

TypeScript declarations

TypeScript does not know the export names of arbitrary .wasm files by default. If your source imports a raw .wasm file, add declarations that match your wasm exports:

src/wasm.d.ts
declare module '*.wasm' {
  export function add(left: number, right: number): number;
}

For wasm generated by tools such as wasm-pack, prefer using the .d.ts files generated by those tools.

Controlling inline output

Rslib inlines small ESM .wasm imports by default. The default inline limit is 14 * 1024 bytes.

You can control this behavior with inline and inlineLimit:

rslib.config.ts
export default {
  lib: [
    {
      format: 'esm',
      wasm: {
        inline: 'auto',
        inlineLimit: 14 * 1024,
      },
    },
  ],
};

To force inline output:

rslib.config.ts
export default {
  lib: [
    {
      format: 'esm',
      wasm: {
        inline: true,
      },
    },
  ],
};

To emit the .wasm file as a separate asset for ESM .wasm imports:

rslib.config.ts
export default {
  lib: [
    {
      format: 'esm',
      wasm: {
        mode: 'asset',
        assetFileName: 'static/wasm/[name].[contenthash:8][ext]',
      },
    },
  ],
};

For Node.js targets, the generated facade reads the emitted .wasm file through node:fs/promises. For web targets, it loads the emitted .wasm file with fetch(new URL(..., import.meta.url)).

wasm-pack / wasm-bindgen

Rslib supports local JavaScript glue files that reference companion .wasm assets with the standard new URL('./file.wasm', import.meta.url) pattern. This also covers ESM glue generated by tools such as wasm-pack / wasm-bindgen when the generated glue uses that pattern.

For wasm-pack, the recommended target is currently wasm-pack --target web. This target generates ESM glue like:

pkg/my_lib.js
if (module_or_path === undefined) {
  module_or_path = new URL('my_lib_bg.wasm', import.meta.url);
}

You can import the generated glue from your library entry:

src/index.ts
import init, { add, initSync } from './pkg/my_lib.js';

export { init, initSync, add };

In bundled output, the glue file is processed through the same new URL() handling as other JavaScript modules. In bundleless output, Rslib additionally scans local JavaScript glue files and emits companion .wasm files next to them:

dist
dist/
  index.js
  pkg/
    my_lib.js
    my_lib_bg.wasm

Rslib does not patch the generated initialization protocol. This keeps APIs such as init(), initSync(), and custom initialization inputs working as generated by tools such as wasm-bindgen.

Warning

wasm-pack --target bundler uses ESM .wasm imports and may involve circular initialization between the wasm module and generated JavaScript glue. Treat it as an advanced scenario and test the final output in your target runtime.

wasm-pack --target nodejs and wasm-pack --target no-modules are not recommended for the current ESM-only WASM pipeline.

Advanced options

You can enable or disable each supported input form separately:

rslib.config.ts
export default {
  lib: [
    {
      format: 'esm',
      wasm: {
        // Support new URL('./foo.wasm', import.meta.url)
        url: true,
        // Support import { foo } from './foo.wasm'
        module: true,
        // In bundleless output, scan local JS glue files and copy companion wasm assets
        glue: true,
      },
    },
  ],
};

For new URL() references, Rslib preserves the original relative path by default. You can also rewrite the URL to an emitted asset filename:

rslib.config.ts
export default {
  lib: [
    {
      format: 'esm',
      wasm: {
        url: {
          mode: 'rewrite',
        },
        assetFileName: 'static/wasm/[name].[contenthash:8][ext]',
      },
    },
  ],
};

Rspack runtime mode

If you intentionally want to use Rspack's runtime handling for WebAssembly, you can opt into it explicitly:

rslib.config.ts
export default {
  lib: [
    {
      format: 'esm',
      wasm: {
        mode: 'rspack-runtime',
      },
    },
  ],
};

This mode enables Rspack's asyncWebAssembly experiment. It is useful when you control the consuming application environment, but it is not recommended as the default output strategy for portable libraries.