close
  • English
  • Wasm

    Rslib natively supports WebAssembly (WASM) modules, allowing you to directly import and use .wasm files in your project using the ESM import mechanism defined by the WebAssembly ESM Integration proposal.

    Note

    When importing .wasm modules using WebAssembly ESM Integration, only ESM output is supported, so format must be set to 'esm' (the default).

    Use WASM modules

    Rslib supports the following ways to use .wasm modules.

    Static imports and re-exports

    You can use standard ESM syntax to import a .wasm module and access its instantiated exports, or re-export them directly:

    import { add } from './add.wasm';
    import * as wasm from './add.wasm';
    import './add.wasm';
    
    export { add } from './add.wasm';
    export * from './add.wasm';
    export * as wasm from './add.wasm';

    Dynamic import

    You can use import() to dynamically import a .wasm module and access its instantiated exports:

    const wasm = await import('./add.wasm');

    Source phase import

    You can use Source Phase Imports to obtain a compiled WebAssembly.Module and instantiate it manually with a custom import object:

    import source addModule from './add.wasm';
    
    const { instance } = await WebAssembly.instantiate(addModule, {
      env: { now: Date.now },
    });

    You can also use import.source() to obtain a compiled WebAssembly.Module dynamically:

    const addModule = await import.source('./add.wasm');
    Note

    TypeScript cannot currently parse import source or import.source(). Use these forms in JavaScript files, or choose a toolchain that supports them.

    Output modes

    You can use lib.wasm.mode to select the output mode for .wasm modules:

    • bundle is true: Only compile mode is available.
    • bundle is false: preserve mode is used by default when the .wasm modules are resolved and loaded by a downstream build tool that supports WebAssembly ESM Integration (such as Rsbuild or Rspack) or a target runtime with native support (such as Node.js versions matching >=24.5.0). If the consumer does not support this feature, or you do not want to rely on it to handle the .wasm modules, use compile mode.

    The following source files demonstrate how to configure the compile and preserve modes and their build outputs.

    src/index.ts
    src/utils.ts
    src/add.wasm
    export { useAdd } from './utils.js';

    compile mode

    Rslib parses each .wasm module, generates the JavaScript glue code required to load and instantiate it, and emits its binary as a static asset to the directory specified by output.distPath.wasm (dist/static/wasm by default), with a content hash in the filename.

    Depending on the bundle configuration, Rslib emits the following files in the dist directory:

    bundle
    bundleless
    index.js
    static/wasm/[contenthash].module.wasm
    function __webpack_require__(moduleId) {
      // Read from the cache and execute the registered module...
    }
    
    __webpack_require__.add = (modules) => {
      // Register modules...
    };
    __webpack_require__.v = async (
      exports,
      wasmModuleId,
      wasmModuleHash,
      importsObj,
    ) => {
      // Load static/wasm/[contenthash].module.wasm based on output.target...
      const bytes = await loadWasmBytes(wasmModuleHash);
      const { instance } = await WebAssembly.instantiate(bytes, importsObj);
      return Object.assign(exports, instance.exports);
    };
    
    __webpack_require__.add({
      './src/add.wasm'(module, exports, __webpack_require__) {
        module.exports = __webpack_require__.v(exports, module.id, '[contenthash]');
      },
    });
    
    const add = await __webpack_require__('./src/add.wasm');
    const useAdd = (a, b) => (0, add.add)(a, b);
    export { useAdd };

    The generated loading code depends on output.target:

    • web: Loads .wasm files with fetch.
    • node: Loads .wasm files with asynchronous Node.js file system APIs.

    preserve mode

    Rslib keeps imports of .wasm modules in the JavaScript output and emits them unchanged in the dist directory, preserving their source-relative paths and original filenames:

    index.js
    utils.js
    add.wasm
    export { useAdd } from './utils.js';

    preserve mode retains the original .wasm filenames, so output.filenameHash does not affect them.

    Path and filename constraints for JavaScript output

    Rslib updates imports of .wasm files in the JavaScript output to point to the emitted files, but does not update import module names recorded inside .wasm binaries.

    If any of these module names resolve to JavaScript output, avoid changing its relative paths or filenames with these options:

    Use with wasm-bindgen

    wasm-bindgen is a tool for building WebAssembly libraries with Rust. The --target option generates output for different runtime environments.

    Rslib currently supports the following targets:

    • bundler (recommended): The JavaScript glue imports the .wasm module as an ES module while providing the imports required to instantiate it. Both compile and preserve modes are supported. When using preserve mode, follow the path and filename constraints described above.
    • module: The JavaScript glue uses a Source Phase import to obtain the compiled WebAssembly.Module, then constructs the import object and instantiates the module. Both compile and preserve modes are supported.
    • web / experimental-nodejs-module: The JavaScript glue locates and loads the .wasm file through new URL('./pkg.wasm', import.meta.url). Rslib treats the file as a static asset, so lib.wasm.mode does not apply.

    Type declaration

    TypeScript does not provide built-in module declarations for .wasm files. If you use TypeScript, add a declaration file next to the .wasm file using the .d.wasm.ts extension, and enable allowArbitraryExtensions in tsconfig.json:

    src/add.d.wasm.ts
    export function add(a: number, b: number): number;