RenderのExress.jsにReactアプリを載せる方法

# はじめに
Reactでちょっとしたものを作って公開しようとしたとき、次にどうする？を書いておきます。
①：Reactでちょっとしたものを作る（詳細は割愛）
②：Express.jsに①のアプリを載せる
③：Renderへのデプロイ


## 簡単に用語の説明
### [Express.js](https://expressjs.com/ja/)
> Node.jsのための高速で、革新的な、最小限のWebフレームワーク（Express.jsのホームページより）

HTTP(S)接続して何かしら返すAPIライブラリです。htmlを返すWebサーバーだけでなく、もちろんAPIとしてもOK。

### [Render](https://render.com/)
Node.jsだけでなく、Python、Docker、Goなど様々な環境をデプロイ・公開する環境。

## 今回作ったもの
3次元の点群CSVを表示するツールです。表面上の機能はJavaScriptでできますが、わざわざNodeとExpressとRenderを使った版。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/592c3663-8fe9-c869-5078-b07484555bbb.png)

[3D-scatter plotter on Render](https://threed-scatter-app.onrender.com/)

なお表面上の機能は、以前公開してます。
このときはHerokuを使って作ったんですが、これは、静的なHTMLをエディタで書いて、それをHerokuへアップロードしただけ。なのでHerokuである必要もなかったです。JavaScriptでこんなんできるよ、という目的でした。
~~そしてHerokuの有料化によって、使えなくなってたけど放置してました。~~

https://qiita.com/yo16/items/1577b913de26366116c4

Nodeで作り直したかった目的は、この散布図ツールじゃなくて別のものを作りたくて、そのまえに基盤部分の技術確認用です。

### 環境
React等、JavaScript周辺の開発スピードがたいへん速く、過去ブログなどが陳腐化していきます。丸パクリしても動かないことはザラなので、ご注意ください。この記事を作った日は、2024年1月19日。主なモジュールのバージョンは下記です。
- Windows10
- node.js: 20.10.0
- react: 18.2.0
- express: 4.18.2

### ソース

https://github.com/yo16/plotly_3d_scatter2


### 最終全体構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/722610/e39b30ca-9ad4-d3e1-65f3-487de9d15fa2.png)
- `scatter-app`：reactのアプリ（手順①の話）
- `server-app`：Expressのプロジェクト（手順②の話）
- `sample_data`はうさぎの点群CSVを入れてるフォルダ。動作には関係なし。


# 構築手順①～③
## ① Reactでメイン機能を作る
冒頭に書いた「Reactでちょっとしたものを作って」の部分です。なのでここは深く書きませんが、`create-react-app`でアプリを作って、`npm start`で起動したら、`http://localhost:3000`でアクセスできるものです。ここまではできてる前提。ヒントとなるサイト等もいっぱいありますね。
今回は、Plotlyを使って、3次元のCSVから散布図を描くアプリです。

`npm run build`して、buildフォルダを生成しておきます。
②以降で、これをExpressというhttpサービスに載せます。


## ②Express.jsの環境
### ②-1. Expressプロジェクトを作る
手元のNode環境に、`express-generator`をインストールします。`-g`でなくてもいいかもですが、`server-app`というプロジェクトを作るためだけに、トップにnode環境を作るのがなんとなく嫌だったので、`-g`してます。
```shell
# グローバル環境にexpress-generatorをインストール
npm install -g express-generator
```

次にexpressプロジェクトを作ります。そうすると、`server-app`という名前のフォルダができて、必要なもろもろが入ります。`server-app`という名前は変更可能です。
```shell
# expressプロジェクトを作る
express server-app
```

最後に、`server-app`に作られた`package.json`を元に、使用するライブラリ群をインストールします。
```shell
# ライブラリをインストール
cd server-app
npm install
```

ここで試しに、`npm start`とやって、`http://localhost:3000` からアクセスできる＝正しくインストールできたことを確認しておきます。ちなみに、`http://localhost:3000/users`もひな形があって、アクセスできます。それ以外URLは、Page Not Foundになります。
止めるときは、Ctrl+C。

### ②-2. usersのページを削除
`/server-app/app.js`内に、usersへアクセスするためのコードが２か所あるので、消しておきます。
```JavaScript:app.js
～ 略 ～
//var usersRouter = require('./routes/users');
～ 略 ～
//app.use('/users', usersRouter);
～ 略 ～
```

`/server-app/routes/users.js`を削除しておきます。読み込まれないし、いらないので。

この結果、`http://localhost:3000/users`へアクセスできなくなります。


### ②-3. ReactアプリをExpress環境へコピー
①でbuildフォルダができていると思うので、その下にあるファイルとフォルダ群をまとめて全部コピーします。
次に、`server-app/public`以下へ全部貼り付けます。

この結果、`http://localhost:3000`へアクセスすると、①のReactで`npm run start`で見ていた画面が現れます。
- 参考：[React+Expressで本番環境へデプロイ #JavaScript - Qiita](https://qiita.com/creaporta/items/aedc6f7510cfb5f6352e)


作ったものをgithubへプッシュして、開発は以上です。③ではデプロイ。

## ③Renderへデプロイ
### ③-1. Renderのアカウント作成（割愛）
[Render](https://render.com/)

### ③-2. Web Serviceの作成
`Build and deploy from a Git repository` で、githubへのアクセスを許可して作成します。
②でプッシュしたリポジトリを選択します。
迷いそうなパラメータは下記。

| 項目名 | 値 | 備考 |
|---|---|---|
| Root Directory | server-app | ②で作ったExpressのプロジェクト名 |
| Runtime | Node | |
| Build Command | yarn |自動的に、左端に`server-app/`が入る |
| Start Command | npm start |自動的に、左端に`server-app/`が入る |
| Instance Type | Free | 無料枠 |
| Environ Variables | DEBUG=server-app:* | |

設定項目は、[Deploy a Node Express App | Render Docs](https://docs.render.com/deploy-node-express-app) にさらっと書いてあります。
環境変数のDEBUGのところは、Expressのドキュメントの[Express のアプリケーション生成プログラム](https://expressjs.com/ja/starter/generator.html)を参考にしてます。
無料枠は、15分間アクセスがないと停止しちゃいます。おそらくDockerが停止している。そこから起動するのに、体感で30秒くらいかかったので、サービスを提供するとしたらありえないくらい遅いです。（とある記事で8秒と書いてあったのに。）
でも私は今のところは無料枠でやってます。

正しく動くと、URLが発行されてアクセスできます。

# まとめ
今回デプロイした3D散布図は、buildフォルダを丸っと持ってきて動いたけど、これはどんな場合でも通用するんだろうか。フロントエンドエンジニアの独学新人なので、まだあまりわかりません。
でも、未知かつ古い情報まみれの森を開拓しながら、とりあえずデプロイまで行きついたので、ここで一区切り。間違いやもっといい方法等あったら是非コメントください！