Files
fusion/docs/solutions/integration-issues/vite-api-source-modules-proxied-to-backend.md

5.2 KiB

title, date, category, module, problem_type, component, symptoms, root_cause, resolution_type, severity, related_components, tags
title date category module problem_type component symptoms root_cause resolution_type severity related_components tags
Vite API source modules proxied to the backend in dashboard dev mode 2026-06-08 integration-issues dashboard-dev-server integration_issue tooling
Agent-browser snapshots show a blank or broken dashboard even though the dashboard source compiles
Vite module requests such as /api.ts, /api-node.ts, or /api/legacy.ts are forwarded to the backend instead of served by Vite
Hot-module or cache-busted source requests with query strings can re-enter the backend proxy
config_error config_change medium
development_workflow
vite
proxy
agent-browser
hmr
dashboard
worktree
source-modules

Vite API source modules proxied to the backend in dashboard dev mode

Problem

The dashboard dev server used a broad /api proxy rule that caught the app's own Vite source-module requests. In linked-worktree browser verification, that made agent-browser see a blank or broken dashboard because requests for files like /api.ts and /api/legacy.ts were sent to the backend instead of Vite's module pipeline.

Symptoms

  • agent-browser could open the page but could not reliably inspect the Settings UI because the dashboard failed during module loading.
  • Direct requests for /api.ts, /api-node.ts, and /api/legacy.ts returned backend/proxy behavior instead of JavaScript from Vite.
  • /api/health still needed to proxy to the dashboard backend, so simply disabling the proxy was not a valid fix.
  • The first regex fix excluded only paths ending in .ts; review caught that Vite can append query strings, so /api/foo.ts?x=1 would still proxy.

What Didn't Work

  • Treating this as an agent-browser problem. The browser automation was working; the page it loaded was failing because module requests were misrouted.
  • Debugging linked-worktree HMR as a stale bundle issue. Stale bundles are a real worktree trap, but here direct URL checks showed Vite source module paths were being routed to the backend.
  • Switching the proxy from "/api" to a regex that only excluded \.ts$. That fixed plain /api/foo.ts but missed query-string requests that Vite may use for module import and HMR cache busting.
  • Removing or bypassing the API proxy. Real backend endpoints such as /api/health still need to reach the API server during dev.

Solution

Keep the backend proxy for real API endpoints, but make the proxy key exclude Vite source-module paths under /api*.

// Before: prefix proxy caught both backend endpoints and source modules.
proxy: {
  "/api": {
    target: `http://localhost:${process.env.FUSION_API_PORT ?? "4040"}`,
    changeOrigin: true,
    ws: true,
  },
}

The final proxy rule:

// packages/dashboard/vite.config.ts
server: {
  proxy: {
    // Keep Vite source modules under app/api* on the dev server while proxying real API endpoints.
    "^/api(?!/.*\\.[jt]sx?(?:\\?|$))(/|$)": {
      target: `http://localhost:${process.env.FUSION_API_PORT ?? "4040"}`,
      changeOrigin: true,
      ws: true,
    },
  },
}

Verify both sides of the boundary:

# Should be served by Vite as JavaScript modules.
curl -i "$DASHBOARD_URL/api.ts"
curl -i "$DASHBOARD_URL/api-node.ts"
curl -i "$DASHBOARD_URL/api/legacy.ts?import"

# Should still proxy to the backend API server.
curl -i "$DASHBOARD_URL/api/health"

After the fix, agent-browser could snapshot the dashboard and navigate Settings -> Project Models, including the Plan/Triage, Executor, and Reviewer controls.

Why This Works

Vite treats proxy keys beginning with ^ as regular expressions matched against the request URL. The dashboard has source modules whose served URLs begin with /api, while the backend API namespace also begins with /api; a prefix rule cannot distinguish them.

The negative lookahead rejects source-module extensions before the proxy claims the request:

  • /api/health matches the proxy and reaches the backend.
  • /api/legacy.ts does not match the proxy and stays on Vite.
  • /api/legacy.ts?import also stays on Vite because the source-extension check allows an optional query string.
  • .tsx, .js, and .jsx are excluded too so future source modules do not rediscover the same failure.

Prevention

  • When adding a Vite dev-server proxy, test both a real backend endpoint and any source modules that share the same URL prefix.
  • Include query-string cases in proxy-regex checks; Vite module and HMR requests are often not bare pathnames.
  • Prefer a short inline comment for subtle proxy regexes so future maintainers know which requests must stay on Vite.
  • If browser automation sees a blank dashboard, confirm module routing with direct curl checks before debugging the browser tool.