laravel-InertiaのSSRでハマったこと


別記事でInertiaを導入したが、いらないJS呼んでる感が強くlighthouseとか使ったときにもあまり良いスコアがでなかった
（もっとも、一番の原因はTwitterやらGoogleAdsenseやらYouTubeの外部JSのせいだが）

https://qiita.com/miyawa-tarou/items/1b3ec0344e1b39ce9158

ということもありSSR（ServerSideRendering）を試そうと思ったのだが、自分の環境では色々ハマったので残しておく

# SSRに変更する

完全にこれ↓のままです。色々いじったけどこれはこのままでOKでした。

https://inertiajs.com/server-side-rendering

# どこのエラーかわからぬまま沼にハマる

## Reactのエラーが詳細に出ない

何も考えずに

```
yarn build
```

としたときにページは表示はされるのですが、ブラウザには下記のようなエラーが。結果的にSSRが動いていないです。

```
app-944fdd91.js:119 Uncaught Error: Minified React error #418; visit https://reactjs.org/docs/error-decoder.html?invariant=418 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.

Uncaught Error: Minified React error #423; visit https://reactjs.org/docs/error-decoder.html?invariant=423 for the full message or use the non-minified dev environment for full errors and additional helpful warnings.
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140947/a0cfda5b-1512-5ca7-35f5-153f4655be7d.png)

概要はわかるがどこがエラーなのかわからない……
これはproductionと認識されているからなので、下記を追加

```:.env.production
NODE_ENV=development
```

`yarn dev` で開発してもSSRで動いている気もするのでそれでも良いかもしれません。
まあ下記のようなエラーで何が悪いのか結局よくわからないんですけどね

```
Warning: Expected server HTML to contain a matching <header> in <div>.
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140947/a5c86218-3c8a-34d7-157f-d739aefa0dfa.png)

サーバー生成のものとHTMLが一致しないっぽい？
<header> は単に自分がはじめに書いたHTMLタグだからですね
何を書いても、タグを書かなくてもエラーになります。（中身空だと動きます）

## nodeサーバーにアクセスが行ったことがわからない

で、サーバー側と内容が異なる原因がそもそもnodeサーバーにアクセスが行っていなかったことでした。
下記のような感じでサーバー立てると思いますが、そもそも立ち上げなくてもブラウザ側のエラーが同じ。

```
$ php artisan inertia:start-ssr
Starting SSR server on port 13714...
Inertia SSR server started.
```

で、このサーバーの悪いところで、アクセスが行ったのかもよくわかりません。
ちなみに、下記のようにアクセスしたときにNOT_FOUNDになるのは正常に立ち上がっている感じです。

```
# curl http://localhost:13714       
{"status":"NOT_FOUND","timestamp":1676184716668}
```

ちなみに利用するのは `/render` ですが、直接叩くとエラーが出ます。
これ自体も必要な値を渡してないだけなので問題ありません。

```
# curl http://localhost:13714/render

nodeサーバー側
SyntaxError: Unexpected end of JSON input
    at JSON.parse (<anonymous>)
    at /render (file:///var/www/dojin/node_modules/@inertiajs/core/dist/server.esm.js:1:302)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Server.<anonymous> (file:///var/www/dojin/node_modules/@inertiajs/core/dist/server.esm.js:1:527)
```

わからんもんはわからないので、通信が来たら呼ばれそうなところに適当にログを仕込みました。下のあたり

https://github.com/inertiajs/inertia/blob/e62247fd8da9fee1e8321f9035bcd773866543b7/packages/core/src/server.ts#L26-L37

結果直接飛ぶとログが吐かれますが、作成中のページを開いても何も出ません。
なのでサーバーは立てたがどこからもアクセスが来てないようです。

## Inertiaからnodeサーバーにアクセスするところを確認する

Inertiaのどこでアクセスしているかというと

https://github.com/inertiajs/inertia-laravel/blob/dfa84251bf1c2f46aa5091c8775e9825e3c390bb/src/Ssr/HttpGateway.php#L13-L34

↑ここです。Exception吐いても何も残していないので、何もわからないのです。

参考：https://github.com/inertiajs/inertia-laravel/pull/425/files
とりあえずこれに近い感じでログに吐くようにしたら、エラーが検知できました。

```
[2023-02-12 11:27:11] local.ERROR: GuzzleHttp\Exception\ConnectException: cURL error 7: Failed to connect to 127.0.0.1 port 13714: Connection refused (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for http://127.0.0.1:13714/render in /var/www/dojin/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:210
Stack trace:
#0 /var/www/dojin/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(158): GuzzleHttp\Handler\CurlFactory::createRejection(Object(GuzzleHttp\Handler\EasyHandle), Array)
#1 /var/www/dojin/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php(110): GuzzleHttp\Handler\CurlFactory::finishError(Object(GuzzleHttp\Handler\CurlHandler), Object(GuzzleHttp\Handler\EasyHandle), Object(GuzzleHttp\Handler\CurlFactory))
（以下略）
```

やっぱりここの通信が失敗してますね。

結果的に自分のエラーは
「DockerでPHPサーバーを構築しているが、PHPサーバーからローカル（WSL）に立てたnodeのサーバーへアクセスが出来なかったことが原因」でした。
そのためPHPサーバーから `curl` しても動かないです。
特殊な環境な気もするので同じハマり方をするかたは少ないでしょうけど…。

解決策としてはnodeサーバー自体をPHPと同じところに立てることで、ここの通信ができるようになりました。
（本当はローカルに立てた方が便利なのですが、ここの通信部分のあれこれはうまくいかず）

# いよいよReactのエラー解消

ここまではReactでエラー出ているけど、そもそもInertia内でうまく行ってないことが原因でした。
通信ができるようになったらあとはReactでのエラーのみです。
シンプルに作ったページでは動くのですが、一部ページでエラーになります。

```
Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object.
    at CircleList (file:///var/www/dojin/bootstrap/ssr/ssr.mjs:208:121)
    at main
    at div
    at main
    at Layout (file:///var/www/dojin/bootstrap/ssr/ssr.mjs:39:21)
    at Index (file:///var/www/dojin/bootstrap/ssr/ssr.mjs:387:84)
    at L (file:///var/www/dojin/node_modules/@inertiajs/react/dist/index.esm.js:1:488)
    at div
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
    at renderElement (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6047:9)
    at renderNodeDestructiveImpl (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6108:11)
    at renderNodeDestructive (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6080:14)
    at renderNode (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6263:12)
    at renderChildrenArray (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6215:7)
    at renderNodeDestructiveImpl (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6145:7)
    at renderNodeDestructive (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6080:14)
    at renderNode (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:6263:12)
    at renderHostElement (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:5646:3)
    at renderElement (/var/www/dojin/node_modules/react-dom/cjs/react-dom-server-legacy.node.development.js:5956:5)
```

## Material-UIのIconの呼び出し方がだめだった

結局なぜだめなのかは分からないが、

```
import ListAltIcon from "@mui/icons-material/ListAlt";

＜ListAltIcon fontSize="small" />
```

の呼び出し方では、何故かエラーになっていました。
エラーになった理由も明確に出たわけではなく、これを外したら動いたという感じです。
下記のように修正すると直りました。

```
import { ListAlt } from "@mui/icons-material";
```

ちなみにビルド時に `@mui/icons-material` を全部見るのか時間がかかるようになりました。