🙆‍♀️

結局inertia.js + react + viteでリモートホストでHMRするにはどうしたらいいのか

2025/01/16に公開

令和ももう7年にもなって、bladeを使っているとしても 今時流石にbladeファイルを書いてF5とか押してる人はいないよな? jsはビルドしないとだからHMRせざるを得ないから頑張ってる人がほとんどだろうけど、

それにしてもリモートに繋いでのHMRする情報が少ない、リモートに繋いで何かコード書いてる人なんてあんまおらんからか...

HMRの設定(ベタな奴)

たとえば接続先が 35.72.31.192 であったら

vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    server: {
        hmr: {
            host: '35.72.31.192', // <-------- ここにベタベタなホスト記入
        }
    },

    plugins: [
        laravel({
            input: 'resources/js/app.jsx',
            refresh: true,
        }),
        react(),
    ],
});

基本、こんな事にしてあげればいい。まあ確かに動くっちゃ動く。
ただし、これはcommitするファイルなのでここにグローバルIPをベタっと書きたくないだろう。

これを評価しているファイル

node_modules/laravel-vite-plugin/dist/index.js 基本的にはこの中で色々やっている。ただし、この中のソースコードを読んでも特殊な環境変数をセットしたからそれが使われるという事は無さそうだ。

駄目なやつ(process.env.VITE_HMR_HOSTとかを取りに行く)

VITE_HMR_HOSTという変数を定義して .env に書いたとしよう。

.env
VITE_HMR_HOST=35.72.31.192

この時以下のようにしてprocess.env.VITE_HMR_HOSTで取れるんじゃないかと思ったりしたが

vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
console.log(process.env.VITE_HMR_HOST); // -> undefinedになる

export default defineConfig({
    server: {
        hmr: {
            host: process.env.VITE_HMR_HOST || 'localhost',
        }
    },

    plugins: [
        laravel({
            input: 'resources/js/app.jsx',
            refresh: true,
        }),
        react(),
    ],
});

vite.config.jsを読む時点では .env は評価されておらず、これは使えない。

まあとりいそぎ環境変数はぶっこまれてるみたいだからnpmする時に環境変数つっこんでやればそれはそれでいいのかもしれんけどやっぱり .env に書きたい。

微妙に駄目なやつ(dotenvを使った事前読み込み)

というか今までこの方法でやっていたりした

vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';
import dotenv from 'dotenv';

// .env ファイルを読み込む
dotenv.config();

console.log('VITE_HMR_HOST:', process.env.VITE_HMR_HOST);

export default defineConfig({
    server: {
        hmr: {
            host: process.env.VITE_HMR_HOST || 'localhost',
        },
    },
    plugins: [
        laravel({
            input: 'resources/js/app.jsx',
            refresh: true,
        }),
        react(),
    ],
});

これを行うと

VITE_HMR_HOST: 35.72.31.192

などとなり、一見よさそうだが

node_modules/laravel-vite-plugin/dist/index.js
function resolveLaravelPlugin(pluginConfig) {
  let viteDevServerUrl;
  let resolvedConfig;
  let userConfig;
  const defaultAliases = {
    "@": "/resources/js"
  };
  return {
    name: "laravel",
    enforce: "post",
    config: (config, { command, mode }) => {
      userConfig = config;
      const ssr = !!userConfig.build?.ssr;
      const env = loadEnv(mode, userConfig.envDir || process.cwd(), "");
      console.log(env); // ここでenvの内容をdumpしてみる

とかすると

  VITE_APP_NAME: '${APP_NAME}',
  VITE_HMR_HOST: '35.72.31.192',

こうなっちゃう。すると


${APP_NAME}がそのまま展開されとる

こんな感じのtitleになってしまい見苦しい。これはおそらくenvの展開が2度行われちゃっているためなんじゃないかなと思う。

// dotenv.config();

とすれば

  VITE_APP_NAME: 'Laravel',
  VITE_HMR_HOST: '35.72.31.192',

このように正しく展開されている。グムム...

今までやってきたこと

if (process.env.NODE_ENV !== 'production') {
    dotenv.config();
}

こんな風にして npm run build の時だけdotenv.config()しないようにとかいう小細工をしてきた、これはこれで流石に辛い

一応の解決: viteのloadEnvを使う

vite.config.js
import { defineConfig, loadEnv } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig(({ mode }) => {
    const env = loadEnv(mode, process.cwd(), '');
    const host = env.VITE_HMR_HOST || (env.APP_URL ? new URL(env.APP_URL).host : 'localhost');

    return {
        server: {
            hmr: {
                host: host,
            },
        },
        plugins: [
            laravel({
                input: 'resources/js/app.jsx',
                refresh: true,
            }),
            react(),
        ],
    };
});

こんな風にviteloadEnvを呼びこんできて、これで評価する。これで何とかなるようだ。

この辺の設定込みのbleeze 初期ツリーをどこかに置こうかな

それでは今回は短い記事で失礼します。Happy web developping!

Discussion