Rspack & Rsbuild Plugin

Obfuscate JavaScript in an Rspack or Rsbuild build

Add one plugin to the Rspack config, or to tools.rspack in Rsbuild, and every production JavaScript asset is protected after Rspack’s minifier and before the content hash is computed. The free options run on your own machine with no account.

Tested 2026-10-29

Real builds, same result

Rspack 2.3 and Rsbuild 2.3, production mode with the built-in minifier, javascriptobfuscator-com 0.5.0, no account. The protected bundle printed exactly what the unprotected one printed.

HookprocessAssets, after minification
Hashes[contenthash] follows protected file
Source mapsRemoved for protected assets
Setup

Rspack: one line in plugins

The plugin ships inside javascriptobfuscator-com as javascriptobfuscator-com/rspack.

Terminal
npm install --save-dev javascriptobfuscator-com
rspack.config.js
const JsoProtectorRspackPlugin = require("javascriptobfuscator-com/rspack");

module.exports = {
  mode: "production",
  entry: "./src/main.js",
  devtool: "source-map",
  output: { filename: "[name].[contenthash].js", clean: true },
  plugins: [new JsoProtectorRspackPlugin()]
};

What the plugin does on rspack build

  1. Taps processAssets at the optimize-size stage. Rspack’s built-in minifier has already run by then, so the plugin protects the minified code and nothing re-minifies it afterwards.
  2. Protects every .js asset in one batch and replaces it in the compilation; CSS, HTML and images are untouched.
  3. Leaves hashing to Rspack. The real content hash is computed later, so [contenthash] changes when the protected file changes and long-term caching stays correct.
  4. Drops the asset’s source map, so no .map describing the unprotected code is emitted.
  5. Picks the engine. No API key and only free options: protected locally, nothing uploaded. With a key, paid options run on the hosted engine.
Rsbuild

Rsbuild: pass the same plugin through tools.rspack

rsbuild.config.mjs
import { defineConfig } from "@rsbuild/core";
import JsoProtectorRspackPlugin from "javascriptobfuscator-com/rspack";

const isProduction = process.env.NODE_ENV === "production";

export default defineConfig({
  output: { sourceMap: { js: "source-map" } },
  tools: {
    rspack: {
      plugins: isProduction ? [new JsoProtectorRspackPlugin()] : []
    }
  }
});

Checked with Rsbuild 2.3

rsbuild build wrote static/js/index.[hash].js protected — strings encoded, the free-version header present — and no .map next to it, although output.sourceMap asked for one.

tools.rspack also applies to rsbuild dev, so the config above adds the plugin only when NODE_ENV is production, which rsbuild build sets. Development rebuilds stay fast and readable.

Using Rsbuild for a React, Vue or Svelte app? The framework guides cover what to exclude: React, Vue, Svelte.

Real Output

What came out of the Rspack build

The sample is a pricing table and a licence-key checksum in three modules. The unprotected production bundle was 516 bytes; the protected one 1,254 bytes, of which 546 are the free-version comment (left out below).

dist/main.261f6a5fd1a3e691.js (excerpt)
(()=>{"use strict";let c,a,b=[{name:"\x73\x74\x61\x72\x74\x65\x72",seats:5,monthly:29},{name:"\x74\x65\x61\x6d",seats:25,monthly:49},{name:"\x62\x75\x73\x69\x6e\x65\x73\x73",seats:100,monthly:99}];function d(b){let a=0;for(let c of b+"\x61\x63\x6d\x65\x2d\x6c\x69\x63\x65\x6e\x73\x65\x2d\x76\x32")a=31*a+c.charCodeAt(0)>>>0;return a.toString(16);}...

Both bundles printed {"quote":{"tier":"team","total":490,"perSeat":40.83},"valid":true,"forged":false}. With the free engine, quoted strings are encoded and local names replaced; property names, template-literal strings and the program’s structure stay as they were. The paid presets add string encryption, flattening and runtime defences — each transform shown on real code.

Options

Constructor options

OptionWhat it doesExample
presetfree by default with no API key; standard, balanced and maximum need a plan.preset: "standard"
excludeAsset names to leave unprotected.exclude: ["**/vendors-*.js"]
extensionsWhich asset extensions count as JavaScript. Default [".js"].extensions: [".js", ".mjs"]
reservedNamesNames the renamer must keep.reservedNames: ["bootstrapApp"]
removeSourceMapsOn by default.removeSourceMaps: false
manifestWrites a JSON record of what was protected.manifest: "dist/jso-manifest.json"

Paid presets read credentials from JSO_API_KEY and JSO_API_PASSWORD; set them as CI secrets, not in the config file. Excluding the vendor chunk is usually worth it: third-party libraries gain little from obfuscation and cost build time.

Frequently Asked

Rspack obfuscation questions

Does the obfuscator run before or after Rspack’s minifier?

After. In our Rspack 2.3 and Rsbuild 2.3 production builds the built-in minifier had already run when the plugin received the assets, so the protected output was not re-minified.

Are content hashes still correct after obfuscation?

Yes. The plugin updates the assets before Rspack computes the real content hash, so [contenthash] reflects the protected file. In our test the hash changed from 717a097b… unprotected to 261f6a5f… protected.

How do I add it to Rsbuild?

Through tools.rspack in rsbuild.config: tools: { rspack: { plugins: [new JsoProtectorRspackPlugin()] } }. Rsbuild passes the plugin to the Rspack compiler it runs — in development too, so add it only when NODE_ENV is production.

Do I need an account?

No. With no API key the plugin protects on your own machine with the free engine: local variables renamed and string literals encoded, nothing uploaded, no rate limit. The output starts with a short comment naming the product. Paid options run on the hosted engine and need a plan.

Other Build Tools

Not using Rspack?

The same package protects Rollup, esbuild, Parcel and Gulp builds, or any output folder from the command line.