electron-vite

website·Indexed 30 days ago

https://cn-evite.netlify.app

A build tool for Electron applications that leverages Vite's advantages. It provides a fully typed JavaScript API, support for HMR and hot reloading, and features for source code protection using V8 bytecode. The tool includes a CLI for development and production builds, handles dependency optimization, and supports TypeScript and isolated builds.

Tokens
12.4K
Snippets
69
Records
86
Agent score
74%

What's inside electron-vite

  1. Resolve 'cachedDataRejected' errors when using bytecode

    The error Invalid or incompatible cached data (cachedDataRejected) occurs when build.bytecode is enabled but the bytecode cache does not match the target platform and architecture. You must compile the corresponding bytecode cache for the specific target platform.
  2. Protect Electron source code with V8 Bytecode and ASAR Integrity

    To protect Electron applications from reverse engineering, code tampering, and unauthorized redistribution, a combination of V8 Bytecode and ASAR Integrity validation is recommended.

    • ASAR Integrity: Validates the ASAR archive against a build-time hash at runtime. If the hash is missing or mismatched, the app terminates. Requires Electron 16+ (macOS) and Electron 30+ (Windows).
    • V8 Bytecode: Compiles JavaScript source into V8 bytecode caches, making the code significantly harder to reverse engineer while maintaining native performance. In electron-vite, this is implemented via a bytecode compilation plugin and loader that ensures compatibility with the Electron Node.js environment.
  3. Handle cross-architecture V8 bytecode compilation in electron-vite

    When compiling V8 bytecode for a target architecture different from the host machine's architecture, you must explicitly set the ELECTRON_EXEC_PATH environment variable to point to the Electron executable of the target architecture. This ensures the bytecode is generated correctly for the intended platform. This logic can be implemented in a beforeBuild hook to automate the environment setup before running the 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 host architecture
    
        // Only modify ELECTRON_EXEC_PATH if target and host architectures differ
        if (targetArch !== hostArch) {
          // Replace with the actual path to the target architecture's Electron binary
          process.env.ELECTRON_EXEC_PATH = `/path/to/electron-${targetArch}/Electron.app/Contents/MacOS/Electron`
        }
    
        // Execute the electron-vite build command
        execSync('npm run electron-vite build', { stdio: 'inherit' })
      }
    }
  4. Import native Node modules (.node)

    Native Node modules can be imported in two ways:

    1. Direct Import: Use this if the module is guaranteed to be compatible with the current platform and architecture.
    2. Path Import: Use ?asset to get the path, then use require to load it. This is preferred when you need to dynamically select the module based on platform and architecture.
    // Method 1: Direct
    import addon from '../../resources/hello.node'
    console.log(addon?.hello())
    
    // Method 2: Via path (for platform-specific loading)
    import addonPath from '../../resources/hello.node?asset'
    import { createRequire } from 'module'
    const require = createRequire(import.meta.url)
    const native = require(addonPath)
    console.log(native?.hello())
  5. Understand default dependency handling in electron-vite

    electron-vite automatically manages dependencies to keep the final build lightweight. By default, the electron module and all Node.js built-in modules are treated as external dependencies.

    • Main Process and Preload Scripts: Dependencies listed under dependencies in package.json are treated as external and are NOT bundled. They are included later by the application packager (e.g., electron-builder).
    • Renderer Process: Dependencies listed under dependencies in package.json ARE bundled to reduce chunk count and improve performance. It is recommended to install renderer dependencies as devDependencies to reduce the final installation package size.
    • DevDependencies and Phantom Dependencies: Any dependency actually imported or required in the code will be bundled, regardless of whether it is listed in devDependencies or is a 'phantom dependency' (present in node_modules but not explicitly declared in package.json).
  6. Configure Isolated Builds for Preload Scripts (Electron Sandbox)

    To support the Electron sandbox, preload scripts must be output as single products. If you have multiple preload entry points with shared dependencies, you must enable isolatedEntries: true. Additionally, it is recommended to set externalizeDeps: false to ensure a full bundle is created.
    import { defineConfig } from 'electron-vite'
    import { resolve } from 'path'
    
    export default defineConfig({
      preload: {
        build: {
          rollupOptions: {
            input: {
              index: resolve(__dirname, 'src/preload/index.ts'),
              test: resolve(__dirname, 'src/preload/test.ts')
            }
          },
          isolatedEntries: true,
          externalizeDeps: false
        }
      }
    })
  7. Debug electron-vite processes using VSCode

    To debug the main and renderer processes in VSCode, create a .vscode/launch.json file. The main process is launched via electron-vite, while the renderer process is debugged by attaching to the remote debugging port (9222). Use the 'Debug All' compound configuration to start both simultaneously. Note that the renderer process can only be debugged via attachment.
    {
      "version": "0.2.0",
      "configurations": [
        {
          "name": "Debug Main Process",
          "type": "node",
          "request": "launch",
          "cwd": "${workspaceRoot}",
          "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
          "windows": {
            "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
          },
          "runtimeArgs": ["--sourcemap"],
          "env": {
            "REMOTE_DEBUGGING_PORT": "9222"
          }
        },
        {
          "name": "Debug Renderer Process",
          "port": 9222,
          "request": "attach",
          "type": "chrome",
          "webRoot": "${workspaceFolder}/src/renderer",
          "timeout": 60000,
          "presentation": {
            "hidden": true
          }
        }
      ],
      "compounds": [
        {
          "name": "Debug All",
          "configurations": ["Debug Main Process", "Debug Renderer Process"],
          "presentation": {
            "order": 1
          }
        }
      ]
    }
  8. Debug electron-vite processes using WebStorm

    In WebStorm, set up two separate run configurations to debug the application:

    1. Main Process: Create an Npm run configuration with:

      • Command: run
      • Scripts: dev
      • Arguments: -- --sourcemap --remote-debugging-port=9222
    2. Renderer Process: Create an Attach to Node.js/Chrome run configuration with:

      • Host: localhost
      • Port: 9222
  9. Fork Utility Processes or Child Processes

    electron-vite supports forking child processes using the Electron UtilityProcess API or Node.js child_process. The child process script must be imported using the ?modulePath suffix.
    // main.js
    import { utilityProcess, MessageChannelMain } from 'electron'
    import forkPath from './fork?modulePath'
    
    const { port1, port2 } = new MessageChannelMain()
    const child = utilityProcess.fork(forkPath)
    child.postMessage({ message: 'hello' }, [port1])
    
    // fork.js
    process.parentPort.on('message', (e) => {
      const [port] = e.ports
      port.on('message', (e) => console.log(`Message from parent: ${e.data}`))
      port.start()
      port.postMessage('hello')
    })
    
  10. Distribute Electron applications using electron-builder

    Use electron-builder as a complete solution for packaging Electron apps for macOS, Windows, and Linux. This requires an electron-builder.yml configuration file and corresponding scripts in package.json to trigger builds for specific platforms.
    # electron-builder.yml example
    appId: com.electron.app
    productName: vue-ts
    directories:
      buildResources: build
    files:
      - '!**/.vscode/*'
      - '!src/*'
      - '!electron.vite.config.{js,ts,mjs,cjs}'
      - '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
      - '!{.env,.env.*,.npmrc,pnpm-lock.yaml}'
      - '!{tsconfig.json,tsconfig.node.json,tsconfig.web.json}'
    asarUnpack:
      - resources/**
    afterSign: build/notarize.js
    win:
      executableName: vue-ts
    nsis:
      artifactName: ${name}-${version}-setup.${ext}
      shortcutName: ${productName}
      uninstallDisplayName: ${productName}
      createDesktopShortcut: always
    mac:
      entitlementsInherit: build/entitlements.mac.plist
      extendInfo:
        - NSCameraUsageDescription: Application requests access to the device's camera.
        - NSMicrophoneUsageDescription: Application requests access to the device's microphone.
        - NSDocumentsFolderUsageDescription: Application requests access to the user's Documents folder.
        - NSDownloadsFolderUsageDescription: Application requests access to the user's Downloads folder.
    dmg:
      artifactName: ${name}-${version}.${ext}
    linux:
      target:
        - AppImage
        - snap
        - deb
      maintainer: electronjs.org
      category: Utility
    appImage:
      artifactName: ${name}-${version}.${ext}
    npmRebuild: false
    publish:
      provider: generic
      url: https://example.com/auto-updates
    // package.json scripts
    "scripts": {
      "build:win": "npm run build && electron-builder --win --config",
      "build:mac": "npm run build && electron-builder --mac --config",
      "build:linux": "npm run build && electron-builder --linux --config"
    }
  11. Build a production version of an Electron app

    To package an Electron application for distribution, run the electron-vite build command. This prepares the production assets required for the final application bundle.
    npm run build # assuming the script maps to electron-vite build
  12. Import Node.js Worker Threads in electron-vite

    electron-vite allows direct import of Node workers using specific query parameters:

    1. ?modulePath: Returns the module path of the worker. This is the recommended way to create workers.
    2. ?nodeWorker: Returns a custom worker constructor.
    // 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', (msg) => console.log(msg))