Vite dev server: proxy config normalization reorders glob keys, drops string `context` and misses URLs with a query string
维护者通常 1 天内回复
已经有一个关联 PR 被合并了。
- #34258 来自 @aminesbdev —— 已合并
评估
- 难度
- 4/5
- 预计耗时
- 3-5 天
- 新手友好度
- 65/100
- Issue 类型
- 缺陷
- 描述清晰度
- 描述清楚
- 活跃度
- 活跃
- 技术栈
- angular, node.js, typescript, vite
调研方向
Start with packages/angular/build/src/utils/load-proxy-config.ts and inspect normalizeProxyConfiguration, then trace how Vite matches proxy patterns against request URLs. Check existing proxy configuration tests and run the relevant tests for ordering, string context, and query strings. Done means all three reproductions proxy to the expected backend without changing unrelated matching behavior.
由索引模型根据 Issue 内容生成。
描述
Command
serve
Is this a regression?
- Yes, this behavior used to work in the previous version
The previous version in which this bug was not present was
The webpack-based @angular-devkit/build-angular:dev-server
Description
normalizeProxyConfiguration in packages/angular/build/src/utils/load-proxy-config.ts turns the proxy file into the object Vite expects. Three things get lost along the way. In each case the request isn't proxied and falls through to the app (index.html), and nothing shows up in the ng serve output.
- Glob entries lose their position. Each glob key is replaced with
normalizedProxy[pattern] = …; delete normalizedProxy[key], which moves it to the end of the object. Vite uses the first entry that matches, so a specific glob written first loses to a broader plain key written after it. - A string
contextdrops the whole entry. In the array form, an entry whosecontextisn't an array is skipped. webpack-dev-server passescontextto http-proxy-middleware aspathFilter, which accepts a single string, socontext: '/legacy'works there. The array form conversion was added after #25337 so that webpack-style configs keep working, and this case slipped through. - Globs are matched against the URL including its query string. The regex built by picomatch ends with
$and Vite tests it againstreq.url, so/search/**matches/searchbut not/search?q=angular. http-proxy-middleware matches both globs and plain keys against the pathname only.
Minimal Reproduction
A new app served by @angular/build:dev-server, plus a backend that echoes the port and URL it receives:
// backend.mjs
import http from 'node:http';
for (const port of [3998, 3999]) {
http.createServer((req, res) => res.end(`${port} got ${req.url}\n`)).listen(port);
}
1. Order with ng serve --proxy-config proxy.conf.json:
{
"/api/auth/**": {"target": "http://localhost:3998"},
"/api/": {"target": "http://localhost:3999"}
}
curl localhost:4200/api/auth/login returns 3999 got /api/auth/login. I expected it to go to 3998.
2. String context with ng serve --proxy-config proxy.conf.mjs:
export default [{context: '/legacy', target: 'http://localhost:3999'}];
curl localhost:4200/legacy/users returns index.html. loadProxyConfiguration returns {} for this file.
3. Query string with ng serve --proxy-config proxy.conf.json:
{
"/search/**": {"target": "http://localhost:3999"}
}
curl localhost:4200/search is proxied, but curl 'localhost:4200/search?q=angular' returns index.html.
Exception or Error
None. The requests are just not proxied.
Your Environment
Angular CLI : 22.2.0
Angular : 22.2.0
Node.js : 24.21.0
Package Manager : npm 11.19.0
Operating System : darwin arm64
@angular/build : 22.2.0
@angular/cli : 22.2.0
vite : 8.3.0
The code is the same on main.
Anything else relevant?
#34258 fixes the first two points. The third one isn't part of it: for a trailing /**, picomatch puts a $ inside the generated regex, so it takes more than appending an optional query string, and it changes which requests get proxied.
- 主要语言
- TypeScript
- 星标
- 27k
- 派生
- 11.8k
- 平均合并
- 1 天 46 分钟
- 30 天内合并 PR
- 160
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
angular/angular-cli 的其他 Issue
-
area: @angular/cli
难度 1/5 1 小时以内 新手友好度 78/100
angular/angular-cli#34263 ·
维护者通常 1 天内回复
-
area: @angular/build gemini-triaged
难度 2/5 1-3 小时 新手友好度 74/100
angular/angular-cli#33955 ·
维护者通常 1 天内回复
-
area: @angular/cli gemini-triaged
难度 2/5 1-3 小时 新手友好度 72/100
angular/angular-cli#33055 · 1 条评论 · 3 个 reaction ·
维护者通常 1 天内回复
-
Two TS linting errors in `main.ts`可能已有人在做 @Hangell 今天认领。 未关闭area: @schematics/angular
难度 1/5 1 小时以内 新手友好度 45/100
angular/angular-cli#34267 ·
维护者通常 1 天内回复
-
area: @angular/build
难度 4/5 3-5 天 新手友好度 48/100
angular/angular-cli#34262 ·
维护者通常 1 天内回复
查看 angular/angular-cli 的全部 Issue
相似的 Issue
-
难度 2/5 1-3 小时 新手友好度 68/100
rajbos/ai-engineering-fluency#2340 · 1 条评论 ·
维护者通常 1 天内回复
-
community documentation first-timers-only good first issue hacktoberfest help wanted low hanging fruit up-for-grabs
难度 1/5 1 小时以内 新手友好度 70/100
lingdojo/kana-dojo#31864 · 1 条评论 · 5 个 reaction ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 68/100
zenstackhq/zenstack#2873 ·
维护者通常 1 天内回复
-
CLI: TUI shows onboarding when the provider's API key is only in the environment (e.g. OPENROUTER_API_KEY)可能已有人在做 关联的 PR 仍在进行中或已合并。 未关闭CLI
难度 2/5 1-3 小时 新手友好度 67/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 76/100
paperclipai/paperclip#15490 ·
维护者通常 1 天内回复