Next.JSのMiddlewareがEdge Runtime上でしか動かないのに、なぜnext dev等で動くのか

2024/07/27に公開

経緯

本業の方で、Next.JS14を用いて開発、というか既存のレガシーな作りを取っ払ってNextにreplaceしちゃおうぜ計画を行っている。
その際に技術的に気になったことをメモしていく。できれば継続的に🐟

今回は、Middlewareを使いたい瞬間があり、そこで色々調べた中で、Middlewareの動作環境の仕様で驚いた点があったのでメモしておく✏️

起こったこと

うちのサービスでは、基本的にUserAgentを元に、PCとMobileで分けてViewを作成している。
その判別処理を、NextのMiddleware機能を用いて、リクエストのパラメータにviewport情報を付与し、それを元にPCかSPかを判別しようとしていた。
https://nextjs.org/docs/pages/building-your-application/routing/middleware

しかしMiddlewareを設定してみても正常に機能せず、logを出力するようにしても出てこなかったので、なんでだろうなぁと思い色々記事を見たり、GPTに聞いたりしていた。

(ちなみにこの問題自体は、単純にpage extensionの問題だった。page配下ではないMiddlewareに対しても、page extensionが適応されることは少々違和感が残るが笑)
https://nextjs.org/docs/pages/api-reference/next-config-js/pageExtensions

MiddlewareはEdge Runtime上でしか動かない

技術顧問の方の力も借りつつ、上記問題を調べるうちに、公式のこの記述に出くわした
https://nextjs.org/docs/pages/building-your-application/routing/middleware#runtime

ミドルウェアは現在、Edgeランタイムのみをサポートしています。 Node.jsランタイムは使用できません。

Edge Runtimeとは、Vercelから出てるRuntimeらしく、Vercelが世界中に配置しているエッジ・サーバーに置いて、エンドユーザーがWebアプリケーションを使用するときの遅延を短縮することができるように設計されているらしい。
https://edge-runtime.vercel.app/

Edge Runtime自体は、Cloudflare Workers上で動くようになっているらしく、Vercel内部にCloudflare Workerが取り入れられているらしい。
https://news.ycombinator.com/item?id=29003514

でも、next devやstartはNode.JS Runtimeで動作するはずなので、

「もしかして、Vercelでデプロイ行わない限り、Middleware機能って使えない仕様になっているの!?」

という不安と疑問が湧き出てきたってわけだ😱

MiddlewareがNode.JS Runtime上でも動作する理由

でも上記問題は解決し、普通にnext dev時もstart時も、Middlewareが動作することが確認できた。
だとすると、公式ドキュメントの記載の意味は一体なんだったのか・・・

結論からいうと、
Next.jsでは、next devを使用する際に、Node.jsランタイムが通常使用されますが、ミドルウェアに関しては、Cloudflare Workersに似た仮想ワーカー環境がシミュレートされるらしい。

それで、一応Node.JS runtime上でもMiddlewareが機能しているのだ。
ただ、あくまで仮想ワーカーなので、Edge Runtimeで使えるAPIが全て使えるようになっているわけではなく、
Vercelでは、そもそもNode.JS runtime上でもMiddlewareがEdge Runtime上と同じくらい最適に動作できないかという話になっているっぽい。
これに関連する話は、このDiscusionでも議論されている。
https://github.com/vercel/next.js/discussions/46722

まとめ

公式ドキュメント、ややこしい言い回しすな😫

Discussion