Awesome
vite-electron-plugin
High-performance, esbuild-based Vite Electron plugin
- š High-performance <sub><sup>(Not Bundle, based on esbuild)</sup></sub>
- šÆ Support Plugin <sub><sup>(Like Vite's plugin)</sup></sub>
- š± What you see is what you get
- š„ Hot restart
Quick Setup
- Add dependency to project
npm i -D vite-electron-plugin
- Add
vite-electron-plugin
intovite.config.ts
import electron from 'vite-electron-plugin'
export default {
plugins: [
electron({
include: [
// The Electron source codes directory
'electron',
],
}),
],
}
- Create
electron/main.ts
and type the following code
import { app, BrowserWindow } from 'electron'
app.whenReady().then(() => {
const win = new BrowserWindow()
if (process.env.VITE_DEV_SERVER_URL) {
win.loadURL(process.env.VITE_DEV_SERVER_URL)
} else {
win.loadFile('dist/index.html')
}
})
- Add entry into
package.json
{
+ "main": "dist-electron/main.js"
}
Examples
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
Conventions
- Any file ending with
reload.ext
(e.g.foo.reload.js
,preload.ts
) after an update,
will trigger a reload of the Electron-Renderer process, instead of an entire Electron App restart.
Which is useful when updating Preload-Scripts.
Configuration
electron(config: Configuration)
<table>
<thead>
<th>Key</th>
<th>Type</th>
<th>Description</th>
<th>Required</th>
<th>Default</th>
</thead>
<tbody>
<tr>
<td>include</td>
<td><code>Array</code></td>
<td>
<code>directory</code> or <code>filename</code> or <code>glob</code> Array.<br/>
Must be a relative path, which will be calculated based on the <code>root</code>.<br/>
If it is an absolute path, it can only be a subpath of root.<br/>
Otherwise it will cause the output file path to be calculated incorrectly.<br/>
</td>
<td>ā
</td>
<td></td>
</tr>
<tr>
<td>root</td>
<td><code>string</code></td>
<td></td>
<td></td>
<td><code>process.cwd()</code></td>
</tr>
<tr>
<td>outDir</td>
<td><code>string</code></td>
<td>Output Directory.</td>
<td></td>
<td><code>dist-electron</code></td>
</tr>
<tr>
<td>api</td>
<td><code>Record<string, any></code></td>
<td>Useful if you want to pass some payload to the plugin.</td>
<td></td>
<td></td>
</tr>
<tr>
<td>plugins</td>
<td><code>Plugin[]</code></td>
<td>See the Plugin API.</td>
<td></td>
<td></td>
</tr>
<tr>
<td>logger</td>
<td><code>{ [type: string], (...message: string[]) => void }</code></td>
<td>Custom log. If <code>logger</code> is passed, all logs will be input this option</td>
<td></td>
<td></td>
</tr>
<tr>
<td>transformOptions</td>
<td><code>import('esbuild').TransformOptions</code></td>
<td>Options of <code>esbuild.transform()</code></td>
<td></td>
<td></td>
</tr>
<tr>
<td>watch</td>
<td><code>import('chokidar').WatchOptions</code></td>
<td>Options of <code>chokidar.watch()</code></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Plugin API
The design of plugin is similar to Vite's plugin. But simpler, only 4 hooks in total.
configResolved
- Type:
(config: ResolvedConfig) => void | Promise<void>
- Kind:
async
,sequential
You can freely modify the config
argument in ths hooks or use.
onwatch
<sub><sup>serve only</sup></sub>
- Type:
(envet: 'add' | 'change' | 'addDir' | 'unlink' | 'unlinkDir', path: string) => void
- Kind:
async
,parallel
Triggered by include
file changes. You can emit some files in this hooks. Even restart the Electron App.
transform
- Type:
(args: { filename: string, code: string, done: () => void }) => string | import('esbuild').TransformResult | void | Promise<string | import('esbuild').TransformResult | void>
- Kind:
async
,sequential
Triggered by changes in extensions
files in include.
ondone
- Type:
(args: { filename: string, distname: string }) => void
- Kind:
async
,parallel
Triggered when transform()
ends or a file in extensions
is removed.
Builtin Plugin
import path from 'node:path'
import electron from 'vite-electron-plugin'
import {
alias,
copy,
dest,
esmodule,
customStart,
loadViteEnv,
} from 'vite-electron-plugin/plugin'
export default {
plugins: [
electron({
plugins: [
alias([
// `replacement` is recommented to use absolute path,
// it will be automatically calculated as relative path.
{ find: '@', replacement: path.join(__dirname, 'src') },
]),
copy([
// filename, glob
{ from: 'foo/*.ext', to: 'dest' },
]),
// Dynamic change the build dist path.
dest((_from, to) => to?.replace('dist-electron', 'dist-other')),
customStart(({ startup }) => {
// If you want to control the launch of Electron App yourself.
startup()
}),
// Support use ESM npm-package in Electron-Main.
esmodule({
// e.g. `execa`, `node-fetch`, `got`, etc.
include: ['execa', 'node-fetch', 'got'],
}),
// https://vitejs.dev/guide/env-and-mode.html#env-files
// Support use `import.meta.env.VITE_SOME_KEY` in Electron-Main
loadViteEnv(),
],
}),
],
}
JavaScript API
import {
type Configuration,
type ResolvedConfig,
type Plugin,
build,
watch,
startup,
defineConfig,
default as electron,
} from 'vite-electron-plugin'
Example
// dev
watch({
include: [
// The Electron source codes directory
'electron',
],
plugins: [
{
name: 'plugin-electron-startup',
ondone() {
// Startup Electron App
startup()
},
},
],
})
// build
build({
include: ['electron'],
})