Search code examples
javascriptelectronsveltesvelte-3sveltekit

How to make multiple Svelte windows in Electron?


For my electron app, I would like to open another Svelte-window (or load different windows/components depending on the startup variables).

So let's say I used this tutorial to set up a basic structure, with my App.svelte looking like this:

<script>
    const openLauncher = () => {
        window.api.openWindow("launcher");
    };
</script>

<button on:click={openLauncher}>Open Launcher</button>

As you can see, I added an IPC function to open a new window. The corresponding index.js:

const { app, BrowserWindow, ipcMain } = require("electron");
const { join } = require("path");

app.on("ready", () => {
    const mainWindow = new BrowserWindow({
        webPreferences: {
            preload: join(__dirname, "./preload.js"),
        }
    });
    mainWindow.loadFile(join(__dirname, "../public/index.html"));
});

ipcMain.on("openLauncher", (event, args) => {
    const launcher = new BrowserWindow({
        webPreferences: {
            preload: join(__dirname, "./preload.js"),
        }
    });
    launcher.loadFile(join(__dirname, "../public/launcher.html"));
});

preload.js:

const { contextBridge, ipcRenderer } = require("electron");

const API = {
    openWindow: (obj) => ipcRenderer.send("openLauncher", obj),
}

contextBridge.exposeInMainWorld("api", API);

This does work and opens a new window with the launcher.html, but I can't figure out how to get the Svelte components working in that new file.

One idea I had was modifying main.js file so that the body component changes, like so:

import App from './App.svelte';
import LauncherApp from './LauncherApp.svelte';

const bodyID = document.getElementsByTagName('body')[0].id;

const app = {};
if (bodyID == "index") {
    app = new App({
        target: document.body,
    });
}
else if (bodyID == "launcher") {
    app = new LauncherApp({
        target: document.body,
    });
}
export default app;

This works for the main window (i.e. if I switch the IDs, it loads the correct component at startup) but since it doesn't load any Svelte whe opening the new window, this doesn't work.

So I would really appreciate any ideas on how to get Svelte to load for new/different windows/html-files! And if there is a way to do this with SvelteKit, even better!

Thank you in advance!


Solution

  • The obvious quick fix I see is using an #if block on bodyID in App.svelte containing two components, MainApp (content of App.svelte) and LauncherApp, and then simply changing bodyID depending on in which mode you are.

    When using sveltekit I think it would make sense to treat LauncherApp as a separate route (I believe this is the only way to have "separated" pages with sveltekit, though I am not 100%). So when opening a new window you navigate the new instance of your application to the LauncherApp route. If you don't want the same base layout as in the main app, you can add a __layout.reset.svelte file.

    I don't know why your solution didn't work, it was quite elegant.