npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@harmony/wasm-bindgen-webpack-plugin

v0.0.1

Published

Webpack plugin that compiles Rust crates to WebAssembly when importing lib.rs files

Readme

wasm-bindgen-webpack-plugin

WARNING: Most of this plugin was written by an LLM.

A Webpack plugin that automatically compiles Rust crates to WebAssembly when you import lib.rs files.

Features

  • 🦀 Automatic Rust compilation: Compiles Rust crates to WebAssembly when importing lib.rs
  • 🚀 wasm-bindgen integration: Automatically runs wasm-bindgen to generate JS bindings
  • 💾 Smart caching: Avoids recompilation when source hasn't changed
  • 🎯 TypeScript support: Generates TypeScript declarations
  • Webpack integration: Seamless integration with Webpack's module system

Prerequisites

Make sure you have the following tools installed:

# Install the WebAssembly target
rustup target add wasm32-unknown-unknown

# Install wasm-bindgen-cli
cargo install wasm-bindgen-cli

# Install binaryen (includes wasm-opt) - optional but recommended
# On macOS:
brew install binaryen

# On Ubuntu/Debian:
sudo apt install binaryen

# Or build from source:
git clone https://github.com/WebAssembly/binaryen.git
cd binaryen
cmake . && make

Installation

pnpm install wasm-bindgen-webpack-plugin

Quick Start

  1. Build the plugin:

    pnpm install
    pnpm run build
  2. Try the complete example:

    cd example
    pnpm install
    pnpm run dev
  3. Open your browser to http://localhost:8080

Usage

TypeScript Interface

The plugin accepts the following configuration options:

interface WasmBindgenWebpackPluginOptions {
  /** Directory where compiled wasm files will be cached */
  cacheDir?: string;
  /** Additional cargo build flags */
  cargoArgs?: string[];
  /** Additional wasm-bindgen flags */
  wasmBindgenArgs?: string[];
  /** Enable WebAssembly optimization with wasm-opt before running wasm-bindgen */
  optimizeWebassembly?: boolean;
}

1. Configure Webpack

Add the plugin to your webpack configuration:

// webpack.config.js
const WasmBindgenWebpackPlugin = require("wasm-bindgen-webpack-plugin");

module.exports = {
  // ... other webpack config
  plugins: [
    new WasmBindgenWebpackPlugin({
      // Optional: Custom cache directory (default: ".cache/wasm")
      cacheDir: ".wasm-cache",

      // Optional: Additional cargo build flags (default: ["--release"])
      cargoArgs: ["--release"],

      // Optional: Additional wasm-bindgen flags (default: [])
      // Note: --typescript is automatically added by the plugin
      wasmBindgenArgs: [],

      // Optional: Enable WebAssembly optimization via wasm-opt (default: false)
      optimizeWebassembly: true,
    })
  ]
};

2. Create a Rust Crate

Create a Rust crate with WebAssembly bindings:

# my-rust-lib/Cargo.toml
[package]
name = "my-rust-lib"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
wasm-bindgen = "0.2"

[dependencies.web-sys]
version = "0.3"
features = [
  "console",
]
// my-rust-lib/src/lib.rs
use wasm_bindgen::prelude::*;

// Import the `console.log` function from the `console` module from the web-sys crate
#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);
}

// Define a macro to provide `console.log!(..)` syntax
macro_rules! console_log {
    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}

#[wasm_bindgen]
pub fn greet(name: &str) {
    console_log!("Hello, {}!", name);
}

#[wasm_bindgen]
pub fn add(a: i32, b: i32) -> i32 {
    a + b
}

3. Import in JavaScript/TypeScript

Now you can import the Rust crate directly by importing its lib.rs:

// Import the Rust crate - the plugin will compile it automatically!
import * as wasmModule from './my-rust-lib/src/lib.rs';

// Use the exported functions
wasmModule.greet("WebAssembly");
const result = wasmModule.add(5, 3);
console.log(result); // 8

TypeScript Support

If you're using TypeScript, you can create a declaration file next to your lib.rs that re-exports the actual generated types:

// my-rust-lib/src/lib.rs.d.ts
export * from "../../.cache/wasm/my_rust_lib";

The path in the re-export should match your cache directory structure. By default, the plugin caches compiled WebAssembly modules at .cache/wasm/{package_name}/.

Handling TypeScript Compilation Timing

When building from a clean state (no cache), you might encounter TypeScript errors because the Rust code hasn't been compiled yet when TypeScript tries to type-check your code. To solve this, use ForkTsCheckerWebpackPlugin with the correct plugin order.

Install the plugin:

pnpm install --save-dev fork-ts-checker-webpack-plugin

Important: Plugin order matters - WasmBindgenWebpackPlugin must come before ForkTsCheckerWebpackPlugin:

// webpack.config.js
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: {
          loader: 'ts-loader',
          options: {
            // `ForkTsCheckerWebpackPlugin` does async type checking.
            transpileOnly: true,
          },
        },
        exclude: /node_modules/,
      },
    ],
  },
  plugins: [
    // Order matters: `WasmBindgenWebpackPlugin` MUST come before `ForkTsCheckerWebpackPlugin`.
    new WasmBindgenWebpackPlugin({
      optimizeWebassembly: true,
    }),
    new ForkTsCheckerWebpackPlugin(),
  ],
};

This configuration:

  • Automatically delays TypeScript checking until WASM compilation completes
  • Requires both correct plugin order AND internal hook coordination
  • Provides seamless type checking with WASM modules on first build
  • The WasmBindgenWebpackPlugin automatically detects and integrates with ForkTsCheckerWebpackPlugin

How it Works

  1. Detection: The plugin hooks into Webpack's module resolution to detect when you import a lib.rs file
  2. Manifest Discovery: Uses cargo read-manifest from the directory containing the lib.rs file to get both the Cargo.toml location and the exact target name
  3. Target Directory Discovery: Uses cargo metadata to determine the correct target directory for the project
  4. Compilation: When detected, it:
    • Runs cargo build --target wasm32-unknown-unknown --target-dir <discovered-target-dir> to compile the Rust crate to WebAssembly
    • Optionally runs wasm-opt on the resulting .wasm file to optimize it (if wasmOptArgs are provided)
    • Runs wasm-bindgen on the (potentially optimized) .wasm file to generate JavaScript bindings and TypeScript declarations
  5. Caching: Results are cached in the specified cache directory and only recompiled when the Cargo.toml or Rust source files change
  6. Integration: The generated JavaScript file is returned to Webpack as if you had imported it directly
  7. Hot Reloading: All Rust source files and Cargo.toml are added as file dependencies for proper hot reloading

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | cacheDir | string | ".cache/wasm" | Directory where compiled WASM files are cached | | cargoArgs | string[] | ["--release"] | Additional arguments passed to cargo build | | wasmBindgenArgs | string[] | [] | Additional arguments passed to wasm-bindgen (Note: --typescript is automatically added) | | optimizeWebassembly | boolean | false | Enable WebAssembly optimization with wasm-opt |

Note: The plugin automatically determines the Cargo target directory using cargo metadata and doesn't require manual configuration.

Examples

Development vs Production

// webpack.config.js
const isProduction = process.env.NODE_ENV === "production";

module.exports = {
  plugins: [
    new WasmBindgenWebpackPlugin({
      cargoArgs: isProduction ? ["--release"] : [],
      wasmBindgenArgs: isProduction ? [] : ["--debug"],
      optimizeWebassembly: isProduction, // Only optimize in production
    })
  ]
};

Custom Cache Directory

// webpack.config.js
const path = require("path");

module.exports = {
  plugins: [
    new WasmBindgenWebpackPlugin({
      cacheDir: path.join(__dirname, ".wasm-cache"),
      optimizeWebassembly: true, // Enable optimization
    })
  ]
};

Development Mode (No Release Optimization)

// webpack.config.js
module.exports = {
  plugins: [
    new WasmBindgenWebpackPlugin({
      cargoArgs: [], // No --release flag for faster debug builds
      wasmBindgenArgs: ["--debug"] // Optional debug mode for wasm-bindgen
    })
  ]
};

WebAssembly Optimization

// webpack.config.js
module.exports = {
  plugins: [
    new WasmBindgenWebpackPlugin({
      cargoArgs: ["--release"],
      optimizeWebassembly: true, // Enables wasm-opt
    })
  ]
};

The optimizeWebassembly: true flag automatically applies these optimization flags:

  • -O: Optimize

Troubleshooting

Common Issues

  1. "cargo: command not found": Make sure Rust is installed and in your PATH
  2. "wasm-bindgen: command not found": Install wasm-bindgen-cli with cargo install wasm-bindgen-cli
  3. "target 'wasm32-unknown-unknown' not installed": Run rustup target add wasm32-unknown-unknown
  4. "wasm-opt: command not found": Install binaryen (brew install binaryen on macOS) or set optimizeWebassembly: false in your config
  5. TypeScript errors on first build (e.g., "Property 'add' does not exist"): This happens when TypeScript tries to type-check before Rust compilation generates the types. Use ForkTsCheckerWebpackPlugin with correct plugin order (WasmBindgenWebpackPlugin before ForkTsCheckerWebpackPlugin) as described in the TypeScript Support section

Performance Tips

  • The plugin caches compilation results, so subsequent builds are much faster
  • Use --release flag for production builds for smaller and faster WebAssembly modules
  • Enable optimizeWebassembly: true for maximum size optimization in production builds
  • Consider using wee_alloc as a global allocator in your Rust code to reduce bundle size
  • The optimization automatically enables bulk memory and other WebAssembly features for better performance