Skip to content
PortBay

A visual editor for Vite with nothing to install

PortBay launches your Vite dev server, so it adds source-location stamping to its own launch from a config generated outside your repo. Vue, Svelte, React and Qwik. Your package.json and node_modules stay byte-identical. Pro, early access, opt-in.

The short answer

How do I set up visual editing on a Vite project?

Visual editing on a Vite project normally begins with installing a plugin, which means changing your package.json, your lockfile and your config to get a development-only feature. That is avoidable when whatever launches the dev server can pass configuration in from outside the repository. PortBay launches yours, so it hands Vite a generated config that imports and spreads your own and adds a source-location plugin carried inside the app itself — nothing to install, and your project byte-identical before and after. It covers Vue, Svelte, React, Preact, Solid and Qwik, stamping .vue, .svelte, .jsx and .tsx with the file, line and column behind each element. The plugin applies only while serving, so a production build never loads it. Pro, early access, opt-in under Settings.

Verified against the product, 2026-09-05.

In the app

A Vite dev server, stamped at launch

acme-shop · Board6 cards3 agents online
Pending2
infra
Rate-limit the API
P1
Dark mode polish
P2
Todo2
auth
Add OAuth login
P0Claude Code0/3oauth-login
Auto-dispatching
implement OAuth on app.test
db
Migrate to Postgres
P1
In Progress1
Fix flaky checkout test
P0
Done2
Set up Mailpit inbox
P2
Seed demo data
P2
1/5 · AssignA card lands in Todo and @claude is mentioned

PortBay runs your Vite project at its own .test URL with trusted HTTPS and dispatches board cards into it. The visual editor edits that same running app in your real browser — one live site, not a multi-frame design canvas.

Walkthrough

Your first edit, with nothing installed

Four steps, and none of them is an install command. The stamping is already on by the time your dev server boots.

  1. Install PortBay and add your Vite project
  2. Turn the visual editor on
  3. Start the project — stamping is already there
  4. Open Edit in browser and change something

Install PortBay and add your Vite project

Homebrew installs the app and the bundled portbay CLI. Add the project folder and PortBay detects the framework and the bundler, runs your dev server, and serves it at its own .test hostname over trusted HTTPS.

brew tap portbay-app/portbay && brew install --cask portbay

Turn the visual editor on

It ships to Pro under early access and is off by default. Sign in to Pro, then flip the Early Access toggle. The open-source build does not include the editor at all — it is not compiled in.

Settings › Account › Early Access

Start the project — stamping is already there

PortBay writes a vite.config.mjs outside your repo that imports and spreads your own config, adds its plugin, and points the dev server at it with a single --config flag. Nothing is written inside your project. The plugin runs only while serving, so vite build never loads it and no stamp can reach a production bundle.

portbay start myapp

Open Edit in browser and change something

The project's Visual editing section has one button. It opens your normal browser at your normal .test URL with the edit bar docked at the top, booting in Preview mode where the page stays fully interactive. Switch to Edit, double-click text to type into the live page, then Save to write to source.

https://myapp.test
Without PortBay

Where .vue and .svelte differ from .jsx and .tsx

Both lanes are stamped, and both write back. They differ on one tier, and it is worth knowing which side of the line your project sits on before you judge the results.

So a Vue or Svelte project maps essentially everything you can click. A React project maps everything you wrote, and stops at markup that came out of a dependency you did not author.

Questions

Asked before downloading

Correct, for Vite. The plugin is compiled into the PortBay binary, written out to PortBay's own data directory, and handed to your dev server through a generated config that lives outside your repo. There is no package to add and none to remove: uninstall PortBay and your package.json, node_modules and config files are byte-for-byte what they were. The plugin is not on npm and never will be, because nothing needs to serve it.

Vue, Svelte and SvelteKit, React (which is also the lane Preact and Solid take), Qwik and Angular — anything running on Vite. Astro and Nuxt are supported too, through their own injection paths, because neither takes the same config flag: Astro needs a project-relative config path and Nuxt has no --config at all, so it is extended as a layer instead. Each of those has its own page with the details specific to it; this page covers the mechanism they share.

JSX was refused, and that changed in August 2026. Documentation and older write-ups still say .jsx and .tsx cannot be stamped; that is out of date. Both are scanned script-first now and their host elements carry data-pb-loc, and a className edit writes back through a tree-sitter JSX path. One tier genuinely did not come back — see the next answer.

Component usages. In a .vue or .svelte file, a <Card/> tag carries its own coordinate, so an element a component rendered still traces back to your markup. In a .jsx or .tsx file it does not, because a capitalised tag there can be a TypeScript generic parameter list rather than a component, and inserting an attribute into the wrong one is a syntax error in your module. The practical loss is markup produced by a library you did not author: it carries no coordinate.

No. The plugin declares apply: 'serve', so Vite loads it for the dev server and never for vite build. There is also nothing to leave behind in your source, because the attribute is added during serving rather than written into your files — the difference from editors that write their own id attributes into your components and expect you to strip them later.

No. PortBay can only add its own instrumentation to dev servers it launches through Vite or Astro, so Babel pipelines get no stamping. Text, class and attribute edits still resolve by searching your source, but structural edits are refused rather than guessed. If you are on Next.js, that has its own supported path through an SWC plugin.

Two capabilities are worth knowing about. Renaming a Tailwind design token rewrites every reference to it across the project in the same save, so the definition and its uses never drift apart. And a selection can be extracted into a new component, which is supported on Astro, JSX, Svelte and Vue — the four languages whose grammar PortBay can move a subtree in safely. It refuses by name when a selection contains a template expression it cannot move rather than producing something that does not compile.

No. It is a Pro feature, still in early access behind an opt-in toggle in Settings, and it is not compiled into the open-source build. The rest of what this page describes — running your Vite dev server, the .test hostname, trusted HTTPS, the task board — is in the free, open-source app.

PortBay mascot — a friendly blue tugboat

Give your projects and your agents a real local home.

Download for macOS

Free & open source · macOS 11+ on Apple Silicon · Pro from $10/mo