はじめに
とある Web サイトで挑戦中の技術課題に「Next.js を使わず React で SSR しよう」というものがあり、 Express アプリケーションで SSR した React アプリケーションから静的ファイルを読み込もうとしたのだけど、なかなかうまくいかず四苦八苦した。
結論
静的ファイルを Express アプリケーションでサーブする時に使うexpress.static
という関数がある。
この関数に静的ファイルまでの相対パスを指定するとき、実行する Express アプリケーションからの相対パスではなく、Express アプリケーションを起動するディレクトリからの相対パスとなる。
Express アプリケーションをpackage.json
の script から起動するときは注意しよう。
構成
ライブラリ
ライブラリ | バージョン |
---|---|
Node.js | 19.4.0 |
React | 18.2.0 |
express | 4.18.2 |
ディレクトリ
.
├── dist/ # ビルドしたファイルの出力先
│ ├── client.js # Reactアプリケーションをビルドしたファイル
│ └── server.js # Expressアプリケーションをビルドしたファイル
├── node_modules
├── src/
│ ├── client.tsx # Reactアプリケーション本体
│ ├── index.tsx # Reactアプリケーションをhydrateするファイル
│ └── server.tsx # Expressアプリケーションの実装
├── .gitignore
├── package-lock.json
├── package.json
├── tsconfig.json
└── webpack.config.ts
ハマったポイント
Express アプリケーションで SSR した React アプリケーションをクライアントサイドで hydrate した時に、useState hook で state を更新できなかった。 Express アプリケーションの当初の実装は以下の通り。
|
|
server.tsx
をビルドしてdist/server.js
を出力していたため、8 行目をexpress.static("./")
とすれば、同じディレクトリに出力したdist/client.js
が読み込める想定だった。
Webpack を利用するのが初めてだったため、ビルドの設定に不備があるのかと Webpack 周りをひたすらググった後に、<script defer="defer" src="client.js"></script>
でサーブしているclient.js
が 404 になっていることに気付いた。
{
// 省略
"scripts": {
"dev": "webpack && node dist/server.js"
},
// 省略
}
上記はプロジェクトルートにあるpackage.json
の抜粋。
原因はプロジェクトルートにあるpackage.json
の script からnpm run dev
コマンドで Express アプリケーションを起動していたためだった。server.tsx
の 8 行目をexpress.static("dist")
に修正したところdist/client.js
が読み込まれ、state の更新ができるようになった。
|
|
サンプル
以下の GitHub リポジトリに本記事で使用したサンプルコードを公開している。
