まずは結論から
/api/以下の全階層のリクエストに対してプロキシを適用したい場合、パスには * を2つ書きましょう。
const PROXY_CONFIG = {
"/api/**": { // OK
target: "http://localhost:4321",
},
"/api/*": { // NG
target: "http://localhost:4321",
},
};
解説
Angular 17 まではプロキシの設定で /api/* と書くと、/api から始まるすべてのリクエストに対してプロキシが適用されていました(詳細は後述します)。
この挙動が Angular 18 から変わっています。
Angular 17 と 18 でプロキシの挙動が変わってしまった要因は2つあります。
- 開発サーバーが webpack-dev-server から Vite に変わった
- webpack-dev-server のバージョンが 4系から5系になった
直接的な原因は Angular そのものではなく、Angular CLI が依存している webpack-dev-server にあります。
Angular 18 アップデートの影響
何も考えずに ng update で Angular 18 にすると、既存のプロジェクトのビルダーが @angular-devkit/build-angular:application にマイグレーションされます(拒否もできます)。
...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:browser",
...
...
"architect": {
"build": {
"builder": "@angular-devkit/build-angular:application",
...
ビルダーが browser から application に変わると、使用されるバンドラーも Webpack から esbuild に変わります。
それに伴って開発サーバーも webpack-dev-server から Vite に変わります。
applicationビルダーは、Angular 17 から正式にサポートされましたが、当時は新規プロジェクトのデフォルトビルダーになっただけで、既存のプロジェクトに影響はありませんでした。
それが Angular 18 からは、アップデート時に既存のプロジェクトのビルダーがマイグレーションされるようになりました。
また、そのまま Webpack を使用する場合も注意が必要で、 webpack-dev-server のバージョンが5系になったことで、どちらにせよ今回の問題に直面します。
webpack-dev-server (v4) と Vite のパスの違い
次のように末尾が /* の挙動が webpack-dev-server (v4) と Vite で異なります。
const PROXY_CONFIG = {
"/api/*": {
target: "http://localhost:4321",
},
};
上記の場合、
- webpack-dev-server
-
/apiから始まるすべてのリクエストに対して機能する
-
- Vite
- 1階層までのリクエスト(
/api/usersまで)に対して機能する
- 1階層までのリクエスト(
| リクエストパス | webpack | Vite |
|---|---|---|
| /api/users | ◯ | ◯ |
| /api/users/settings | ◯ | × |
| /api/users/settings/admin | ◯ | × |
| /apihoge.html | ◯ | × |
このように挙動が異なるのは、 webpack-dev-server (v4) が後方互換性のために独自の実装をしているからです。
webpack-dev-server (v4) では、パスの末尾にある /* は削除されます。
そのため、/api/* と /api は同じパスとして扱われ、/api で始まるすべてのリクエストにマッチします。
これは誤解を招く実装であるため、v5では削除されています。
https://github.com/webpack/webpack-dev-server/issues/2454
おわりに
この件は GitHub に Issue として挙げられています。
#53652 Proxy config works differently when switching from Webpack to Vite devserver
そこでも言及されていますが、このことは Angular 公式のアップデートガイドには記載されていません。
Angular Update Guide from v17 to v18
クリティカルな変更点なので載せてもらいたいですが、せめて本記事が同じ問題でお悩みの方々の助けとなれば幸いです。