A Bun bundler plugin that integrates javascript-obfuscator for code obfuscation during builds.
- TypeScript Support: Works seamlessly with TypeScript files - Bun handles compilation before obfuscation
- Separate Vendor Bundles: Automatically bundles node_modules separately (not obfuscated) and rewrites imports so everything works at runtime
- Recursive Dependency Scanning: Automatically discovers all external dependencies by scanning your entire codebase
- Comment-Aware: Ignores imports in commented-out code
- Minification Support: Apply Bun's minification before obfuscation for optimal code size
- Full Obfuscator Options: All javascript-obfuscator options are supported
bun add bun-plugin-javascript-obfuscatorThe obfuscatedBuild function provides a complete build pipeline that:
- Uses Bun to compile TypeScript to JavaScript and apply minification
- Applies obfuscation to your application code
- Bundles node_modules into a separate vendor file (not obfuscated)
- Rewrites imports in the main bundle to use the vendor bundle
import { obfuscatedBuild } from "bun-plugin-javascript-obfuscator";
const result = await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true, // Bun handles minification before obfuscation
obfuscator: {
compact: true,
controlFlowFlattening: true,
stringArray: true,
stringArrayThreshold: 0.75,
},
// Bundle node_modules separately (default: true)
bundleNodeModules: true,
nodeModulesBundleName: "vendor.js",
});
if (result.success) {
console.log("Build completed!");
console.log("Main bundle (obfuscated):", result.outputs);
console.log("Vendor bundle:", result.vendorOutput?.outputs);
}For simpler use cases where you don't need TypeScript support or separate vendor bundling, you can use the plugin API directly:
import { javascriptObfuscator } from "bun-plugin-javascript-obfuscator";
await Bun.build({
entrypoints: ["./src/index.js"], // Note: .js files only
outdir: "./dist",
plugins: [
javascriptObfuscator({
compact: true,
controlFlowFlattening: true,
}),
],
});The main build function that provides full TypeScript support and vendor bundle separation.
| Option | Type | Default | Description |
|---|---|---|---|
entrypoints |
string[] |
required | Entry point files for the build |
outdir |
string |
required | Output directory for bundled files |
minify |
boolean |
false |
Enable Bun's minification before obfuscation |
obfuscator |
ObfuscatorOptions |
{} |
javascript-obfuscator options |
bundleNodeModules |
boolean |
true |
Bundle node_modules into a separate file |
nodeModulesBundleName |
string |
"vendor.js" |
Name of the vendor bundle file |
isExternal |
(path: string) => boolean |
(see below) | Custom function to identify external modules |
plugins |
BunPlugin[] |
[] |
Additional Bun plugins to run before obfuscation |
external |
string[] |
[] |
Modules to exclude from both main and vendor bundles (e.g., native modules) |
skipVendorBundleGeneration |
boolean |
false |
Skip generating vendor bundle but still rewrite imports to use an existing one |
existingVendorBundlePath |
string |
undefined |
Path to existing vendor bundle (for validation when using skipVendorBundleGeneration) |
Default isExternal behavior: Modules are considered external if they:
- Contain
node_modulesin the path - Don't start with
.,/, or~(bare imports likelodash)
interface ObfuscatorBuildResult {
success: boolean;
logs: BuildLog[];
outputs: BuildArtifact[]; // Main bundle (obfuscated)
vendorOutput?: BuildOutput; // Vendor bundle (not obfuscated)
}Creates a Bun plugin for direct integration with Bun.build().
Note: This plugin works at the source file level and is best suited for JavaScript files. For TypeScript support, use obfuscatedBuild instead.
| Option | Type | Default | Description |
|---|---|---|---|
include |
RegExp |
/\.(js|mjs)$/ |
Files to include for obfuscation |
exclude |
RegExp |
undefined |
Files to exclude from obfuscation |
Plus all javascript-obfuscator options.
import { obfuscatedBuild } from "bun-plugin-javascript-obfuscator";
await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true,
target: "bun",
obfuscator: {
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.4,
debugProtection: true,
disableConsoleOutput: true,
identifierNamesGenerator: "hexadecimal",
renameGlobals: false,
selfDefending: true,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ["base64"],
stringArrayThreshold: 0.75,
},
});When using native modules that can't be bundled (e.g., modules with .node files), exclude them:
await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
minify: true,
obfuscator: {
compact: true,
stringArray: true,
},
// These modules will remain as external requires
external: [
"argon2", // Native crypto module
"nodejs-polars", // Has .node files
"better-sqlite3", // Native SQLite bindings
],
bundleNodeModules: true,
nodeModulesBundleName: "vendor.js",
});import { obfuscatedBuild } from "bun-plugin-javascript-obfuscator";
import JavaScriptObfuscator from "javascript-obfuscator";
// Get preset options
const presetOptions = JavaScriptObfuscator.getOptionsByPreset("high-obfuscation");
await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
obfuscator: presetOptions,
});Available presets:
defaultlow-obfuscationmedium-obfuscationhigh-obfuscation
If you want node_modules to remain external (not bundled at all):
await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
bundleNodeModules: false, // node_modules imports remain as external requires
obfuscator: {
compact: true,
},
});await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir: "./dist",
// Only treat specific packages as external
isExternal: (path) => {
return path.startsWith("react") || path.startsWith("lodash");
},
obfuscator: {
compact: true,
},
});When building multiple entrypoints separately (e.g., main app and worker scripts), you can share a single vendor bundle:
const outdir = "./dist";
const obfuscatorConfig = { compact: true, stringArray: true };
// First build: generates vendor.js
const mainResult = await obfuscatedBuild({
entrypoints: ["./src/index.ts"],
outdir,
minify: true,
obfuscator: obfuscatorConfig,
bundleNodeModules: true,
nodeModulesBundleName: "vendor.js",
});
// Second build: reuses existing vendor.js
const workerResult = await obfuscatedBuild({
entrypoints: [
"./src/workers/worker1.ts",
"./src/workers/worker2.ts",
],
outdir,
minify: true,
obfuscator: obfuscatorConfig,
bundleNodeModules: true,
nodeModulesBundleName: "vendor.js",
// Skip generating vendor.js, just rewrite imports to use the existing one
skipVendorBundleGeneration: true,
existingVendorBundlePath: `${outdir}/vendor.js`,
});This approach:
- Generates the vendor bundle only once (from the first build)
- Rewrites imports in all builds to reference the shared vendor bundle
- Avoids duplicating dependencies across multiple output files
-
Dependency Analysis: The build function recursively scans all your source files (starting from entrypoints) for import/require statements to identify external dependencies. Comments are stripped before scanning to avoid false positives from commented-out code.
-
Phase 1 - Bun Compilation: Your TypeScript/JavaScript code is compiled and bundled by Bun with node_modules marked as external. This phase handles:
- TypeScript to JavaScript compilation
- Minification (if enabled)
- Tree shaking
- Bundle optimization
-
Phase 2 - Obfuscation: The bundled JavaScript output is passed through javascript-obfuscator with your specified options.
-
Phase 3 - Vendor Bundle: If
bundleNodeModulesis enabled:- External dependencies are bundled into a separate vendor file (not obfuscated)
- The main bundle is rewritten to import from the vendor bundle instead of the original package names
- All import styles are handled:
import x from,import * as x from,import { a, b } from, andrequire()
This approach keeps your application code obfuscated while:
- Third-party code remains readable (it's already public anyway)
- Avoiding issues that can occur when obfuscating already-minified library code
- Making debugging easier by keeping vendor code readable
The plugin is written in TypeScript and exports all necessary types:
import {
obfuscatedBuild,
javascriptObfuscator,
type ObfuscatorBuildOptions,
type ObfuscatorBuildResult,
type BunObfuscatorPluginOptions,
type ObfuscatorOptions,
} from "bun-plugin-javascript-obfuscator";MIT