あらすじ
- SvelteKitの
v1.27.0
で書かれたアプリがあった <input type=file webkitdirectory multiple>
を使って、FormData
に載せてサーバーに送ってるv1.27.0
では、サーバー側でそのFile.name
から、パス情報を含んだ状態で受け取れたv1.27.1
以降、サーバー側でパス情報が受け取れなくなってた- ブラウザからのリクエスト時点では、パス情報が含まれてることは確認できてる
というわけで、SvelteKitをアップデートしたら、パッチアップデートしかないはずなのに壊れた・・・ということを調査してた。
あれこれ調べた結果、Request
のポリフィルの有無でそれが起きることがわかった。
変更としては、v1.27.1
のこのPRで入ったもの。
fix: only apply some polyfills below node 18.11 by dummdidumm · Pull Request #10920 · sveltejs/kit https://github.com/sveltejs/kit/pull/10920
すべてのNode.jsバージョンでポリフィルしてたものを、18.11以下でだけやるようになったと。
つまり、ポリフィルが使われなくなった結果、挙動が変わったということ。
調査
アプリ側の問題?
そもそもポリフィルは独自実装であり、できるならば使わないほうが良いように思う。
それで挙動が変わったなら、それこそが本来の挙動というべきであり、アプリの実装が間違った用途で利用してたってことになるはず。
そう思って、最初はアプリ側のコードを修正した。
が、Cloudflare Workersに実際にデプロイしてみると、修正したコードは動かず、修正前のコードでは動作するという状態に。
- Cloudflare Workers: パス情報を含んでる
- ローカルでの
vite dev
: パス情報を含まない
Bunで最小構成を組んでみても、パス情報は含まれてた。
ので、ローカルでの環境に何らかの問題があるはずで、
- ViteのSSRとSvelteKitの接合点の問題
- Node.js自体の問題
という切り分けをした。
ViteはただのNode.jsに従うのみ
https://github.com/sveltejs/kit/tree/master/packages/kit/src/exports/vite
コードを追ってみたが、Request
に対して特別なことはしておらず、ただグローバルにあるそれを使ってた。
関係あるとすれば、SvelteKitがグローバルをポリフィルする某PRにもあった部分。
となるとNode.jsの問題
この時点で使ってたNode.jsのバージョンはv20.2.0
で、そこそこ新しいものだったので、まさかここに問題があるとは思ってなかった。
が、試しにv21.2.0
にあげてみたら、見事に問題が起きなくなった。
Node.js・・・お前だったのか・・って感じ。
原因はNode.jsとUndiciのバージョン
原因は、Node.jsが依存しているundici
のバージョンが、Node.js自体のバージョンによって違うことだった。
- Node@20.2.0: Undici@5.22.0
- Node@21.2.0: Undici@5.27.0
この間のundici
のCHANGELOGを追ってみると、ドンピシャなアップデートがundici
に入ってた・・・。
fix: preserve file path when parsing formdata by jimmywarting · Pull Request #2245 · nodejs/undici https://github.com/nodejs/undici/pull/2245
これは、Undiciのv5.24.0
から入ってる。
Release v5.24.0 · nodejs/undici https://github.com/nodejs/undici/releases/tag/v5.24.0
Undiciのv5.24.0
が使われるようになったNode.jsのバージョンは、v20.8
以降なので、v20.2
のNode.jsではダメだが、v21.2
のNode.jsでは想定通りの挙動になるというわけ。
SvelteKitのバージョンアップによって、ポリフィル(Undici最新)が使われなくなった結果、古いUndiciに依存したNode.jsが使われることになり、それで予期せぬ挙動になった。
久々にこういうハマり方したわ・・・。