Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Rationale of Rspack Custom Binding

The reason why Rspack is so fast is that it's written in Rust and so as the Rspack's internal builtin plugins and builtin loaders.

For most of the time, We assume you've been using Rspack JavaScript API and writing Rspack JavaScript Plugins. And you might probably heard there're some overheads when using JavaScript API. The rumour is true! Rspack is mostly written in Rust and providing the adapting layer with JavaScript API requires a lot of hassle of passing values back and forth between Rust and JavaScript. This creates a lot of overheads and performance issues.

But have you ever wondered if there's a way to extend Rspack's functionality by writing native Rust code and not requiring to sacrifice the performance or if you're able to use the rich Rust APIs? And the answer is yes. This is where Rspack Custom Binding comes in.

To get started with Rspack Custom Binding, you need to know the surface level of how Rspack binding works.

How Rspack Binding Works

If you are using the @rspack/cli or @rspack/core and not knowing what a custom binding is, you are using Rspack binding. It's a simple architecture that allows you to extend Rspack's functionality by leveraging the Rspack JavaScript API. It's just the same as how you use the Webpack JavaScript API to extend Webpack.

Let's take a deep dive into the architecture. It contains 3 parts:

  • npm:@rspack/core: The JavaScript API layer of Rspack. Written in JavaScript.
  • npm:@rspack/binding: The Node.js Addon of Rspack.
  • crate:rspack_binding_api: The N-API glue layer of Rspack. Written in Rust.
flowchart TD
    Core("npm:@rspack/core")
    style Core stroke-width:0px,color:#FFDE59,fill:#545454

    Core --> Binding("npm:@rspack/binding")
    style Binding stroke-width:0px,color:#FFDE59,fill:#545454

    Binding --> APIs("crate:rspack_binding_api")
    style APIs stroke-width:0px,color:#FFDE59,fill:#545454

crate:rspack_binding_api

The N-API glue layer of Rspack.

This layer contains a glue code that bridges the gap between N-API-compatible runtimes, which, most of the time, is Node.js and Rust Core crates.

npm:@rspack/binding

The Node.js Addon of Rspack.

This layer links crate:rspack_binding_api and compiles it into a Node.js Addon (a *.node file) with NAPI-RS. The functionalities that npm:@rspack/core provides are mostly exposed by the Node.js Addon in npm:@rspack/binding.

Note: Maybe you have checked out the code on npm and it does not contain the *.node file. This is because the *.node files are dispatched by the @rspack/binding-* packages (e.g. @rspack/binding-darwin-arm64) for different platforms. Don't worry about this at the moment. We will get into the details in the custom binding section.

npm:@rspack/core

The JavaScript API layer of Rspack.

The internal of npm:@rspack/core is written in JavaScript. It bridges the gap between the Node.js Addon in npm:@rspack/binding and Rspack JavaScript API.

npm:@rspack/cli is a command line tool that uses npm:@rspack/core to build your project.

How Rspack Custom Binding Works

Let's use the diagram below to understand how a custom binding works. It shows a "Before" state, representing the standard Rspack setup, and an "After" state, which illustrates the custom binding approach.

In the Before state, your project uses the default Rspack binding. This is created solely from crate:rspack_binding_api, the core glue layer between Rust and Node.js.

In the After state, you introduce your own native code. As the diagram shows, your User Customizations (like custom Rust plugins) are combined with the original crate:rspack_binding_api.

This combination produces a new, personalized Custom Binding. This becomes your project's new Node.js addon, allowing you to inject high-performance, custom logic directly into Rspack's build process.

Crucially, you can continue to use npm:@rspack/core with your custom binding. This allows you to benefit from native performance and customization without rewriting the JavaScript API layer, reusing all the features it provides. We will cover how to integrate @rspack/core with a custom binding in a later section.

flowchart LR
    subgraph Before ["_Before_"]
        Original("crate:rspack_binding_api")
        style Original stroke-width:0px,color:#FFDE59,fill:#545454
    end

    subgraph After ["_After_"]
        Plugin("User Customizations:<br>- custom plugins")
        style Plugin stroke-width:0px,color:#AB7F45,fill:#FFE2B1

        API("crate:rspack_binding_api")
        style API stroke-width:0px,color:#FFDE59,fill:#545454

        Plugin --> CustomBinding("Custom Binding = <br>crate:rspack_binding_api + User Customizations")
        API --> CustomBinding
        style CustomBinding stroke-width:0px,color:#AB7F45,fill:#FFE2B1
    end

    Before -.-> After

    style Before stroke-dasharray: 5 5
    style After stroke-dasharray: 5 5

Next Steps

Now you have a basic understanding of how Rspack Custom Binding works. Let's move on to the Create From Template guide to set up your development environment.