vite-plugin-electron

repository·main·Indexed 21 days ago

https://github.com/electron-vite/vite-plugin-electron

A Vite plugin that integrates the Electron lifecycle into the Vite build process. It provides a Simple API for quick setup with presets for main and preload processes, a flexible Flat API for low-level configuration, and an Environment API via vite-plugin-electron/multi-env for complex multi-target builds. Features include hot reloading for preload scripts, dynamic target resolution via electronPluginFactory, and tools to externalize dependencies using notBundle.

Tokens
14.9K
Snippets
47
Records
61
Agent score
72%

What's inside vite-plugin-electron

  1. Understand Preload Script Compatibility Matrix

    main

    When using Electron, the compatibility of import vs require in preload scripts depends on your webPreferences configuration. In most cases, using cjs (CommonJS) format for preload scripts is recommended to ensure maximum compatibility across different sandbox and node integration settings.

    Refer to the following matrix to determine if import or require will work based on your webPreferences:

    webPreferencesimportrequire
    nodeIntegration: false (default)
    nodeIntegration: true
    sandbox: true (default)
    sandbox: false
    nodeIntegration: false + sandbox: true
    nodeIntegration: false + sandbox: false
    nodeIntegration: true + sandbox: true
    nodeIntegration: true + sandbox: false

    Note: indicates a SyntaxError or ReferenceError.

  2. Manage dependencies correctly to avoid double bundling

    main

    To prevent code from being bundled twice (once by Vite/Rolldown and once by electron-builder), follow these placement rules for your package.json dependencies:

    TypeExampledependenciesdevDependencies
    Node.js C/C++ Native Modulesserialport, sqlite3
    Node.js CJS Packageselectron-store
    Node.js ESM Packagesexeca, got, node-fetch
    Web PackagesVue, React

    Key Takeaway: Native modules should be in dependencies so electron-builder can collect their binaries. Other buildable modules (CJS/ESM) should be in devDependencies to avoid being bundled by Vite and then re-processed by electron-builder.

  3. Compare Flat API vs Simple API

    main

    The plugin offers two primary ways to configure Electron targets:

    Simple API (vite-plugin-electron/simple)

    • Recommended for most users.
    • Includes preset configurations specifically for preload scripts.
    • Uses a grouped object structure (main, preload, renderer).

    Flat API (vite-plugin-electron)

    • More flexible/low-level.
    • Best if you are building a secondary encapsulation (e.g., a framework plugin like nuxt-electron).
    • Does not automatically identify which entry is a preload script; you must manage the adaptation yourself.
    • Uses an array of options where each entry is treated as a target.
  4. Understand the default build formats

    main

    The plugin produces different output formats and file extensions based on the type field in your package.json. This ensures compatibility between the Electron main process, preload scripts, and the renderer process.

    • If package.json has { "type": "module" } (ESM):

      • Main process: esm format, .js suffix.
      • Preload scripts: cjs format, .mjs suffix.
      • Renderer process: .js suffix.
    • If package.json has { "type": "commonjs" } (Default):

      • Main process: cjs format, .js suffix.
      • Preload scripts: cjs format, .js suffix.
      • Renderer process: .js suffix.
  5. Compare Simple API vs Flat API

    main

    The plugin provides two main ways to configure Electron targets:

    • Simple API (vite-plugin-electron/simple): Recommended for most users. It includes presets for main and preload scripts, automatically identifying and configuring preload scripts.
    • Flat API (vite-plugin-electron): A lower-level, more flexible API. It does not automatically recognize preload scripts or apply preload-specific presets. It is ideal if you are building a wrapper (like nuxt-electron) or need custom logic.

    Note on Vite versions: The plugin automatically adapts build configurations. It uses rolldownOptions for Vite 8+ and rollupOptions for Vite < 8.

    // Flat API Example
    import electron from 'vite-plugin-electron'
    
    export default {
      plugins: [
        electron({
          entry: 'electron/main.ts',
        }),
      ],
    }
  6. Prevent automatic Electron startup

    main

    To prevent Electron from starting automatically (e.g., to wait for other local services), you can use one of the following methods. You can then manually trigger startup by calling startup() after setting the control to false.

    • Set startup.prevent = true in your code.
    • Set the environment variable ELECTRON_STARTUP_PREVENT=1 or ELECTRON_STARTUP_PREVENT=true.

    Await the return value of startup() to determine if the startup was actually triggered or prevented.

  7. Use the `notBundle` plugin for faster development

    main

    Starting from v0.13.0-beta.0, you can use the notBundle plugin to prevent modules in node_modules from being bundled during development. This significantly speeds up the development cycle by allowing modules to be loaded via require (CommonJS) instead of being bundled into a single file.

    Note: Since v0.13.0-beta.2, notBundle must be imported explicitly from vite-plugin-electron/plugin.

    import electron from 'vite-plugin-electron'
    import { notBundle } from 'vite-plugin-electron/plugin'
    
    export default defineConfig(({ command }) => ({
      plugins: [
        electron({
          entry: 'electron/main.ts',
          vite: {
            plugins: [command === 'serve' && notBundle()],
          },
        }),
      ],
    }))
  8. Configure multiple targets with Environment API

    main

    For vite-plugin-electron@>=1.0.0, you can use the Environment API to build multiple Electron targets (like main, preload, and custom workers) using Vite's Environment API. This is the recommended way for complex multi-target builds.

    Using electronSimple (Multi-env)

    electronSimple groups configurations by environment name. main and preload use default presets, while other keys are treated as custom targets built like the main process.

    Using electron (Flat Multi-env)

    Pass an array of options to the base electron plugin to define multiple inputs manually.

    Using electronPluginFactory

    If you need to resolve targets dynamically (e.g., based on package.json content), use the factory function.

    import { electronSimple } from 'vite-plugin-electron/multi-env'
    
    export default {
      plugins: [
        electronSimple({
          main: {
            input: 'electron/main.ts',
            notBundle: true, // Externalize npm dependencies in dev
            options: {
              define: { __ELECTRON_TARGET__: JSON.stringify('main') },
            },
          },
          preload: {
            input: 'electron/preload.ts',
            options: {
              define: { __ELECTRON_TARGET__: JSON.stringify('preload') },
            },
          },
          custom: {
            input: 'electron/custom.ts',
            options: {
              define: { __ELECTRON_TARGET__: JSON.stringify('custom') },
            },
          },
        }),
      ],
    }
  9. Configure multi-target builds with Environment API

    main

    For complex projects requiring multiple Electron targets (e.g., main, preload, and custom worker processes), use the Environment API via vite-plugin-electron/multi-env. This is the future-facing way to handle builds.

    Using electronSimple (Grouped API)

    electronSimple accepts an object grouped by environment name. main and preload keys use default presets, while custom keys are built like main-process targets.

    import { electronSimple } from 'vite-plugin-electron/multi-env'
    
    export default {
      plugins: [
        electronSimple({
          main: {
            input: 'electron/main.ts',
            bundleDeps: {
              dev: { include: ['some-cjs-dependency'] },
              build: { exclude: ['electron-updater'] },
            },
            options: {
              define: { __ELECTRON_TARGET__: JSON.stringify('main') },
            },
          },
          preload: {
            input: 'electron/preload.ts',
            options: {
              define: { __ELECTRON_TARGET__: JSON.stringify('preload') },
            },
          },
          custom: {
            input: 'electron/custom.ts',
            options: {
              define: { __ELECTRON_TARGET__: JSON.stringify('custom') },
            },
          },
        }),
      ],
    }

    Using Flat API (Array of Options)

    import electron from 'vite-plugin-electron/multi-env'
    
    export default {
      plugins: [
        electron([
          { input: 'electron/main.ts' },
          { input: 'electron/preload.ts' },
        ]),
      ],
    }
  10. Quick Setup with vite-plugin-electron/simple

    main

    To quickly integrate Electron into a Vite project, follow these steps:

    1. Install the dependency:

      npm i -D vite-plugin-electron
    2. Configure vite.config.ts using the simple API. This API provides presets for main and preload processes:

      import electron from 'vite-plugin-electron/simple'
      
      export default {
        plugins: [
          electron({
            main: {
              // Shortcut of `build.lib.entry`
              entry: 'electron/main.ts',
            },
            preload: {
              // Shortcut of `build.rolldownOptions.input` (or `build.rollupOptions.input` on Vite < 8)
              input: 'electron/preload.ts',
            },
            // Optional: Use Node.js API in the Renderer process
            renderer: {},
          }),
        ],
      }
    3. Implement the Main process (electron/main.ts). Use process.env.VITE_DEV_SERVER_URL to load the app during development:

      import { app, BrowserWindow } from 'electron'
      
      app.whenReady().then(() => {
        const win = new BrowserWindow({ title: 'Main window' })
      
        if (process.env.VITE_DEV_SERVER_URL) {
          win.loadURL(process.env.VITE_DEV_SERVER_URL)
        } else {
          win.loadFile('dist/index.html')
        }
      })
    4. Update package.json to point to the built main process file:

      {
        "main": "dist-electron/main.js"
      }
    npm i -D vite-plugin-electron
  11. Enable Hot Reload for Main Process (v0.29.0+)

    main

    Since version v0.29.0, when preload scripts are rebuilt, they emit an electron-vite&type=hot-reload event to the main process. If your application does not require a renderer process (e.g., a pure main-process app), you can implement hot-reloading by listening for this message and reloading the windows.

    To enable this, add a message listener to your main process entry point that reloads all open windows when the specific event is received.

    // electron/main.ts
    
    process.on('message', (msg) => {
      if (msg === 'electron-vite&type=hot-reload') {
        for (const win of BrowserWindow.getAllWindows()) {
          // Hot reload preload scripts
          win.webContents.reload()
        }
      }
    })
  12. Implement Hot Reload for Preload Scripts

    main

    When a preload script is rebuilt, the plugin sends an electron-vite&type=hot-reload message to the main process. You can listen for this event in your main process to trigger a reload of all renderer windows, enabling hot-reloading of preload logic without restarting the whole app.

    // electron/main.ts
    import { app, BrowserWindow } from 'electron'
    
    process.on('message', (msg) => {
      if (msg === 'electron-vite&type=hot-reload') {
        for (const win of BrowserWindow.getAllWindows()) {
          // Hot reload preload scripts by reloading the webContents
          win.webContents.reload()
        }
      }
    })
    // electron/main.ts
    
    process.on('message', (msg) => {
      if (msg === 'electron-vite&type=hot-reload') {
        for (const win of BrowserWindow.getAllWindows()) {
          // Hot reload preload scripts
          win.webContents.reload()
        }
      }
    })