@reticlehq/vite-plugin
v3.2.0
Published
Vite plugin for Reticle: dev-only source-map stamping plus auto-injected reticle.connect(). apply:'serve' guarantees it never ships to production.
Maintainers
Readme
@reticlehq/vite-plugin
One-line Vite integration for Reticle. The plugin does the whole dev-time wiring for you:
- Source mapping: stamps
data-reticle-source="file:line:col"on JSX host elements (via@reticlehq/babel-plugin) soreticle_inspectcan report the component's source file. Needed on React 19. - Auto-connect: injects a dev-only
install(); reticle.connect()into your entry module, so you never touch the entry file yourself. - Svelte source mapping: the same stamp on Svelte markup, applied before
@sveltejs/vite-plugin-sveltecompiles it. - Dependency pre-bundling: declares the SDK's CJS runtime deps in
optimizeDepsso the SDK loads on linked and monorepo setups. - Production-safe by construction:
apply: 'serve'means Vite drops the plugin entirely fromvite build. There is no env gate to forget; instrumentation cannot reach a production web bundle.
Install
npm i -D @reticlehq/react @reticlehq/vite-plugin@reticlehq/react is the runtime kit the injected connect() imports (it re-exports the browser SDK). vite >= 4 is a peer dependency.
Use
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import { reticle } from '@reticlehq/vite-plugin';
export default defineConfig({
plugins: [reticle(), react()],
});That is the entire integration: no entry-file edit, no Babel-plugin wiring, no env gating. npx @reticlehq/server init writes this line for you in a Vite project, inserting reticle() right after the opening [, which is why that is the order shown here.
Array order does not actually matter: the plugin declares enforce: 'pre', so Vite runs it before @vitejs/plugin-react wherever you put it.
Options
reticle({
port, // bridge WebSocket port; baked into connect() only when non-default
session, // stable session label; defaults to a fresh per-tab id
projectId, // stable project identity; defaults to one derived from package.json name + root
token, // auth token forwarded to connect() when the bridge requires one
root, // project root, so reported source paths are repo-relative
sdkVersion, // installed SDK version, so a skewed pair can name itself
sourceMapping, // default true; stamp data-reticle-source (harmless on React <=18)
inject, // default true; auto-inject reticle.connect()
captureNetworkBodies, // default false; record request/response bodies on reticle_network
allowNonLocalhost, // default false; allow a page/bridge that is not on localhost (needs a token)
desktop, // default false; also apply to `vite build`, for an Electron/Tauri renderer
onWarn, // where a diagnostic goes; defaults to the console
});captureNetworkBodies is off by default because a body is the one part of a request that routinely carries a card number, a token, or a customer's address. It is also settable as VITE_RETICLE_CAPTURE_BODIES=1 for a single debugging session.
allowNonLocalhost is for a dev server that cannot be served on localhost — a host-based multi-tenant frontend, or an app with cookie-scoped auth on a custom dev hostname. It is not sufficient on its own: the SDK also requires a pairing token outside localhost, and refuses with "a pairing token is required outside localhost" when it is missing. The plugin supplies one automatically from the daemon's ~/.reticle/pairing-token, so a running daemon is normally all it takes — pass token yourself only when that file is unreachable. A bridge that is itself non-local must also use wss://. Settable as VITE_RETICLE_ALLOW_NON_LOCALHOST=1 for a single session.
desktop: true makes the plugin apply to vite build as well and calls connect() with allowInProduction, because a packaged desktop renderer is a production build with no dev server. That means an instrumented production bundle, which a web app must never ship. Keep it behind your own dev-only build target.
Apache-2.0.
