electron-vite

website·Indexed 30 days ago

https://evite.netlify.app/

A Vite-powered build tool for Electron applications. It provides a fully typed JavaScript API, CLI for development and building, and features including HMR, hot reloading, source code protection, and isolated builds. Supports TypeScript and provides guides for dependency handling, asset management, and migration from v4.

Tokens
12.5K
Snippets
76
Records
92
Agent score
75%

What's inside electron-vite

  1. Overview of electron-vite

    electron-vite is a build tool designed to provide a faster and leaner development experience for Electron. It bundles code using Vite while handling Electron's dual environment (Node.js and browser contexts). Key features include a single configuration point for main, renderer, and preload scripts, instant Hot Module Replacement (HMR) for renderer processes, hot reloading for main/preload scripts, multi-threading support, optimized asset handling, isolated build mode for sandboxing, and V8 bytecode compilation for source code protection.
  2. Resolve cachedDataRejected errors with bytecode

    The error Error: Invaild or incompatible cached data (cachedDataRejected) occurs when build.bytecode is enabled but the bytecode cache was not compiled for the specific target platform and architecture of the machine running the app. You must compile the bytecode cache for the target environment to prevent this runtime error.
  3. Build Electron applications for multiple architectures using electron-builder hooks

    When building for multiple architectures in a single process, you must dynamically update the ELECTRON_EXEC_PATH environment variable to match the target architecture. This can be achieved by using the beforeBuild hook in electron-builder to set the correct path to the Electron executable and then invoking the electron-vite build command.
    const { execSync } = require('child_process')
    const os = require('os')
    
    module.exports = {
      async beforeBuild(context) {
        const targetArch = context.arch  // Target architecture
        const hostArch = os.arch()       // Current machine architecture
    
        // Only modify ELECTRON_EXEC_PATH if target architecture differs from host
        if (targetArch !== hostArch) {
          process.env.ELECTRON_EXEC_PATH = `/path/to/electron-${targetArch}/Electron.app/Contents/MacOS/Electron`
        }
    
        // Execute the electron-vite build via npm
        execSync('npm run electron-vite build', { stdio: 'inherit' })
      }
    }
  4. Understand default dependency bundling in electron-vite

    electron-vite applies different bundling rules based on the process and the package.json section:

    • Node.js built-ins & electron module: Always treated as external dependencies.
    • Main process & Preload scripts: Dependencies listed in dependencies are treated as external (not bundled) because they are included during the final app packaging (e.g., via electron-builder).
    • Renderer process: Dependencies listed in dependencies are bundled to reduce chunks and improve performance. It is recommended to install renderer dependencies as devDependencies to keep the final package size smaller.
    • Import-based bundling: Any dependency actually imported or required in the code will be bundled if it is listed in devDependencies or is a "phantom dependency" (present in node_modules but not in package.json).
  5. Cross-compile V8 Bytecode for different architectures

    V8 bytecode caches are bound to specific V8 versions and CPU architectures (x64 vs ARM64). To generate bytecode for a different architecture on the same platform, set the ELECTRON_EXEC_PATH environment variable to the path of the target architecture's Electron executable.
    // electron.vite.config.x64.ts
    import { defineConfig } from 'electron-vite'
    
    export default defineConfig(() => {
      process.env.ELECTRON_EXEC_PATH = '/path/to/electron-x64/Electron.app/Contents/MacOS/Electron'
    
      return {
        // ...
      }
    })

    // Install Electron for a specific architecture via npm: // npm install --arch=ia32 electron

  6. Migrate from bytecodePlugin to build.bytecode in v5

    The bytecodePlugin is deprecated in v5. To enable or customize bytecode generation for source code protection, use the build.bytecode configuration option. This can be set to a boolean (true) or an object for advanced configuration (e.g., specifying protectedStrings).
    import { defineConfig } from 'electron-vite'
    
    export default defineConfig({
      main: {
        build: {
          // Enable bytecode
          bytecode: true 
          // OR customize with options
          // bytecode: { protectedStrings: ['foo'] }
        }
      },
      preload: {
        build: {
          bytecode: true
        }
      }
    })
    
  7. Set up the recommended project structure for electron-vite

    To work with minimal configuration, electron-vite recommends a specific project structure. When this convention is followed, the tool automatically detects the entry points for the main process, preload scripts, and the renderer.
    .
    ├──src
    │  ├──main
    │  │  ├──index.ts
    │  │  └──...
    │  ├──preload
    │  │  ├──index.ts
    │  │  └──...
    │  └──renderer    # with vue, react, etc.
    │     ├──src
    │     ├──index.html
    │     └──...
    ├──electron.vite.config.ts
    ├──package.json
    └──...
  8. Implement Node Worker threads in electron-vite

    Node workers can be imported by appending a specific suffix to the import request.

    1. Use ?modulePath to get the worker bundle path (recommended for standard compliance).
    2. Use ?nodeWorker to get a node worker constructor directly.
    // Using ?modulePath (Recommended)
    import { Worker } from 'node:worker_threads'
    import workerPath from './worker?modulePath'
    new Worker(workerPath, {})
    
    // Using ?nodeWorker
    import createWorker from './worker?nodeWorker'
    createWorker({ workerData: 'worker' })
        .on('message', (message) => console.log(`Message: ${message}`))
        .postMessage('')
  9. Migrate from electron-vite v4 to v5

    When upgrading to electron-vite 5.0, be aware of the following deprecations and configuration changes:

    1. externalizeDepsPlugin is deprecated. Use the build.externalizeDeps configuration option instead. This behavior is now enabled by default in v5.
    2. bytecodePlugin is deprecated. Use the build.bytecode configuration option instead.
  10. Load environment variables in electron-vite config

    electron-vite does not load .env files by default. Use the loadEnv helper within the config function to load variables. By default, only variables prefixed with MAIN_VITE_, PRELOAD_VITE_, and RENDERER_VITE_ are loaded unless the prefixes parameter is modified.
    import { defineConfig, loadEnv } from 'electron-vite'
    
    export default defineConfig(({ command, mode }) => {
      // Load env file based on `mode` in the current working directory
      const env = loadEnv(mode)
      return {
        // electron-vite config
      }
    })
    
  11. Update nested configuration fields to use static objects in v5

    In v5, function-based configuration is no longer supported for nested config fields such as main, preload, or renderer. You must define these as static configuration objects. If conditional logic is required, it must be handled at the top level of the defineConfig function rather than within the nested fields.
    import { defineConfig } from 'electron-vite'
    
    export default defineConfig({
      main: {
        // Static object only
      },
      preload: {
        // Static object only
      },
      renderer: {
        // ❌ DO NOT use defineViteConfig(({ command, mode }) => { ... }) here
        // Use a static object
      }
    })
    
  12. Add TypeScript type definitions for environment variables

    To enable type checking and intellisense for user-defined environment variables in TypeScript, define the ImportMetaEnv interface in an env.d.ts file.
    /// <reference types="vite/client" />
    
    interface ImportMetaEnv {
      readonly MAIN_VITE_SOME_KEY: string
      // more env variables...
    }
    
    interface ImportMeta {
      readonly env: ImportMetaEnv
    }