Skip to Content
GuideDev Tooling

Dev Tooling

package.json scripts fallback

3va <name> runs package.json.scripts.<name> (via the project’s actual package manager — pnpm/yarn/bun/npm, detected by lockfile) whenever <name> isn’t one of 3va’s own subcommands — the same convention npm run <name> / pnpm <name> follow:

3va build # not a 3va subcommand → runs `pnpm run build` (or npm/yarn/bun)

Built-in subcommands always win: 3va dev / 3va test / etc. run 3va’s own implementation, never a same-named script.

This is not sandboxed — the delegated script is a real external process (the actual package manager, running arbitrary shell), completely outside the permissions system’s capability model (which only governs JS executed inside 3va’s own V8 engine; internally this lives in the vvva_permissions crate). Consistent with 3va install never running postinstall scripts, running it requires explicit consent: a [y/N] prompt in a TTY, --yes to skip it, "3va": { "no-prompt": true } in package.json to skip it permanently, or a hard deny with no prompt at all outside a TTY (CI, pipes).

Test runner

Jest-compatible. No configuration required.

3va test 3va test tests/unit 3va test --watch 3va test --coverage 3va test --update-snapshots

Supports describe, test, expect, watch mode, coverage reporting, and these matchers: toBe, toEqual, toStrictEqual, toBeNull, toBeUndefined, toBeDefined, toBeTruthy, toBeFalsy, toBeGreaterThan(OrEqual), toBeLessThan(OrEqual), toContain, toHaveLength, toMatch, toThrow, toMatchSnapshot, and toMatchInlineSnapshot. Implemented in the vvva_test crate — no Jest install needed.

Not implemented: mocks/spies (jest.fn(), toHaveBeenCalled(With)), toBeCloseTo, toMatchObject, toHaveProperty, toBeInstanceOf, toBeNaN, toContainEqual, and resolves/rejects. If your test suite depends on mocking, it isn’t portable to 3va test yet.

Bundler

3va bundle src/index.ts 3va bundle src/index.ts -o dist/bundle.js --minify

Walks the real import graph from the entry — project files, node_modules (both ESM and CommonJS packages), .json, and .css — and inlines everything into one self-contained file, runnable standalone via 3va run dist/bundle.js or in a browser <script> tag. .css imports inject a <style> tag when a DOM is present (browser) and no-op otherwise (CLI/server); asset imports (images, fonts) embed the original path as a string, not a copied/hashed file — there’s no production asset pipeline yet. The output directory is created automatically if it doesn’t exist.

--minify works. --source-map and --split are not implemented for this path — see Roadmap. For automatic rebuilds on change, use 3va dev (watches and rebuilds with a 300 ms debounce) — it also serves the project directly via on-demand transpilation without needing a full bundle at all.

Dev server with HMR

3va dev 3va dev --port 3000 --host 0.0.0.0 --open

Automatically detects the project framework (Next.js, Astro, Nuxt, SvelteKit, Remix, Gatsby, SolidStart, Qwik, RedwoodJS) and delegates to its native dev server. For custom/unrecognized setups, runs a built-in dev server:

  • On-demand ESM serving (Vite-style) — a root-level index.html referencing <script type="module" src="/src/main.jsx"> works directly: .js/.jsx/.ts/.tsx files are transpiled per request (JSX/TS stripped via oxc) and their import specifiers rewritten so the browser’s native ES module loader can resolve them — project-relative imports stay project-relative, bare specifiers ("react") and anything under node_modules resolve to /@fs/<path>. import "./x.css" is wrapped in a tiny style-injecting module; .css requested directly (a <link> tag) is served as-is.
  • A full bundle to dist/bundle.js still runs on start and on every source change (300 ms debounce) — served at /bundle.js, useful for a hand-rolled public/index.html that references it directly.
  • SPA fallback checks public/index.html, then a root-level index.html, then a built-in default page.

HMR is full-page reload via Server-Sent Events (/__hmr), not granular per-module hot replacement — see Roadmap. Two Ctrl+C within the 30s drain window force an immediate shutdown, useful since a browser tab’s open /__hmr connection otherwise keeps the server “draining” for the full timeout.

CPU profiler

3va run app.ts --prof # writes profile.cpuprofile 3va run app.ts --prof --flamegraph=flame.svg # also emit SVG flamegraph 3va prof profile.cpuprofile --top 20 # post-hoc analysis

Output is V8-compatible .cpuprofile JSON, loadable in Chrome DevTools and speedscope.app . Flamegraphs use the Inferno format.

Debugger

3va run app.ts --inspect # CDP on 127.0.0.1:9229 3va run app.ts --inspect=0.0.0.0:9230

Opens a WebSocket CDP server. Connect via chrome://inspect or any DAP-compatible IDE. debugger; statements pause execution and emit Debugger.paused CDP events.

Interactive sandbox

3va sandbox

REPL with permission management. Inside the session: .allow-read=PATH, .allow-write=PATH, .allow-net=HOST, .allow-env, and .permissions to list current grants. Leave with exit, quit, or ^D.

Other commands

3va doctor # environment health check 3va --accessible # EN 301 549 mode: no ANSI, no animations, screen-reader friendly