CLI
Full reference for the Wakaru command line.
Run Wakaru with npx wakaru or install it globally with npm i -g wakaru.
Decompile a single file
wakaru input.js -o output.js
cat input.js | wakaru > output.js # stdin/stdout work tooWithout -o, output goes to stdout.
A .cjs or .cts input is decompiled as CommonJS: its require() calls and
module.exports are left alone instead of being recovered as ESM syntax,
because Node loads such a file as CommonJS however it is written. Every other
input name still recovers ESM. --unpack does not apply this yet: a .cjs
input file, or a recovered module that keeps a .cjs name, can still be
written with ESM syntax that Node cannot load.
Unpack bundles
wakaru bundle.js --unpack -o out/
wakaru entry.js chunk.js --unpack -o out/ # multiple explicit files
wakaru dist/ --unpack -o out/ # recursively scan a directory
wakaru ./compiled-app --unpack -o out/ # Bun single-file executable
wakaru gtm.js --unpack -o out/ # Google Tag Manager containerVariants:
| Option | Effect |
|---|---|
--unpack | Detect the bundle format, split into modules, decompile each |
--unpack --raw | Raw split only: skips the readability pipeline (so --level does not apply). Scope-hoisted chunks still get the statement splitting that ESM linking needs. Provisional names, no module-graph promise |
--unpack=strict | Structural detection only, no heuristic fallback |
--unpack=inspect | Finer scope-hoist boundaries for static inspection. Always prints a warning. Not an executable reconstruction |
Directory inputs scan .js, .mjs, and .cjs recursively, skipping hidden
paths and node_modules. Input source maps (--source-map) are rejected
with --unpack.
Module filenames come from the paths in the bundle. Characters Windows does
not allow in a filename, such as " and *, become _ on every platform.
Unpacked output follows Node's rules for ESM and CommonJS, except in a few
known cases. A module that stays CommonJS is usually named .js, and an ESM
module imports it with a default import, which Node resolves to
module.exports. A CommonJS module that requires an ESM sibling needs
require(esm), Node v22.12 or v20.19 and later. A bundler that rebuilds the
output reads that import by the __esModule convention instead: if the
CommonJS module sets __esModule, the import reads its exports.default,
usually undefined. To rebuild, rename every file without module syntax
(import, export, import.meta, or top-level await) to .cjs, scripts
included, update the imports and kept require() calls that name them, and
add {"type": "module"} at the output root.
Module provenance
wakaru bundle.js --unpack --provenance -o out/--provenance adds provenance.json, linking recovered filenames to their
source inputs and byte ranges. Each range is [start, end): the start byte
is included, and the end byte is excluded. These are extraction regions,
not line-by-line mappings of the rewritten output. Each module's input is
the path exactly as you passed it, or the directory argument joined with the
file's path below it for a directory input. A module from an empty factory
has no ranges but still names its input.
See Read an unpacked bundle for an example, or use source maps to trace output positions.
Bun single-file executables
--unpack on a bun build --compile binary (PE, Mach-O, ELF) validates
Bun's embedded module graph and decompiles the JavaScript entries. It never
executes the binary. When the binary embeds its original source files, a
note: line on stderr names the wakaru bun extract command that writes
them. To dump every embedded file, assets, WASM, and native
add-ons included:
wakaru bun extract ./compiled-app -o extracted/
wakaru bun extract ./compiled-app -o extracted/ --json
wakaru bun extract ./compiled-app -o extracted/ --include-internalsbun extract is a container operation. It writes every validated file record
below extracted/files/ plus a manifest.json. It never parses or executes
the contents. Each file holds the stored bytes, except that non-ASCII
JavaScript or text that Bun 1.4.1+ stored as UTF-16 is written as UTF-8. When
the app was compiled with --sourcemap, the original source files embedded in
Bun's source maps are written below extracted/sources/, with each .. in a
path written as %2E%2E. If a record's source map cannot be read, its sources
are skipped with a warning and the rest is still extracted.
--include-internals also writes Bun's opaque
source-map, bytecode, and module-info regions. Bun 1.3.3+ is supported.
Google Tag Manager containers
--unpack on a saved gtm.js container skips the GTM runtime and writes the
code the site added: each Custom JS variable to macros/jsm-<n>.js, each
inline Custom HTML script to tags/html-<tag_id>-<n>.js, and an index.md
that lists the macros, the tags with the triggers that fire or block them, and
the external script URLs. Macro references read
__gtm_macro_<n>, where <n> is the row in index.md. Pass --raw to keep
each piece as extracted.
Rewrite level
wakaru input.js --level minimal
wakaru input.js --dce # full dead-code reachability sweepChoose minimal, standard (the default), or aggressive.
See Rewrite levels.
Source maps
wakaru input.js --source-map input.js.map -o output.js
wakaru input.js --emit-source-map -o output.js
wakaru extract input.js.map -o src/--source-mapuses an input map for identifier recovery and import deduplication (single-file mode only).--emit-source-mapwrites a.mapalongside each output file, mapping output back to input. Works with--unpack, where each module's map points into the bundle and does not embed the bundle's text. With--formatter, the map describes the formatted output.wakaru extractwrites the files embedded in a map'ssourcesContentto disk. When the map carries original sources, this recovers them directly.
Vue SFC recovery (experimental)
wakaru input.js --vue-sfc -o output.js # JavaScript plus a recovered input.vue
wakaru input.js --vue-sfc -o App.vue # Vue-only output; errors if recovery fails
wakaru bundle.js --unpack --vue-sfc -o out/ # additive .vue sidecars per recovered moduleBest-effort Vue 3 render recovery. With a non-.vue output path, Wakaru
writes normal JavaScript and adds a sibling .vue sidecar when recovery
succeeds. Without -o, stdout remains JavaScript.
Output options
wakaru input.js --formatter -o output.js # final formatting pass (off by default)
wakaru bundle.js --unpack --json -o out/ # machine-readable JSON to stdout--json includes warnings and errors in the JSON object. In unpack mode,
each module also gets an artifact kind and status. Useful for CI and
tooling.
Any warning with is_error: true makes Wakaru exit nonzero, but it still
writes every artifact and the JSON first. In unpack JSON, failed counts the
modules with such a warning; the other modules are still usable.
Within one major version, the --version line, the --json object,
provenance.json, and the exit status rules change only by addition: new
fields, and new values for category fields such as kind and status.
Ignore fields you do not know, and treat an unknown category value as unknown
rather than as an error.
Diagnostics
wakaru input.js --diagnostics # post-transform checks to stderr
wakaru input.js --profile trace.json # Chrome trace; add --profile-rules for per-rule spansWith --diagnostics, conflicting emitted declarations (including var versus
let or const across nested blocks) produce error-class warnings and a nonzero
exit. Legal repeated var declarations and inner-scope shadowing are allowed.
Unpack always reports a non-error cross_module_class_call warning when a
module may call a recovered class without new. Rerun with --level minimal
if the output must execute.
Decompile and unpack always report a non-error commonjs_export_unrecovered
warning when an ESM output module still reads or writes the listed exports
through exports or module.exports. Those accesses throw a ReferenceError
when they run.
A module that would come out as ESM with a require call left in it stays
CommonJS instead, since ESM has no require. Decompile and unpack always
report a non-error commonjs_require_unrecovered warning when an ESM output
module still calls require for the listed specifiers anyway. Those calls
throw a ReferenceError when they run.
Unpack always reports a non-error commonjs_require_of_esm warning when a
module that stayed CommonJS requires a module recovered as ESM whose
namespace differs from the CommonJS value it replaced, such as a
module.exports value it reads, a default it read through an interop
that is no longer there, or a write to its exports object, which the
namespace does not take. A provider that a module of the input writes to
stays CommonJS, so only a write unpack did not see is reported.
Unpack always reports a non-error commonjs_exports_escape warning when a
module passes a provider's exports object to a function in another module or
one wakaru cannot follow, and that provider is now an ES module. If the
function writes to the object, the write throws when it runs.
Unpack always reports a non-error missing_imported_name warning when an
ESM output module imports a name that the sibling ESM module it names does
not export. Node fails to link that module, so none of the module graph that
imports it runs.
With --diagnostics, decompile and unpack report a non-error
es_source_kept_commonjs warning for a module that stayed CommonJS although
its input looks compiled from an ES module, with the evidence and the
requires it kept.
Unpack reports a non-error runtime_residual warning when a module keeps a
bundler runtime call that the output does not define, such as Turbopack chunk
loading or path resolution through __turbopack_context__, or webpack's
require.e and require.t around a lazy import() whose chunk was not among
the inputs. It also lists webpack require(id) calls whose module id the
output does not link: in no input, in an opaque module, or in several modules
of the build. The rest of the module is recovered.
Overwrite protection
Wakaru refuses to overwrite existing files or write into a non-empty output
directory unless --force is passed.