Electron 🔗 Vite
English | 简体中文
In short, vite-plugin-electron
makes developing Electron apps as easy as normal Vite projects.
- 🔥 Hot Restart (Main process)
- 🔄 Hot Reload (Preload scripts)
- ⚡️ HMR (Renderer process)
- 🚀 Not Bundle, It's fast (Like Vite's Not Bundle)
- 🌱 Fully compatible with Vite and Vite's ecosystem (Based on Vite)
- 🐣 Few APIs, easy to use
- Add the following dependency to your project
npm i -D vite-plugin-electron
- Add
vite-plugin-electron
to theplugins
section ofvite.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: {},
}),
],
}
- 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');
}
})
- Add the
main
entry topackage.json
{
+ "main": "dist-electron/main.mjs"
}
That's it! You can now use Electron in your Vite app ✨
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',
}),
],
}
- Simple API is based on the Flat API
- Simple API incluess some Preload scripts preset configs.
- Flat API provides some more general APIs, which you can use for secondary encapsulation, such as nuxt-electron.
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>
}
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
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 │
┗————————————————————┸——————————┸———————————┛
There are many cases here 👉 electron-vite-samples
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.
ElectronOptions
- typeresolveViteConfig
- function, Resolve the default Vite'sInlineConfig
for build Electron-MainwithExternalBuiltins
- functionbuild
- functionstartup
- function
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()
}
},
}],
},
})
It just executes the electron .
command in the Vite build completion hook and then starts or restarts the Electron App.
- 🚨 By default, the files in
electron
folder will be built into thedist-electron
- 🚨 Currently,
"type": "module"
is not supported in Electron
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 */),
],
},
}),
],
}
Added in: v0.13.0 | Experimental
During the development phase, we can exclude the cjs
format of npm-pkg from bundle. Like Vite's 👉 Not Bundle. It's fast!
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(/* NotBundleOptions */),
],
},
}),
],
}))
API
notBundle(/* NotBundleOptions */)
export interface NotBundleOptions {
filter?: (id: string) => void | false
}
How to work
Let's use the electron-log
as an examples.
┏—————————————————————————————————————┓
│ import log from 'electron-log' │
┗—————————————————————————————————————┛
↓
Modules in `node_modules` are not bundled during development, it's fast!
↓
┏—————————————————————————————————————┓
│ const log = require('electron-log') │
┗—————————————————————————————————————┛