| title | Vite and Analog |
|---|---|
| description | Add the devtools Vite plugin to an Analog app. |
analog(), one import in main.ts. The hub mounts on the Vite dev server.
For *Analog apps, add the *Vite plugin next to analog() and load the overlay in main.ts. The plugin mounts the devtools hub on the Vite dev server.
@santoshyadavdev/ng-devtools and devframe. See Installation.
Register ngDevtools() after analog() in vite.config.ts.
Import the overlay in src/main.ts when import.meta.env.DEV is true.
Start the dev server and click the amber button, or open /__devframes/.
// vite.config.ts
import analog from '@analogjs/platform';
import ngDevtools from '@santoshyadavdev/ng-devtools/vite';
import {defineConfig} from 'vite';
export default defineConfig({
plugins: [analog(), ngDevtools()],
});The plugin does not inject the overlay. Your app imports it in main.ts:
// src/main.ts
import {bootstrapApplication} from '@angular/platform-browser';
import {App} from './app/app';
import {appConfig} from './app/app.config';
bootstrapApplication(App, appConfig).then(() => {
if (import.meta.env.DEV) void import('@santoshyadavdev/ng-devtools/overlay');
});import.meta.env.DEV is false in vite build, so the overlay stays out of your production bundle.
| What | Where |
|---|---|
| Floating button | Bottom-right corner of your page |
| Full-page viewer | /__devframes/ on the Vite dev server |
| HTTP MCP endpoint | /__devframes/__mcp |
The plugin applies to vite serve only. vite build is not affected, so nothing from the plugin reaches your production output.
It mounts the devtools hub on the Vite dev server. The WebSocket shares the dev server's port, over HTTP or HTTPS (server.https or @vitejs/plugin-basic-ssl). In middleware mode, where Vite has no server of its own, the WebSocket runs on its own port.
The hub keeps working after a dev server restart, for example after a config or .env change.
It records Analog page renders, load() fetches, server functions and API calls for the Analog inspector. The apiPrefix option tells it which requests are API calls.
The plugin only answers requests from a loopback address (any 127.x.x.x address or ::1). Other requests to the devtools get 403 with the message "ng-devtools only answers requests from this machine." WebSocket upgrades follow the same rules.
By default the plugin leaves the one-time code off, and the loopback and origin checks take its place. If server.allowedHosts or allowedOrigins allows a host that is not a loopback host, the plugin also asks for the code. See auth. Access and redaction covers every check.
// vite.config.ts
ngDevtools({
base: '/__devframes/',
apiPrefix: 'api',
allowedOrigins: ['https://tunnel.example'],
});| Option | Default | What it does |
|---|---|---|
base |
'/__devframes/' |
Where the hub is mounted. |
apiPrefix |
Analog's apiPrefix, or 'api' |
The prefix of your server routes, used to classify API calls. |
allowedOrigins |
none | Extra exact origins allowed to reach the devtools, for example a tunnel. |
auth |
on if a non-loopback host or origin is allowed, otherwise off | Whether the devtools ask for the one-time code. |
The plugin also takes the devtools options, such as inspectors, agent, actions, redaction and limits. See Configuration.
Change base if /__devframes/ clashes with a route of your own. The leading and trailing slashes are optional: 'devtools', '/devtools' and '/devtools/' all mount the hub at /devtools/, and the loopback checks cover the whole path. The overlay looks for /__devframes/ng-devtools/ and /__ng-devtools/ by default, so a custom base also needs a custom overlay path: pass <base>ng-devtools/ to initOverlay. The floating button follows that path. See A custom mount path.
The plugin reads apiPrefix from your Analog config. Set it here only when the detection is wrong.
Each entry is an origin, such as https://tunnel.example. The request itself must still come from a loopback address.
The plugin reads each entry the way a browser sends an origin: it drops a path or a trailing slash and lowercases the host, so 'https://Tunnel.example/app/' allows https://tunnel.example. It prints a warning in the terminal when it changes an entry, and it ignores an entry that is not a URL, such as 'tunnel.example'. The first request from each origin that the check refuses also prints a warning that names the origin.
A tunnel forwards other people's requests to your machine, and those requests arrive from a loopback address. So the plugin turns the one-time code on when Vite's server.allowedHosts or allowedOrigins allows anything other than localhost or a loopback address (allowedHosts: true counts too). The server prints the code in the terminal, and a browser reads data only after it exchanges that code.
| Value | Effect |
|---|---|
| not set | The code is on only if a non-loopback host or origin is allowed. |
true |
The code is always on. |
false |
The code is always off. The loopback and origin checks still apply. |
While the code is on, the HTTP MCP endpoint also asks for a bearer token. See Send a token.
If your tunnel rewrites the Host header to localhost, you don't list it in server.allowedHosts, so the plugin leaves the code off. Pass auth: true:
// vite.config.ts
ngDevtools({auth: true});If you open the dev server through another hostname that points to your machine (for example myapp.test), list it in Vite's server.allowedHosts. The devtools trust it too.
// vite.config.ts
import analog from '@analogjs/platform';
import ngDevtools from '@santoshyadavdev/ng-devtools/vite';
import {defineConfig} from 'vite';
export default defineConfig({
server: {allowedHosts: ['myapp.test']},
plugins: [analog(), ngDevtools()],
});Add other origins with allowedOrigins:
// vite.config.ts
ngDevtools({allowedOrigins: ['https://tunnel.example']});A non-loopback entry in server.allowedHosts or allowedOrigins turns the one-time code on. See auth.
import.meta.env.DEV.
The request did not come from your machine, or its origin is not trusted. The terminal names a refused origin. Open the app on localhost, list your hostname in server.allowedHosts, or add the origin to allowedOrigins.
The plugin records server calls made through the Vite dev server. Check that the plugin is registered and that apiPrefix matches your server routes. The Analog guide walks through a full setup.
A full Analog setup, including the demo in this repository.
File routes, server calls, render modes, content and lint.
What the overlay sends, and how it finds the server.
The loopback check and the origin rules in detail.