【Netlify + Heroku】Socket.IO アプリのデプロイ

 

Socket.IO クライアント-サーバ間の双方向通信ができる JS ライブラリ
公式サイト
で作成した通信対戦アプリをデプロイするときに結構苦労したので、その記録を書いておきます。

当該のアプリはこちらです。

Geister Online


アプリの構造

Socket.IO を使用して、クライアント-サーバ間で通信をするアプリです。

コードは TypeScript で書き、Webpack を使って、

クライアントのコードはpublic/bundle.jsとして、サーバのコードはdist/main.jsとしてコンパイルしています。

public配下の HTML のscriptタグからbundle.jsを読み込み、

ローカルではnode dist/main.jsをターミナルから入力することでサーバのコードを動かしていました。

ディレクトリ構成は、このようになっていました。

# 静的ファイル
public/
    # css、画像、音声など
    - static/
    - bundle.js
    - index.html
# サーバのコードがコンパイルされたやつ
dist/
    - main.js
# クライアントのコード
src/
# サーバのコード
server.ts
package.json
tsconfig.json
webpack.config.js
...

デプロイ方法

public配下の静的ファイルは Netlifydist配下のサーバのファイルは Heroku で動かしています。

以下の図のように、クライアントサイドは Netlify、サーバサイドは Heroku っていう感じです。

デプロイの構造

おそらく Netlify は静的専用なので、動的なことはできないんだと思います。

この動画を参考にしながらデプロイを進めていきました。


しかし、ここでいくつか問題が発生してしまいました。


問題点

Heroku でビルドできない

Heroku でビルドできなかったので、デプロイログを見ると、package.jsonがないとのこと。

Heroku のプロジェクトパスにはdistを指定しているのですが、その中にはmain.jsしかないからです。

仕方ないのでルートにあったpackage.jsondistに移動すると、ビルドできるようになりました。

こんなところにあっていいんだろうか…
みーこ

Heroku で Application error

heroku logs --tailすると、code=H10 desc=App crashed status=503なエラー。

ログを遡ると、npm startでこけてるっぽい。

実はpackage.jsonの中身はこうなっていました。

package.json
1
2
3
4
5
6
7
{
    ...
    "scripts": {
        "start": "npx webpack && node dist/main.js"
    },
    ...
}

このファイルのパスをさきほど変えたので、この部分のパスも変えなくてはなりません。

webpack.config.jsをこのdistディレクトリに入れてもいいかもしれないですが、

このファイルはクライアントのコードもコンパイルしているし、いろいろ面倒そうなので、

ローカルでnpx webpackして、npm startにはnode main.jsだけ載せることにしました。

package.json
1
2
3
4
5
6
7
{
    ...
    "scripts": {
        "start": "node main.js"
    },
    ...
}

これで Heroku 側の 503 エラーはなくなりました。

いまだに Heroku の URL には Not Found と表示されますが、本体は Netlify 側の URL なので問題ないと思います。

コードの変更があるとデプロイのたびにローカルでいちいちコンパイルしないといけないのがつらいけど、仕方ないか
みーこ

ブラウザで CORS エラー

これが一番煩わしかったです。

ブラウザで Netlify の URL にアクセスして、デベロッパーツールのコンソールを開くと、

このエラーが表示されました。

セキュリティ的な意味で、ドメインが違うサイト間で通信するには明示が必要だということです。

さて、困ったのはどこにそれを書けばいいのかわからないということでした。

クライアント側か?サーバ側か?


クライアント側だとすれば、Netlify のnetlify.toml_headersファイルで HTTP ヘッダを指定することができます。

ところがこれを追加してもうまくいかず…

ということはサーバ側かと思って、Express.js の CORS について調べていろいろ書いてみるも、うまくいかず…

先の動画でもそのコードでも何か特別なことをしているようには見えなかったし、八方塞がりでありました。


ところが、ふと「Socket.IO CORS」で調べると、

なんとバージョンが変わってからは明示的な CORS 設定が必要とか言うじゃないですか。

Handling CORS | Socket.IO

そんなところに原因があるとは思わなかったよ…
みーこ

Netlify の設定ファイルも Express の CORS のコードも必要なく、これだけでヘッダを認識するようになりました。


それで、origin として設定する URL は Netlify の URL にすべきだったのですが、

Heroku の URL にするものだと勘違いしていたため、またもエラー

よく考えれば Socket.IO の CORS 設定のコード(サーバのコード)は Heroku 側だし、

Heroku 側が Netlify 側をブロックしてるんだから、Netlify の URL を書くべきだったんですね。


これでエラーもきれいになくなり、期待通りに動くようになりました。


お役に立てれば幸いです。

では👋