Vue Applications

Your Vue bundle is minified. Anyone can still read it.

vite build shrinks your app for transfer — it does not hide it. One beautifier pass and your Pinia stores, navigation guards, feature flags, and pricing rules are readable again. Obfuscate the built bundle so the JavaScript you hand every visitor stops explaining how your product works.

Reality Check

vite build → dist/assets/index-a1b2.js

That file is your whole front end. Minified, yes. Protected, no — until something removes the meaning as well as the whitespace.

SFCs compile awayTemplates become render functions — protect the output, not the .vue files.
Contracts preservedProp names and emitted events stay reserved.
Router intactPath strings and named routes survive untouched.
Threat Model

Everything in dist/ is public by definition

A Vue SPA is a complete client program delivered to anyone who visits. Your route guards decide who sees what, your stores hold the shape of your domain, your composables carry the rules, and your API layer documents your backend. None of that is hidden by the build. The only variable is how long it takes a stranger to read it.

Navigation guards as a map

A readable beforeEach checking store.user.plan === 'pro' tells an attacker precisely which value to fake and which route to try. Protected control flow makes that a project, not a glance.

Stores describe your domain

Pinia state, getters, and actions in clear text are a free schema of your product — entitlements, limits, workflow states, and all the names you chose for them.

Composables leak the rules

Discounting, quota maths, and trial logic live in composables that ship verbatim. Obfuscation — plus VM protection on the entitlement path — turns copy-paste into reverse engineering.

Protect after the Vue compiler runs
npm run build                 # vite -> dist/
npx jso-protector \
  --preset maximum \
  --input dist \
  --output dist-protected
# deploy dist-protected/ instead of dist/
The Order of Operations

Compile → protect → deploy

  • Never obfuscate .vue files. The SFC compiler must parse your template, script, and style blocks as written.
  • Protect the whole dist folder in one pass so identifiers agree across the entry chunk and every lazily loaded route chunk.
  • Reserve the runtime string contracts — public prop names, emitted event names, route paths and named routes, persisted store keys, and any key read off an API response.
  • Deploy the protected folder and wire the step into CI so no release ships raw by accident.
  • Smoke test the protected build — login, a guarded route, a form submit, one lazy route, a page refresh that rehydrates a persisted store.
What To Exclude

Names Vue matches as strings at runtime

Renaming is safe where the compiler already resolved the reference. It is unsafe where a literal string is matched against a name while the app runs. That line is the entire configuration.

Props and emitted events

A parent writes :user-id="42" and @save="onSave". Those names are your component’s public API and survive into the compiled render code as strings. Reserve them.

Route paths and named routes

path: '/checkout' is matched against the URL, and router.push({ name: 'invoice' }) is matched against a literal. Both are contracts with the browser, not internal names.

Persisted store keys

Anything written to localStorage in one release and read in the next is a storage contract. Rename it and rehydration quietly fails for every returning user.

Layered Defense

Three layers doing three different jobs

Minification — the size layer

Vite already does it. Smaller download, fully reversible with a formatter. Useful, and not a security control — see minification vs obfuscation.

Obfuscation — the comprehension layer

Encrypted string pool, flattened control flow, a per-build polymorphic decoder, and VM bytecode for the functions that matter most. This is what survives beautifying.

Runtime defense — the behavior layer

Runtime defense spots tampering and debugger attachment, so a modified bundle reports in instead of quietly hammering your API.

Frequently Asked

Vue protection questions, answered

Isn’t the production build enough?

No. Vite minifies for bytes. Beautify index-*.js from any Vue site and the logic returns immediately. Compression is not protection.

Do I protect .vue or dist?

dist. The SFC compiler needs your source as written; protection consumes the JavaScript it emits.

Will props and events keep working?

Yes, once reserved. They are your component’s public contract — treat them like API field names, not internal variables.

What about Pinia persistence?

Reserve any store id or state key that crosses a storage or network boundary. Internal-only state renames safely.

Will it hurt performance?

Renaming and string protection are effectively free. VM protection is meaningfully slower than native JavaScript, so scope it to licensing and entitlement paths — never to a render loop.

How do I read production stack traces?

Keep each build’s identifier map private and use symbolication to translate traces back to real names.

Start Now

Read your own bundle the way an attacker would

Open your deployed Vue app, grab the main asset from dist/assets/, and run it through a formatter. Everything you can read, so can everyone else. Then paste that same file into the online obfuscator and compare.