English | 中文
Many thanks to caoxiemeihao's vite-plugin-electron and Doubleshotjs's doubleshot These two excellent libraries inspired me. I hope to use it to simplify development configuration and focus only on business development.
- Fast build
mainandpreloadwith vite - Little configuration, focus on business
- Support
main'sHot Restart - Support
preload'sHot Reload - Support
esmandcjs, you can useesmin electron v28+ - Support
vueandreactand other frameworks supported byvite - Optional electron-builder Simple configuration
# pnpm
pnpm add @tomjs/vite-plugin-electron -D
# yarn
yarn add @tomjs/vite-plugin-electron -D
# npm
npm i @tomjs/vite-plugin-electron --save-devIf you use builder to package your application, please install electron-builder
# pnpm
pnpm add electron-builder -D
# yarn
yarn add electron-builder -D
# npm
npm i electron-builder --save-dev- Recommend
electronand pagesrccode directory structure
|--electron
| |--main // main process code
| | |--index.ts
| |--preload // preload process code
| | |--index.ts
| |--build // electron-builder resources for electron package
| | |--icons
|--src // front-end code
| |--App.vue
| |--main.ts
- Zero configuration, default dist output directory
|--dist
| |--main
| | |--index.js
| | |--index.js.map
| |--preload
| | |--index.js
| | |--index.js.map
| |--renderer
| | |--index.html
See PluginOptions and recommended parameter descriptions in detail
electron/main/index.ts
import { join } from 'node:path';
import { ELECTRON_EXIT } from '@tomjs/vite-plugin-electron/electron';
import { app, BrowserWindow } from 'electron';
// `__dirname` and `__filename` are provided automatically for `esm` output.
const preload = join(__dirname, '../preload/index.mjs');
const url = process.env.VITE_DEV_SERVER_URL;
async function createWindow() {
win = new BrowserWindow({
title: 'Main window',
width: 800,
height: 700,
webPreferences: {
preload,
nodeIntegration: true,
contextIsolation: false,
},
});
if (isDev) {
win.loadURL(url);
}
else {
win.loadFile(indexHtml);
}
}
app.whenReady().then(createWindow);
process.on('message', (data) => {
// When restarting the electron, if devTools is turned on, the electron may not be able to shut down normally.
if (data === ELECTRON_EXIT) {
if (win) {
win.webContents.closeDevTools();
}
}
});Take using esm as an example, but it requires Electron>=28
package.json
Electron preload process must use the .mjs suffix, otherwise an error will be reported, see official documentation. So the default output of esm of preload uses the .mjs suffix. For consistency, main process also ends with .mjs
{
"type": "module",
"main": "dist/main/index.mjs"
}vite.config.ts
// import renderer from 'vite-plugin-electron-renderer'; // Enable nodeIntegration
import electron from '@tomjs/vite-plugin-electron';
import vue from '@vitejs/plugin-vue';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
vue(),
// If you use the agreed directory structure, no configuration is required
electron(),
// If the directory structure is customized, the value must be assigned according to the actual situation
// electron({
// main: {
// entry: 'electron/main/index.ts',
// },
// preload: {
// entry: 'electron/preload/index.ts',
// },
// }),
// renderer(),
],
});Take using cjs as an example
package.json
{
// "type": "commonjs",
"main": "dist/main/index.js"
}vite.config.ts
import electron from '@tomjs/vite-plugin-electron';
import react from '@vitejs/plugin-react-swc';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [react(), electron()],
});- index.d.mts provided by unpkg.com.
| Property | Type | Default | Description |
|---|---|---|---|
| recommended | boolean |
true |
This option is intended to provide recommended default parameters and behavior. |
| external | string[] |
Don't bundle these modules. Node.js built-ins and electron are always excluded. |
|
| main | MainOptions | Configuration options for the electron main process. | |
| preload | PreloadOptions | Configuration options for the electron preload process. | |
| debug | boolean |
false |
Electron debug mode, don't startup electron. You can also use process.env.VITE_ELECTRON_DEBUG. Default is false. |
| builder | boolean | BuilderOptions |
false |
If it is a boolean type, whether to enable electron-builder. If it is an object, it is the configuration of electron-builder. You can also turn it on using process.env.VITE_ELECTRON_DEBUG. |
| inspect | boolean |
false |
Electron will listen for V8 inspector protocol messages on the specified port, an external debugger will need to connect on this port. You can also use process.env.VITE_ELECTRON_INSPECT. See debugging-main-process for more information. |
| devtools | boolean | number |
false |
If true, depending on whether the react plugin exists, inject <script src="http://localhost:8097"></script> code for react-devtools; depending on whether the vue plugin exists, inject <script src="http://localhost:8097"></script> for vue-devtools debugging; if number, it is a custom port. |
Notice
The recommended option is used to set the default configuration and behavior, which can be used with almost zero configuration. The default is true. If you want to customize the configuration, set it to false. The following default prerequisites are to use the recommended project structure.
- Check whether
electron/main/index.tsandelectron/main/index.tsexist, and if so, assign values tomain.entryandpreload.entryrespectively. If it does not exist,main.entrymust be actively assigned, and an error will be reported. - The output directory is based on the
build.outDirparameter ofvite, and outputselectron/main,electron/preloadandsrctodist/main,dist/preloadanddist/rendererrespectively. - Other behaviors to be implemented
Based on UserConfig of vite, some default values are added for ease of use.
| Property | Type | Default | Description |
|---|---|---|---|
| entry | string | string[] | Record |
- |
The main process entry file. When recommended: true, defaults to electron/main/index.ts if it exists. |
| format | 'cjs' | 'esm' |
- |
The bundle format. If not specified, it will use the "type" field from package.json. |
| outDir | string |
"dist/main" (recommended) / "dist-electron/main" | The output directory for the main process files |
| target | string | false |
'node18.18' (esm) / 'node16' (cjs) |
The Node.js build target, passed to Vite's build.target. |
| sourcemap | boolean | 'inline' | 'hidden' |
true (dev) / false (prod) |
Whether to generate sourcemaps. |
| minify | boolean | 'oxc' | 'terser' | 'esbuild' |
false (dev) / true (prod) |
Minify the output. |
| clean | boolean |
true |
Empty the output directory before building. |
| treeshake | boolean |
true (dev) / false (prod) |
Enable/disable tree-shaking. |
| external | string[] |
[] |
Don't bundle these modules. Node.js built-ins and electron are always excluded. |
| watchFiles | string | string[] |
undefined |
Additional files or folders to watch. Note: Vite always watches the module dependency graph, so this is only needed for files outside the graph. |
| ignoreWatch | Arrayable<string | RegExp> |
'.history', '.temp', '.tmp', '.cache', 'dist' |
Ignore files or folders being watched |
| onSuccess | string | function |
undefined |
A shell command or callback to run after every successful build (dev mode). |
Any other top-level Vite UserConfig option (resolve, define, plugins, ...) can also be passed directly.
Based on UserConfig of vite, some default values are added for ease of use.
| Property | Type | Default | Description |
|---|---|---|---|
| entry | string | string[] | Record |
- |
The preload process entry file. When recommended: true, defaults to electron/preload/index.ts if it exists. |
| format | 'cjs' | 'esm' |
- |
The bundle format. If not specified, it will use the "type" field from package.json. |
| outDir | string |
"dist/preload" (recommended) / "dist-electron/preload" | The output directory for the preload process files |
| target | string | false |
'node18.18' (esm) / 'node16' (cjs) |
The Node.js build target, passed to Vite's build.target. |
| sourcemap | boolean | 'inline' | 'hidden' |
true (dev) / false (prod) |
Whether to generate sourcemaps. |
| minify | boolean | 'oxc' | 'terser' | 'esbuild' |
false (dev) / true (prod) |
Minify the output. |
| clean | boolean |
true |
Empty the output directory before building. |
| treeshake | boolean |
true (dev) / false (prod) |
Enable/disable tree-shaking. |
| external | string[] |
[] |
Don't bundle these modules. Node.js built-ins and electron are always excluded. |
| watchFiles | string | string[] |
undefined |
Additional files or folders to watch. Note: Vite always watches the module dependency graph, so this is only needed for files outside the graph. |
| ignoreWatch | Arrayable<string | RegExp> |
'.history', '.temp', '.tmp', '.cache', 'dist' |
Ignore files or folders being watched |
| onSuccess | string | function |
undefined |
A shell command or callback to run after every successful build (dev mode). |
Any other top-level Vite UserConfig option (resolve, define, plugins, ...) can also be passed directly.
When recommended and builder.enable are both true, use electron-builder to package Electron applications.
- In the
build.outDirdirectory configured in vite, generate a new package.json based on the configuration and package.json, excluding non-dependencies. - Execute
npm installand then package.
Reference vite-plugin-electron-renderer and Two package.json Structure
Not suitable for everyone.
To use this function, you need to install additional electron-builder
| Property | Type | Default | Description |
|---|---|---|---|
| appId | string |
"com.electron.${name}" |
The application id. See More |
| productName | string |
"com.electron.${name}" |
product name.See More |
| builderConfig | Configuration | undefined |
electron-builder's Configuration |
The default configuration is as follows:
const config = {
directories: {
buildResources: 'electron/build',
app: path.dirname(resolvedConfig.build.outDir),
output: 'release/${version}',
},
files: ['main', 'preload', 'renderer'],
artifactName: '${productName}-${version}-${os}-${arch}.${ext}',
electronDownload: {
// when npm registry mirror is 'registry.npmmirror.com'
mirror: 'https://npmmirror.com/mirrors/electron',
},
electronLanguages: ['zh-CN', 'en-US'],
win: {
target: [
{
target: 'nsis',
arch: ['x64'],
},
],
},
mac: {
target: ['dmg'],
},
linux: {
target: ['zip'],
},
nsis: {
oneClick: false,
perMachine: false,
allowToChangeInstallationDirectory: true,
deleteAppDataOnUninstall: false,
},
};- Default values for
mainandpreloadwhen the relevant parameters are not configured
| Parameter | Development Mode Default | Production Mode Default |
|---|---|---|
| sourcemap | true |
false |
| minify | false |
true |
| Variable | Description |
|---|---|
VITE_ELECTRON_DEBUG |
Electron main process debug, don't startup electron. When value is true or 1 to enable, false or 0 to disable.Default is undefined. |
VITE_ELECTRON_INSPECT |
Electron will listen for V8 inspector protocol messages on the specified port, an external debugger will need to connect on this port. When value is true, the default port is 5858. |
VITE_ELECTRON_BUILDER |
Enable electron-builder to package. When value is true or 1 to enable, false or 0 to disable. Default is undefined. |
Electron main process and renderer process use.
| Variable | Description |
|---|---|
VITE_DEV_SERVER_URL |
The url of the dev server. |
Use @tomjs/electron-devtools-installer to install the Chrome Devtools plugins and use it like web development
import { app } from 'electron';
app.whenReady().then(() => {
const { installExtension, REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } = await import(
'@tomjs/electron-devtools-installer'
);
installExtension([REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS])
.then((exts) => {
// Install the extension before enabling the developer tools; otherwise, the extension may fail to load.
// win.webContents.openDevTools();
console.log(
'Added Extension: ',
exts.map(s => s.name),
);
})
.catch((err) => {
console.log('Failed to install extensions');
console.error(err);
});
});Run Debug Main Process through vscode to debug the main thread. For debugging tools, refer to Official Documentation
launch.json is configured as follows:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"preLaunchTask": "npm:debug",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": ["."],
"outFiles": [
"${workspaceFolder}/**/*.js",
"${workspaceFolder}/**/*.cjs",
"${workspaceFolder}/**/*.mjs",
"!**/node_modules/**"
],
"envFile": "${workspaceFolder}/node_modules/@tomjs/vite-plugin-electron/debug/.env"
}
]
}tasks.json is configured as follows:
{
"version": "2.0.0",
"tasks": [
{
"label": "npm:debug",
"type": "npm",
"script": "debug",
"detail": "cross-env VITE_ELECTRON_DEBUG=1 vite",
"isBackground": true,
"problemMatcher": {
"owner": "typescript",
"fileLocation": "relative",
"pattern": {
"regexp": "^([a-zA-Z]\\:/?([\\w\\-]/?)+\\.\\w+):(\\d+):(\\d+): (ERROR|WARNING)\\: (.*)$",
"file": 1,
"line": 3,
"column": 4,
"code": 5,
"message": 6
},
"background": {
"activeOnStart": true,
"beginsPattern": "^.*VITE v.* ready in \\d* ms.*$",
"endsPattern": "^.*\\[tomjs:electron\\] startup electron*$"
}
}
}
]
}Use DevTools to debug the preload process.
First execute the following command to install dependencies and generate library files:
pnpm install
pnpm buildOpen the examples directory, there are vue and react examples.
Breaking Updates:
- Requires Vite
^8.0.0(themain/preloadprocesses are now compiled with Vite itself using Rolldown, instead oftsdown). MainOptions/PreloadOptionsare now based on Vite's UserConfig instead of tsdown's options. Any top-level Vite option (resolve,define,plugins, ...) can be passed directly.- The module dependency graph of
main/preloadis always watched in dev mode;watchFilesis only needed for files outside the graph. __dirname/__filenameare now injected automatically foresmoutput (like the previousshimsbehavior), so you can keep using__dirnamein the main process without any manual setup.
Breaking Updates:
- Using tsdown instead of tsup, the main/preload configuration is changed to inherit tsdown.
- If
recommended:trueis not used,watchFilesneeds to be configured. See MainOptions and PreloadOptions for details.