🍥

最新のNuxtでnuxt-electronの無限リロードを回避する

はじめに

nuxt-electronには、v0.7.0にて「Devモードで起動した場合に無限リロードが発生する」というバグが混入しています。
回避策のひとつとしてNuxtのバージョンをv3.6.5までダウングレードするというものがありますが、最新のNuxtでも利用できるよう、暫定的に対応する方法を提案します。
既にこの不具合に対応したPRが存在するため、node_modulesを直接編集しこの変更を直接取り込むことで対応します。

https://zenn.dev/comm_vue_nuxt/articles/0c4725404b040e

※不具合の解消が確認できましたらその旨を追記する予定です。

不具合の詳細

件の不具合はnuxt-electronのIssuesに起票されています。

https://github.com/caoxiemeihao/nuxt-electron/issues/74

Issuesの内容を要約します。

  • Nuxtアプリケーションにnuxt-electronを追加すると、ElectronブラウザのNuxtが常に再起動し続け、ターミナルとブラウザコンソールに大量のエラーが表示される
  • nuxt-electronのフック内で起動ポートがランダムポートになってしまっており、これが無限ループに陥る原因である

また、起動オプションに--no-forkを追加することも提案されていますが、別のエラーが発生し、動作が不安定でした。

対応する

node_modules/nuxt-electron/dist/index.mjs, index.cjsを以下のように編集します。
以下のdiffはindex.mjsのものです。index.cjsにも対応する箇所(全く同じコード)があるため、同様に編集してください。

index.mjs
import { defineNuxtModule } from "@nuxt/kit";
import { startup, build } from "vite-plugin-electron";
let options;
let nuxt;
let viteConfigResolve;
const viteConfigPromise = new Promise((resolve) => viteConfigResolve = resolve);
let viteServerResolve;
const viteServerPromise = new Promise((resolve) => viteServerResolve = resolve);
const index = defineNuxtModule({
  meta: {
    name: "nuxt-electron",
    configKey: "electron",
    compatibility: {
      nuxt: ">=3.0.0"
    }
  },
  hooks: {
    async "vite:extendConfig"(viteInlineConfig) {
      viteInlineConfig.plugins ?? (viteInlineConfig.plugins = []);
      viteInlineConfig.plugins.push({
        name: "get-vite-config",
        configResolved(config) {
          viteConfigResolve(config);
        }
      });
      if (options.renderer) {
        viteInlineConfig.plugins.push((await import("vite-plugin-electron-renderer")).default(options.renderer));
      }
    },
    "vite:serverCreated"(server) {
      viteServerResolve(server);
    },
    // For development
    listen(server, listener) {
-     (async function _listen() {
+     async function _listen() {
        var _a, _b, _c, _d;
        const addressInfo = server.address();
        Object.assign(process.env, {
          // This is required, and it is used in Electron-Main.
          VITE_DEV_SERVER_URL: `http://localhost:${addressInfo.port}`
        });
        for (const config of options.build) {
          config.vite ?? (config.vite = {});
          (_a = config.vite).mode ?? (_a.mode = (await viteConfigPromise).mode);
          (_b = config.vite).build ?? (_b.build = {});
          (_c = config.vite.build).watch ?? (_c.watch = {});
          (_d = config.vite).plugins ?? (_d.plugins = []);
          config.vite.plugins.push({
            name: "nuxt-electron:startup",
            closeBundle() {
              if (config.onstart) {
                config.onstart.call(this, {
                  startup,
                  reload() {
                    viteServerPromise.then((server2) => server2.ws.send({ type: "full-reload" }));
                  }
                });
              } else {
                startup();
              }
            }
          });
          build(config);
        }
-     })();
+     }
+     // Setup a 5 seconds delay to avoid error 404 or 500.
+     setTimeout(
+       () => {
+         _listen();
+       },
+       5000
+     );
    },
    // For build
    async "build:done"() {
      var _a;
      if (!nuxt.options.dev) {
        for (const config of options.build) {
          config.vite ?? (config.vite = {});
          (_a = config.vite).mode ?? (_a.mode = (await viteConfigPromise).mode);
          await build(config);
        }
      }
    },
    "build:manifest"(manifest) {
      for (const key in manifest) {
        manifest[key].dynamicImports = [];
      }
    }
  },
  async setup(_options, _nuxt) {
    options = _options;
    nuxt = _nuxt;
    adaptElectronConfig(options, nuxt);
  }
});
function adaptElectronConfig(options2, nuxt2) {
  var _a, _b, _c;
  if (!options2.disableDefaultOptions) {
    nuxt2.options.ssr = false;
-   nuxt2.options.app.baseURL = "./";
    nuxt2.options.app.buildAssetsDir = "/";
    nuxt2.options.runtimeConfig.app.baseURL = "./";
    nuxt2.options.runtimeConfig.app.buildAssetsDir = "/";
    if (!nuxt2.options.dev) {
      (_a = nuxt2.options.nitro).runtimeConfig ?? (_a.runtimeConfig = {});
      (_b = nuxt2.options.nitro.runtimeConfig).app ?? (_b.app = {});
      nuxt2.options.nitro.runtimeConfig.app.baseURL = "./";
    }
    (_c = nuxt2.options.router.options).hashMode ?? (_c.hashMode = true);
  }
}
export {
  index as default
};

動作確認

npm run dev

正しく変更ができている場合、Devモードで正常に起動します。

Vue・Nuxt 情報が集まる広場 / Plaza for Vue・Nuxt.

Discussion