electron-vite / vite-plugin-electron

:electron: Electronโšก๏ธVite core repo
https://github.com/electron-vite
MIT License
703 stars 57 forks source link
electron plugin vite

vite-plugin-electron

Electron ๐Ÿ”— Vite

English | ็ฎ€ไฝ“ไธญๆ–‡


In short, vite-plugin-electron makes developing Electron apps as easy as normal Vite projects.

Features

Quick Setup

  1. Add the following dependency to your project
npm i -D vite-plugin-electron
  1. Add vite-plugin-electron to the plugins section of vite.config.ts
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.rollupOptions.input`
        input: 'electron/preload.ts',
      },
      // Optional: Use Node.js API in the Renderer process
      renderer: {},
    }),
  ],
}
  1. Create the electron/main.ts file and type the following code
import { app, BrowserWindow } from 'electron'

app.whenReady().then(() => {
  const win = new BrowserWindow({
    title: 'Main window',
  })

  // You can use `process.env.VITE_DEV_SERVER_URL` when the vite command is called `serve`
  if (process.env.VITE_DEV_SERVER_URL) {
    win.loadURL(process.env.VITE_DEV_SERVER_URL)
  } else {
    // Load your file
    win.loadFile('dist/index.html');
  }
})
  1. Add the main entry to package.json
{
+ "main": "dist-electron/main.mjs"
}

That's it! You can now use Electron in your Vite app โœจ

Flat API

In most cases, the vite-plugin-electron/simple API is recommended. If you know very well how this plugin works or you want to use vite-plugin-electron API as a secondary encapsulation of low-level API, then the flat API is more suitable for you. It is also simple but more flexible. :)

The difference compared to the simple API is that it does not identify which entry represents preload and the adaptation to preload.

import electron from 'vite-plugin-electron'

export default {
  plugins: [
    electron({
      entry: 'electron/main.ts',
    }),
  ],
}

Flat API vs Simple API

Flat API (Define)

electron(options: ElectronOptions | ElectronOptions[])

export interface ElectronOptions {
  /**
   * Shortcut of `build.lib.entry`
   */
  entry?: import('vite').LibraryOptions['entry']
  vite?: import('vite').InlineConfig
  /**
   * Triggered when Vite is built every time -- `vite serve` command only.
   *
   * If this `onstart` is passed, Electron App will not start automatically.
   * However, you can start Electroo App via `startup` function.
   */
  onstart?: (args: {
    /**
     * Electron App startup function.
     * It will mount the Electron App child-process to `process.electronApp`.
     * @param argv default value `['.', '--no-sandbox']`
     * @param options options for `child_process.spawn`
     * @param customElectronPkg custom electron package name (default: 'electron')
     */
    startup: (argv?: string[], options?: import('node:child_process').SpawnOptions, customElectronPkg?: string) => Promise<void>
    /** Reload Electron-Renderer */
    reload: () => void
  }) => void | Promise<void>
}

Recommend Structure

Let's use the official template-vanilla-ts created based on create vite as an example

+ โ”œโ”€โ”ฌ electron
+ โ”‚ โ””โ”€โ”€ main.ts
  โ”œโ”€โ”ฌ src
  โ”‚ โ”œโ”€โ”€ main.ts
  โ”‚ โ”œโ”€โ”€ style.css
  โ”‚ โ””โ”€โ”€ vite-env.d.ts
  โ”œโ”€โ”€ .gitignore
  โ”œโ”€โ”€ favicon.svg
  โ”œโ”€โ”€ index.html
  โ”œโ”€โ”€ package.json
  โ”œโ”€โ”€ tsconfig.json
+ โ””โ”€โ”€ vite.config.ts

Built format

This is just the default behavior, and you can modify them at any time through custom config in the vite.config.js

{ "type": "module" }
โ”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ณโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ณโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”“
โ”‚       built        โ”‚  format  โ”‚   suffix  โ”‚
โ” โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”จ
โ”‚ main process       โ”‚   esm    โ”‚    .js    โ”‚
โ” โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”จ
โ”‚ preload scripts    โ”‚   cjs    โ”‚   .mjs    โ”‚ diff
โ” โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”จ
โ”‚ renderer process   โ”‚    -     โ”‚    .js    โ”‚
โ”—โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ธโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ธโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”›

{ "type": "commonjs" } - default
โ”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ณโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ณโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”“
โ”‚       built        โ”‚  format  โ”‚   suffix  โ”‚
โ” โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”จ
โ”‚ main process       โ”‚   cjs    โ”‚    .js    โ”‚
โ” โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”จ
โ”‚ preload scripts    โ”‚   cjs    โ”‚    .js    โ”‚ diff
โ” โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ•‚โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”จ
โ”‚ renderer process   โ”‚    -     โ”‚    .js    โ”‚
โ”—โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ธโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”ธโ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ€”โ”›

Examples

There are many cases here ๐Ÿ‘‰ electron-vite-samples

JavaScript API

vite-plugin-electron's JavaScript APIs are fully typed, and it's recommended to use TypeScript or enable JS type checking in VS Code to leverage the intellisense and validation.

Example

import { build, startup } from 'vite-plugin-electron'

const isDev = process.env.NODE_ENV === 'development'
const isProd = process.env.NODE_ENV === 'production'

build({
  entry: 'electron/main.ts',
  vite: {
    mode: process.env.NODE_ENV,
    build: {
      minify: isProd,
      watch: isDev ? {} : null,
    },
    plugins: [{
      name: 'plugin-start-electron',
      closeBundle() {
        if (isDev) {
          // Startup Electron App
          startup()
        }
      },
    }],
  },
})

Hot Reload

Since v0.29.0, when preload scripts are rebuilt, they will send an electron-vite&type=hot-reload event to the main process.
If your App doesn't need a renderer process, this will give you hot-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()
    }
  }
})

How to work

It just executes the electron . command in the Vite build completion hook and then starts or restarts the Electron App.

Be aware

C/C++ Native

We have two ways to use C/C++ native modules

First way

In general, Vite may not correctly build Node.js packages, especially C/C++ native modules, but Vite can load them as external packages

So, put your Node.js package in dependencies. Unless you know how to properly build them with Vite

export default {
  plugins: [
    electron({
      entry: 'electron/main.ts',
      vite: {
        build: {
          rollupOptions: {
            // Here are some C/C++ modules them can't be built properly
            external: [
              'serialport',
              'sqlite3',
            ],
          },
        },
      },
    }),
  ],
}

Second way

Use ๐Ÿ‘‰ vite-plugin-native

import native from 'vite-plugin-native'

export default {
  plugins: [
    electron({
      entry: 'electron/main.ts',
      vite: {
        plugins: [
          native(/* options */),
        ],
      },
    }),
  ],
}