8000 fix(dev): stop the proxy swallowing /dev-ui and serving a stale bundle by i-yliu · Pull Request #545 · google/adk-web · GitHub
[go: up one dir, main page]

Skip to content

fix(dev): stop the proxy swallowing /dev-ui and serving a stale bundle - #545

Open
i-yliu wants to merge 1 commit into
google:mainfrom
i-yliu:fix-dev-ui-proxy-prefix
Open

i-yliu wants to merge 1 commit into
google:mainfrom
i-yliu:fix-dev-ui-proxy-prefix

Conversation

@i-yliu
@i-yliu i-yliu commented Oct 14, 2026
Copy link
Copy Markdown
Contributor

What

proxy.conf.mjs keys are plain strings, and vite matches a plain-string key as a prefix of the whole request URL:

// vite/src/node/server/middlewares/proxy.ts
function doesProxyContextMatchUrl(context, url) {
  return (context[0] === '^' && new RegExp(context).test(url)) || url.startsWith(context)
}

So '/dev' also matched /dev-ui/... — the path at which adk web serves the Dev UI bundle it ships. Opening the dev server at http://localhost:4200/dev-ui/ fetched the backend's prebuilt main-<hash>.js, not the build the dev server had just produced from the working tree.

Nothing reports this. The app loads, looks right, and behaves like the released version; local changes simply never appear. /dev-ui/ is the path adk web prints and the one anybody switching from adk web to ng serve already has in their address bar, so it is easy to land on.

The fix

Anchor each entry as a regex. vite compiles a key beginning with ^ to a RegExp, which lets the path boundary be stated instead of left to a prefix:

const endpoint = (path) => `^${path}(?:[/?#]|$)`;

The path either ends there or continues after a /, and a query string still matches because the URL is tested whole (/list-apps?relative_path=./ has to keep working).

Two things fall out of the boundary:

  • the '/**' companion keys are redundant, so each path family is one entry instead of two;
  • '/run' no longer needs to be declared after '/run_live' to avoid eating it.

Testing

Checked every key against the URLs the app actually requests:

URL before after
/dev-ui/main-<hash>.js proxied to backend ❌ served by dev server ✅
/dev-ui/ proxied to backend ❌ served by dev server ✅
/dev/apps/x/eval_results proxied ✅ proxied ✅
/dev/apps/x/builder?ts=1 proxied ✅ proxied ✅
/list-apps?relative_path=./ proxied ✅ proxied ✅
/config/telemetry proxied ✅ proxied ✅
/run_live, /run_sse, /run proxied ✅ proxied ✅
/apps/x/users/u/sessions proxied ✅ proxied ✅
/agent-identity/x proxied ✅ proxied ✅
/assets/..., /main.js, / local ✅ local ✅

End to end against a running adk web backend:

$ curl -s localhost:4200/dev-ui/ | grep -o '<script[^>]*src="[^"]*"'
<script type="module" src="/@vite/client"     # the dev server's own build
<script src="polyfills.js"
<script src="main.js"

$ curl -o /dev/null -w '%{http_code}' localhost:4200/dev/apps/home_automation_agent/eval_results
200
$ curl -o /dev/null -w '%{http_code}' 'localhost:4200/list-apps?relative_path=./'
200

Dev-server configuration only; no production build or runtime code is touched.

The dev-server proxy keys are plain strings, and vite matches a plain-string
key as a prefix of the whole request URL. '/dev' therefore also matched
'/dev-ui/...', which is where `adk web` serves the Dev UI bundle it ships. So
opening the dev server at /dev-ui/ -- the path the backend prints, and the one
anybody arriving from `adk web` already has in their address bar -- fetched the
backend's prebuilt main-<hash>.js instead of the build just produced from the
working tree. The app looked right and behaved like the released version, with
no error anywhere to say the local changes had been bypassed.

Give each entry an anchored regex instead: vite compiles a key beginning with
'^' to a RegExp, which lets the path boundary be stated rather than left to a
prefix. '/dev' now ends at '/', '?', '#' or end of string, so '/dev-ui/...'
falls through to the dev server and '/dev/apps/...' still proxies. The same
boundary makes the '/**' companion keys redundant, so each path family is one
entry, and '/run' no longer depends on being declared after '/run_live'.
@gemini-code-assist gemini-code-assist Bot left a comment
Copy link
Copy Markdown

Choose a reaso 8000 n for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces an "endpoint" helper function in "proxy.conf.mjs" to generate regex-based path matchers, preventing prefix matching issues (such as "/dev" matching "/dev-ui") and allowing the removal of redundant wildcard paths. The review feedback suggests enhancing the "endpoint" function by escaping special regular expression characters in the input path to ensure defensive programming and prevent potential matching bugs in the future.

Comment thread proxy.conf.mjs
* boundary be stated: the path either ends here or continues after a '/', and
* a query string or fragment still matches because the URL is tested whole.
*/
const endpoint = (path) => `^${path}(?:[/?#]|$)`;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To ensure defensive programming and prevent potential matching bugs if paths containing special regular expression characters (such as ., +, ?, etc.) are added in the future, it is safer to escape the path string before interpolating it into the RegExp pattern.

const endpoint = (path) => {
  const escaped = path.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  return `^${escaped}(?:[/?#]|$)`;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0