如何使用Electron Forge和Vite在Electron应用程序中显示两个窗口

ttcibm8c  于 2023-05-27  发布在  Electron
关注(0)|答案(1)|浏览(449)

我正在使用Electron Forge和Vite构建一个Electron JS应用程序,我想在应用程序中显示第二个窗口,但它没有正确显示。当我运行npm run start时,第二个窗口打开,但它显示的内容与第一个窗口相同。当我运行npm run make时,它仍然打开第二个窗口,但窗口是空的。
我知道有很多文档化的方法可以做到这一点,但大多数使用web包,或者使用没有Vite的Electron Forge。
我已经做了一个电子锻造应用程序,只是添加了第二个窗口。我用下面的方法生成了它。

npm init electron-app@latest electron-forge-2-windows -- --template=vite

我有以下目录结构。

.
├── forge.config.js
├── index.html
├── modalWindow.html
├── package.json
├── src
│   ├── index.css
│   ├── main.js
│   ├── preload.js
│   └── renderer.js
├── vite.main.config.mjs
├── vite.modal_renderer.config.mjs
├── vite.preload.config.mjs
├── vite.renderer.config.mjs
└── yarn.lock

forge.config.js

module.exports = {
  packagerConfig: {},
  rebuildConfig: {},
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {},
    },
    {
      name: '@electron-forge/maker-zip',
      platforms: ['darwin'],
    },
    {
      name: '@electron-forge/maker-deb',
      config: {},
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {},
    },
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-vite',
      config: {
        // `build` can specify multiple entry builds, which can be Main process, Preload scripts, Worker process, etc.
        // If you are familiar with Vite configuration, it will look really familiar.
        build: [
          {
            // `entry` is just an alias for `build.lib.entry` in the corresponding file of `config`.
            entry: 'src/main.js',
            config: 'vite.main.config.mjs',
          },
          {
            entry: 'src/preload.js',
            config: 'vite.preload.config.mjs',
          },
        ],
        renderer: [
          {
            name: 'main_window',
            config: 'vite.renderer.config.mjs',
          },
          {
            name: 'modal_window',
            config: 'vite.modal_renderer.config.mjs',
          },
        ],
      },
    },
  ],
};

src/main.js

const { app, BrowserWindow } = require('electron');
const path = require('path');

if (require('electron-squirrel-startup')) {
  app.quit();
}

const createWindow = () => {
  const mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      preload: path.join(__dirname, 'preload.js'),
    },
  });

  const modalWindow = new BrowserWindow({
    parent: mainWindow,
    modal: true,
    show: false,
    width: 200,
    height: 200,
  });

  if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
    mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
  } else {
    mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`));
  }

  if (MODAL_WINDOW_VITE_DEV_SERVER_URL) {
    modalWindow.loadURL(MODAL_WINDOW_VITE_DEV_SERVER_URL);
  } else {
    modalWindow.loadFile(path.join(__dirname, `../renderer/${MODAL_WINDOW_VITE_NAME}/index.html`));
  }

  modalWindow.show();
};

app.on('ready', createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) {
    createWindow();
  }
});

vite.main.config.mjs

import { defineConfig } from 'vite';

// https://vitejs.dev/config
export default defineConfig({});

vite.renderer.config.mjs

import { defineConfig } from 'vite';

// https://vitejs.dev/config
export default defineConfig({});

vite.modal_renderer.config.mjs

import { defineConfig } from 'vite';
import { resolve } from 'path';

// https://vitejs.dev/config
export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        modal_window: resolve(__dirname, 'modalWindow.html'),
      },
    },
  },
});

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>

  </head>
  <body>
    <h1>💖 Hello World!</h1>
    <p>Welcome to your Electron application.</p>
    <script type="module" src="/src/renderer.js"></script>
  </body>
</html>

modalWindow.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Hello World!</title>

  </head>
  <body>
    <h1>Modal Window</h1>
    <div>Modal</div>
  </body>
</html>

我可以看到在main.js中,MODAL_WINDOW_VITE_DEV_SERVER_URL常量正在解析为http://localhost:5174,这似乎是正确的,但我不明白是什么将这个URL与正确的html文件联系在一起。我猜我在vite.modal_renderer.config.mjs中所做的应该是这样做的,但显然我做错了什么。

qyyhg6bp

qyyhg6bp1#

您的设置的问题是,名为modalWindow.html的文件也将被构建为modalWindow.html,因此您的loadURL/loadFile调用将导致错误的路径被解析。
你可以做两件不同的事情来解决这个问题:

第一个选项

modalWindow.html作为index.html移动到另一个目录,并在vite.modal_window.config.js中将该目录设置为root

mv modalWindow.html modal_window/index.html # directory is of course arbitrary

vite.modal_window.config.js

export default defineConfig({
  root: resolve(__dirname, "modal_window"),
});
第二个选项

您可以配置vite.renderer.config.js来构建这两个文件,然后使用各自的名称配置loadURL/loadFile
vite.renderer.config.js

export default defineConfig({
  build: {
    rollupOptions: {
      input: {
        main_window: resolve(__dirname, "index.html"),
        modal_window: resolve(__dirname, 'modalWindow.html'),
      },
    },
  },
});

main.js

// mainWindow
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
  mainWindow.loadURL(MAIN_WINDOW_VITE_DEV_SERVER_URL);
} else {
  mainWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/index.html`));
}

// modalWindow - both use the same constant now
if (MAIN_WINDOW_VITE_DEV_SERVER_URL) {
  // add file name here ................................. v 
  modalWindow.loadURL(`${MAIN_WINDOW_VITE_DEV_SERVER_URL}/modalWindow.html`); 
} else {
  // change file name here ...................................................... v 
  modalWindow.loadFile(path.join(__dirname, `../renderer/${MAIN_WINDOW_VITE_NAME}/modalWindow.html`));
}

在这两种解决方案中,我强烈推荐第一种(同时也会将主渲染器文件移动到一个单独的目录中),即使它需要更多的目录和配置。
它通过将每个渲染器视为一个独立的构建,而不可能访问渲染器目录之外的URL,从而干净地将构建彼此分离。它还允许为每个渲染器设置不同的配置,因此可以为一个渲染器设置特定的选项,而不会干扰其他渲染器。
解释*_VITE_*常量:
*_VITE_DEV_SERVER_URL设置为从渲染器配置http://localhost:<port>/<base>启动的Vite dev服务器的基URL,其中port是从5173开始的第一个空闲端口,base取自Vite配置(默认为/)。loadURL调用将解析为该URL,并默认为index.html提供服务,因为没有给出特定的文件
*_VITE_NAME设置为forge.config.js中定义的渲染器名称。Forge为每个渲染器设置Vite的build.outDir.vite/renderer/<renderer.name>/,因此由create-electron-app生成的loadFile调用将解析到正确的渲染器目录。
我希望这有助于澄清一些事情。

相关问题