ローカルの Remix (React Router v7) に好きなURLでアクセスする

ローカル環境の Remix または RRv7 アプリに独自ドメインでアクセスできるようにする
またViteのHMR（ホットリロード）も使えるようにする

https://remix.run/

https://reactrouter.com/

以下独自ドメインを `dev-your-domain.com` とする


# 概要
シーケンス図
![seq.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/df061886-2409-443f-955a-e9699d66cace.png)

以下をコンテナ化する
- 🔓 https-portal
  - HTTPSリクエストに対応させる
  - nginxへリクエストを転送する
- 🔄 Nginx
  - リバースプロキシ
  - リクエストをRemix/RRv7に転送する
- 🎨 Remix/RRv7
  - Webアプリケーション
  - 設定次第で他アプリケーションに置換可能

本記事では以下環境を想定する
- ホストOS
  - Windows 10以降
- コンテナ管理
  - Docker Desktop v4以降
https://www.docker.com/ja-jp/products/docker-desktop/

# ディレクトリ構成

```md:ディレクトリ構成
/
├── deployments/
│   ├── nginx/
│   │   ├── Dockerfile
│   │   └── web.conf
│   ├── web/
│   │   └── Dockerfile
│   └── compose.yml
│
└── workspaces/
    ├── (略)
    └── vite.config.ts
```

- 🚀 deployments
  - Dockerコンテナ用の資材を格納するディレクトリ
- 📁 workspaces
  - Webアプリケーション(Remix/RRv7)用の資材を格納するディレクトリ



# Docker資材

```yaml:deployments/compose.yaml
name: local-custom-domain # 任意の名称
services:
  web: # Remix/RRv7
    build:
      context: ./web
      dockerfile: Dockerfile
    ports:
      - 5173:5173 # for Vite
    volumes:
      - ../workspaces:/var/web/workspaces
    tty: true

  nginx:
    build:
      context: ./nginx
      dockerfile: Dockerfile # to copy *.conf 
    volumes:
      - ../:/var/nginx

  https-portal:
    image: steveltn/https-portal:1.25.2
    ports:
      - 80:80 # for http
      - 443:443 # for https
    environment:
      # for HMR
      WEBSOCKET: true 
      # write your custom domain
      DOMAINS: >-
        dev-your-domain.com -> http://nginx
      # for local
      STAGE: 'local'
    volumes:
      - https-portal-data:/var/lib/https-portal

volumes:
    https-portal-data:
    
```

:::note
Compose ファイル・リファレンス — Docker-docs-ja 1.12.RC2 ドキュメント
https://docs.docker.jp/v1.12/compose/compose-file.html
:::


## web
Remix/RRv7用のコンテナ
Dockerfileは以下の通り

```Dockerfile:/deployments/web/Dockerfile
FROM node:23-alpine

RUN apk update && apk add --no-cache xdg-utils

WORKDIR /var/web/workspaces

```

## nginx
Nginx用のコンテナ
Remix/RRv7用confファイルを読み込ませる必要がある
`proxy_set_header` を設定することでnginx経由でもHMRを使えるようにする

```conf:/deployments/nginx/web.conf
server {
    listen 80;
    server_name dev-your-domain.com; # write your custom domain
    root /var/web/workspaces;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $host;
        proxy_set_header X-Forwarded-Server $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_pass http://web:5173;
        
        # WebSocket 用の追加ヘッダー
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_http_version 1.1;
    }

    error_log /var/log/nginx/test_error.log;
    access_log /var/log/nginx/test_access.log;
}

```

:::note
Module ngx_http_proxy_module
https://nginx.org/en/docs/http/ngx_http_proxy_module.html
:::

Dockerfileを通じてconfファイルをnginxコンテナ内に配置する

```Dockerfile:/deployments/nginx/Dockerfile
FROM nginx:1.27.3

COPY web.conf /etc/nginx/conf.d/

```

## https-portal
```yaml:compose.yaml
  https-portal:
    image: steveltn/https-portal:1.25.2
    ports:
      - 80:80
      - 443:443
    environment:
      WEBSOCKET: true 
      DOMAINS: >-
        dev-your-domain.com -> http://nginx
      STAGE: 'local'
```
- `environment.WEBSOCKET`
  - HMRを利用する際は `true` にする
- `environment.DOMAINS` 
  - 独自ドメインをnginxコンテナに転送するように記載する
- `environment.STAGE`
  - ローカル環境での運用につき `'local'` とする

:::note
SteveLTN/https-portal
https://github.com/SteveLTN/https-portal
:::


# ホストOS関連

## hostsファイル

独自ドメインをlocalhostに紐づけるため<b>管理者権限で</b>hostsファイルを編集・保存する

|OS|hostsファイルのディレクトリ|
|---|---|
|Windows|C:\Windows\System32\drivers\etc|
|Mac|/private/etc/|
|Linux|/etc/|

ファイル末尾に以下のように新規行を追加する
```
127.0.0.1 dev-your-domain.com
```


## コンテナ起動

deploymentsディレクトリにて下記コマンドを実行する

```sh
docker compose up -d --build
```




# Remix/RRv7関連

## インストール
Remix/RRv7アプリを用意していなければセットアップする
下記ドキュメントを参考にwebコンテナ内で作業する

::: note
Installation  | React Router
https://reactrouter.com/start/framework/installation

インストール - React Router v7 ドキュメント 日本語版
https://react-router-docs-ja.techtalk.jp/start/framework/installation
:::

npm run devして `localhost:5173` にアクセスできることを確認する

## Vite設定
```ts:workspaces/vite.config.ts
import { reactRouter } from '@react-router/dev/vite';
import { defineConfig, loadEnv } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  const host = env.SERVER_HOST || 'localhost';

  return {
    plugins: [reactRouter(), tsconfigPaths()],
    server: {
      host: true, // ブラウザからアクセスできるようにするために必要
      watch: {
        usePolling: true, // WSL2対策
        interval: 1000, // 負荷対策
      },
      allowedHosts: [host],
    },
  };
});

```
.envファイルから独自ドメイン名を参照する

```env:/workspaces/.env
SERVER_HOST=dev-your-domain.com

```

:::note
サーバーオプション | Vite
https://ja.vite.dev/config/server-options

Docker + Viteな環境でホットリロードが効かない時の対策
https://zenn.dev/hctaw_srp/articles/1f7f67de03d710
:::

:::note warn
ViteのConfigファイルでは `import.meta.env` を通じて環境変数を参照できない
ビルド前に環境変数を参照したい場合には `loadEnv` ヘルパーを利用する

Vite の設定 | Vite
[https://ja.vite.dev/config/#環境変数を設定に使用する ](https://ja.vite.dev/config/#%E7%92%B0%E5%A2%83%E5%A4%89%E6%95%B0%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%AB%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)
:::


# 疎通確認

npm run devでRemix/RRv7アプリを起動する
独自ドメインでアクセスする前に以下を確認しておく
- `localhost:5173` でアクセスできること
- HMRが動作すること

## 独自ドメインでアクセス

ブラウザから独自ドメイン(`dev-your-domain.com`)にアクセスする

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/e1c41b0e-332e-4d39-88cc-a6a104225cc5.png)
Google Chromeの場合上記のような警告画面が表示される
これを解除するため詳細設定ボタンを押下する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/93c4cc75-6829-4626-9590-53de68b98b3b.png)
上記のリンクを押下する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/16181b23-8ad4-44f3-8fbc-0dc62b3bf918.png)
無事表示される


## HMRの確認
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/8d312484-17e1-4740-86c3-3856fea1145a.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/dc3b7984-2b12-45d8-9a29-1a6e18536e29.png)
開発者ツールを開きコンソールタブとネットワークタブの履歴を削除する


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/78af58f3-7f72-4d0c-b37c-4a2f5000e693.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3194558/1db23ada-50f9-443b-a05e-863f6c42cccc.png)
該当ページのファイルを適当に編集し保存するとHMRが作動する