vue-cli-plugin-electron-haunv 1.0.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,250 @@
1
+ # vite-plugin-electron-builder
2
+
3
+ > Easily Build Your Vue 3 + Vite App For Desktop With Electron
4
+
5
+ [![Node CI](https://github.com/your-username/vite-plugin-electron-builder/actions/workflows/nodeCI.yml/badge.svg)](https://github.com/your-username/vite-plugin-electron-builder/actions/workflows/nodeCI.yml)
6
+ [![npm version](https://img.shields.io/npm/v/vite-plugin-electron-builder.svg)](https://www.npmjs.com/package/vite-plugin-electron-builder)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](./LICENSE)
8
+
9
+ A modern replacement for `vue-cli-plugin-electron-builder`, built on top of **Vite 8**, **Electron 41**, and **electron-builder 26**. All dependencies are kept at their latest versions.
10
+
11
+ ---
12
+
13
+ ## ✨ Features
14
+
15
+ - ⚡ **Vite-native** — instant HMR for the renderer process
16
+ - 🔄 **Auto-restart** — watches your main process files and restarts Electron on change
17
+ - 🔒 **Secure by default** — custom `app://` protocol with path traversal protection, context isolation enabled
18
+ - 🛠 **esbuild** — fast TypeScript/ESM compilation for the main process
19
+ - 🎭 **Playwright** — built-in E2E test helper for Electron windows
20
+ - 📦 **electron-builder** — full packaging for Linux, macOS, and Windows
21
+ - 🖥 **CLI** — scaffold a new project with one command
22
+
23
+ ---
24
+
25
+ ## Quick Start
26
+
27
+ ### Scaffold a new project
28
+
29
+ ```bash
30
+ npx vite-plugin-electron-builder my-app
31
+ cd my-app
32
+ npm run electron:serve
33
+ ```
34
+
35
+ ### Add to an existing Vite + Vue project
36
+
37
+ ```bash
38
+ npm install -D vite-plugin-electron-builder electron electron-builder esbuild
39
+ ```
40
+
41
+ Then update your `vite.config.js`:
42
+
43
+ ```js
44
+ import { defineConfig } from 'vite'
45
+ import vue from '@vitejs/plugin-vue'
46
+ import { createElectronPlugin } from 'vite-plugin-electron-builder'
47
+
48
+ export default defineConfig({
49
+ plugins: [
50
+ vue(),
51
+ createElectronPlugin({
52
+ mainProcessFile: 'src/background.js',
53
+ outputDir: 'dist_electron',
54
+ }),
55
+ ],
56
+ })
57
+ ```
58
+
59
+ Add scripts to your `package.json`:
60
+
61
+ ```json
62
+ {
63
+ "scripts": {
64
+ "electron:serve": "vite-electron serve",
65
+ "electron:build": "vite build && vite-electron build"
66
+ }
67
+ }
68
+ ```
69
+
70
+ ---
71
+
72
+ ## Project Structure
73
+
74
+ After scaffolding, your project will look like this:
75
+
76
+ ```
77
+ my-app/
78
+ ├── src/
79
+ │ ├── App.vue # Vue renderer component
80
+ │ ├── main.js # Renderer entry point
81
+ │ ├── background.js # Electron main process ← edit this
82
+ │ └── preload.js # Preload script (contextBridge)
83
+ ├── tests/
84
+ │ └── e2e/
85
+ │ └── app.spec.js # Playwright E2E tests
86
+ ├── index.html
87
+ ├── vite.config.js
88
+ └── package.json
89
+ ```
90
+
91
+ ---
92
+
93
+ ## Plugin Options
94
+
95
+ ```ts
96
+ interface ElectronBuilderOptions {
97
+ /** Electron main process entry file. Default: 'src/background.js' */
98
+ mainProcessFile?: string
99
+
100
+ /** Output dir for compiled main process. Default: 'dist_electron' */
101
+ outputDir?: string
102
+
103
+ /** Preload script path. Optional. */
104
+ preload?: string
105
+
106
+ /** Enable Node integration in renderer. Default: false */
107
+ nodeIntegration?: boolean
108
+
109
+ /** Enable context isolation. Default: true */
110
+ contextIsolation?: boolean
111
+
112
+ /** Custom protocol scheme name. Default: 'app' */
113
+ customFileProtocol?: string
114
+
115
+ /** Extra Electron CLI flags for development. */
116
+ electronCliArgs?: string[]
117
+
118
+ /** electron-builder config overrides. */
119
+ builderOptions?: import('electron-builder').Configuration
120
+
121
+ /** Native modules to externalize from the bundle. */
122
+ externals?: string[]
123
+ }
124
+ ```
125
+
126
+ ---
127
+
128
+ ## Development
129
+
130
+ ### Commands
131
+
132
+ | Command | Description |
133
+ |---|---|
134
+ | `npm run electron:serve` | Start Vite dev server + Electron |
135
+ | `npm run electron:build` | Build renderer + package with electron-builder |
136
+ | `npm test` | Run Jest unit tests |
137
+ | `npm run test:e2e` | Run Playwright E2E tests |
138
+ | `npm run lint` | ESLint |
139
+
140
+ ### How it works
141
+
142
+ **Development (`electron:serve`)**
143
+
144
+ 1. Vite starts its dev server (default `:8080`)
145
+ 2. The plugin compiles `src/background.js` with esbuild → `dist_electron/main.js`
146
+ 3. Electron is launched pointing at the Vite dev server URL
147
+ 4. chokidar watches `src/background.js` (and preload) — on change, recompiles and restarts Electron
148
+
149
+ **Production (`electron:build`)**
150
+
151
+ 1. Vite builds the renderer to `dist/`
152
+ 2. esbuild compiles and bundles the main process to `dist_electron/main.js`
153
+ 3. electron-builder packages everything into a distributable (`.dmg`, `.exe`, `.AppImage`, etc.)
154
+
155
+ ---
156
+
157
+ ## Security
158
+
159
+ This plugin follows Electron security best practices:
160
+
161
+ - **Context isolation** is enabled by default (`contextIsolation: true`)
162
+ - **Node integration** is disabled by default in the renderer
163
+ - The custom `app://` protocol prevents path traversal attacks
164
+ - The preload template uses `contextBridge` to expose only whitelisted APIs
165
+
166
+ ---
167
+
168
+ ## API Reference
169
+
170
+ ### `createElectronPlugin(options?)`
171
+
172
+ Returns a Vite plugin. Add it to the `plugins` array in `vite.config.js`.
173
+
174
+ ### `createProtocol(scheme, basePath?)`
175
+
176
+ Registers a secure Electron file protocol. Import in your main process:
177
+
178
+ ```js
179
+ import { createProtocol } from 'vite-plugin-electron-builder/lib/protocol'
180
+
181
+ app.whenReady().then(() => {
182
+ createProtocol('app')
183
+ win.loadURL('app://./index.html')
184
+ })
185
+ ```
186
+
187
+ ### `testWithPlaywright(options?)`
188
+
189
+ Launches Electron with Playwright for E2E tests:
190
+
191
+ ```js
192
+ import { testWithPlaywright } from 'vite-plugin-electron-builder'
193
+
194
+ let app, page, stop
195
+
196
+ beforeAll(async () => {
197
+ ;({ app, page, stop } = await testWithPlaywright({
198
+ appPath: 'dist_electron/main.js',
199
+ }))
200
+ })
201
+
202
+ afterAll(() => stop())
203
+
204
+ test('renders app', async () => {
205
+ const el = await page.$('#app')
206
+ expect(el).not.toBeNull()
207
+ })
208
+ ```
209
+
210
+ ---
211
+
212
+ ## Package Versions
213
+
214
+ All dependencies are pinned to their latest major versions:
215
+
216
+ | Package | Version |
217
+ |---|---|
218
+ | `electron` | ^41.0.2 |
219
+ | `electron-builder` | ^26.8.1 |
220
+ | `vite` | ^8.0.0 |
221
+ | `@vitejs/plugin-vue` | ^6.0.5 |
222
+ | `esbuild` | ^0.27.4 |
223
+ | `@playwright/test` | ^1.58.2 |
224
+ | `chalk` | ^5.6.2 |
225
+ | `chokidar` | ^5.0.0 |
226
+ | `commander` | ^14.0.3 |
227
+ | `execa` | ^9.6.1 |
228
+ | `fs-extra` | ^11.3.4 |
229
+ | `semver` | ^7.7.4 |
230
+ | `concurrently` | ^9.2.1 |
231
+ | `wait-on` | ^9.0.4 |
232
+
233
+ ---
234
+
235
+ ## Migrating from vue-cli-plugin-electron-builder
236
+
237
+ | vue-cli-plugin | vite-plugin-electron-builder |
238
+ |---|---|
239
+ | `vue add electron-builder` | `npx vite-plugin-electron-builder my-app` |
240
+ | `vue-cli-service electron:serve` | `vite-electron serve` |
241
+ | `vue-cli-service electron:build` | `vite-electron build` |
242
+ | `vue.config.js` plugin options | `vite.config.js` `createElectronPlugin({})` |
243
+ | `background.js` | `src/background.js` (unchanged) |
244
+ | `createProtocol` | `import { createProtocol } from 'vite-plugin-electron-builder/lib/protocol'` |
245
+
246
+ ---
247
+
248
+ ## License
249
+
250
+ MIT
package/bin/cli.js ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict'
4
+
5
+ const { program } = require('commander')
6
+ const path = require('path')
7
+ const chalk = require('chalk')
8
+ const pkg = require('../package.json')
9
+
10
+ program
11
+ .name('vite-electron')
12
+ .description('Vite Plugin Electron Builder CLI')
13
+ .version(pkg.version)
14
+
15
+ program
16
+ .command('serve')
17
+ .description('Start the Electron development server')
18
+ .option('--main <file>', 'Path to main process file', 'src/background.js')
19
+ .option('--out <dir>', 'Output directory', 'dist_electron')
20
+ .action(async (opts) => {
21
+ const { createServer } = require('vite')
22
+ const { serveElectron } = require('../lib/build')
23
+
24
+ console.log(chalk.cyan('\n🚀 Starting Vite + Electron dev server...\n'))
25
+
26
+ try {
27
+ // Start Vite dev server
28
+ const viteServer = await createServer({
29
+ base: './',
30
+ server: { port: 8080 }
31
+ })
32
+ await viteServer.listen()
33
+ viteServer.printUrls()
34
+
35
+ // Start Electron in watch mode
36
+ const { stop } = await serveElectron({
37
+ mainProcessFile: opts.main,
38
+ outputDir: opts.out
39
+ })
40
+
41
+ // Handle graceful shutdown
42
+ const shutdown = async () => {
43
+ console.log(chalk.yellow('\n[electron-builder] Shutting down...'))
44
+ await stop()
45
+ await viteServer.close()
46
+ process.exit(0)
47
+ }
48
+
49
+ process.on('SIGINT', shutdown)
50
+ process.on('SIGTERM', shutdown)
51
+ } catch (err) {
52
+ console.error(chalk.red('[electron-builder] Serve failed:'), err)
53
+ process.exit(1)
54
+ }
55
+ })
56
+
57
+ program
58
+ .command('build')
59
+ .description('Build the app for production')
60
+ .option('--main <file>', 'Path to main process file', 'src/background.js')
61
+ .option('--out <dir>', 'Output directory', 'dist_electron')
62
+ .option('--platform <platform>', 'Target platform (linux|mac|win)')
63
+ .action(async (opts) => {
64
+ const { buildElectron } = require('../lib/build')
65
+
66
+ console.log(chalk.cyan('\n📦 Building for production...\n'))
67
+
68
+ try {
69
+ await buildElectron({
70
+ mainProcessFile: opts.main,
71
+ outputDir: opts.out,
72
+ builderOptions: opts.platform
73
+ ? { [opts.platform]: {} }
74
+ : {}
75
+ })
76
+ } catch (err) {
77
+ console.error(chalk.red('[electron-builder] Build failed:'), err)
78
+ process.exit(1)
79
+ }
80
+ })
81
+
82
+ program.parse(process.argv)
83
+
84
+ // Show help if no command given
85
+ if (!process.argv.slice(2).length) {
86
+ program.outputHelp()
87
+ }
@@ -0,0 +1,15 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <!-- Required for Electron security -->
7
+ <meta http-equiv="Content-Security-Policy"
8
+ content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline';" />
9
+ <title>Vue 3 + Vite + Electron</title>
10
+ </head>
11
+ <body>
12
+ <div id="app"></div>
13
+ <script type="module" src="/src/main.js"></script>
14
+ </body>
15
+ </html>
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "my-electron-vue-app",
3
+ "version": "0.1.0",
4
+ "description": "A Vue 3 + Vite + Electron desktop application",
5
+ "main": "dist_electron/main.js",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "vite build",
9
+ "electron:serve": "vite-electron serve",
10
+ "electron:build": "vite build && vite-electron build"
11
+ },
12
+ "keywords": [],
13
+ "author": "",
14
+ "license": "MIT",
15
+ "engines": {
16
+ "node": ">=18.0.0"
17
+ },
18
+ "dependencies": {
19
+ "vue": "^3.5.13"
20
+ },
21
+ "devDependencies": {
22
+ "@vitejs/plugin-vue": "^6.0.5",
23
+ "electron": "^41.0.2",
24
+ "electron-devtools-installer": "^4.0.0",
25
+ "vite": "^8.0.0",
26
+ "vite-plugin-electron-builder": "^1.0.0"
27
+ }
28
+ }
@@ -0,0 +1,125 @@
1
+ <template>
2
+ <div id="app">
3
+ <header class="app-header">
4
+ <img src="./assets/logo.svg" alt="Vue + Electron" class="logo" />
5
+ <h1>Vue 3 + Vite + Electron</h1>
6
+ </header>
7
+
8
+ <main class="app-main">
9
+ <p class="tagline">
10
+ Edit <code>src/App.vue</code> and save to see hot-reload in action.
11
+ </p>
12
+
13
+ <div class="info-cards">
14
+ <div class="card">
15
+ <h2>⚡ Vite</h2>
16
+ <p>Lightning-fast HMR during development.</p>
17
+ </div>
18
+ <div class="card">
19
+ <h2>🖥 Electron</h2>
20
+ <p>Cross-platform desktop apps with web tech.</p>
21
+ </div>
22
+ <div class="card">
23
+ <h2>💚 Vue 3</h2>
24
+ <p>Composition API, TypeScript, and more.</p>
25
+ </div>
26
+ </div>
27
+
28
+ <p class="version">Electron API available: {{ hasElectronAPI ? '✅' : '❌' }}</p>
29
+ </main>
30
+ </div>
31
+ </template>
32
+
33
+ <script setup>
34
+ import { ref, onMounted } from 'vue'
35
+
36
+ const hasElectronAPI = ref(false)
37
+
38
+ onMounted(() => {
39
+ hasElectronAPI.value = typeof window.electronAPI !== 'undefined'
40
+ })
41
+ </script>
42
+
43
+ <style>
44
+ * { box-sizing: border-box; margin: 0; padding: 0; }
45
+
46
+ body {
47
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
48
+ background: #0d1117;
49
+ color: #c9d1d9;
50
+ min-height: 100vh;
51
+ }
52
+
53
+ #app {
54
+ display: flex;
55
+ flex-direction: column;
56
+ align-items: center;
57
+ padding: 40px 20px;
58
+ gap: 32px;
59
+ }
60
+
61
+ .app-header {
62
+ display: flex;
63
+ flex-direction: column;
64
+ align-items: center;
65
+ gap: 16px;
66
+ }
67
+
68
+ .logo { width: 80px; height: 80px; }
69
+
70
+ h1 {
71
+ font-size: 2rem;
72
+ font-weight: 700;
73
+ background: linear-gradient(135deg, #42b883, #35495e);
74
+ -webkit-background-clip: text;
75
+ -webkit-text-fill-color: transparent;
76
+ }
77
+
78
+ .tagline {
79
+ font-size: 1.1rem;
80
+ color: #8b949e;
81
+ text-align: center;
82
+ margin-bottom: 24px;
83
+ }
84
+
85
+ .tagline code {
86
+ background: #161b22;
87
+ padding: 2px 8px;
88
+ border-radius: 4px;
89
+ font-family: monospace;
90
+ color: #58a6ff;
91
+ }
92
+
93
+ .info-cards {
94
+ display: grid;
95
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
96
+ gap: 20px;
97
+ width: 100%;
98
+ max-width: 700px;
99
+ }
100
+
101
+ .card {
102
+ background: #161b22;
103
+ border: 1px solid #30363d;
104
+ border-radius: 12px;
105
+ padding: 24px;
106
+ text-align: center;
107
+ }
108
+
109
+ .card h2 { font-size: 1.3rem; margin-bottom: 8px; }
110
+ .card p { color: #8b949e; font-size: 0.95rem; }
111
+
112
+ .version {
113
+ margin-top: 16px;
114
+ font-size: 0.9rem;
115
+ color: #8b949e;
116
+ }
117
+
118
+ .app-main {
119
+ display: flex;
120
+ flex-direction: column;
121
+ align-items: center;
122
+ width: 100%;
123
+ max-width: 800px;
124
+ }
125
+ </style>
@@ -0,0 +1,88 @@
1
+ 'use strict'
2
+
3
+ import { app, protocol, BrowserWindow } from 'electron'
4
+ import { createProtocol } from 'vite-plugin-electron-builder/lib/protocol'
5
+ import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'
6
+ import path from 'path'
7
+
8
+ const isDevelopment = process.env.NODE_ENV !== 'production'
9
+
10
+ // Register the custom protocol before app is ready (required for security)
11
+ protocol.registerSchemesAsPrivileged([
12
+ {
13
+ scheme: 'app',
14
+ privileges: {
15
+ secure: true,
16
+ standard: true
17
+ }
18
+ }
19
+ ])
20
+
21
+ let win
22
+
23
+ async function createWindow() {
24
+ win = new BrowserWindow({
25
+ width: 800,
26
+ height: 600,
27
+ webPreferences: {
28
+ // NOTE: Do NOT enable nodeIntegration in production for security
29
+ nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION === 'true',
30
+ contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
31
+ preload: path.join(__dirname, 'preload.js') // optional
32
+ }
33
+ })
34
+
35
+ if (isDevelopment) {
36
+ // Load from Vite dev server
37
+ await win.loadURL(process.env.VITE_DEV_SERVER_URL || 'http://localhost:8080')
38
+ win.webContents.openDevTools()
39
+ } else {
40
+ // Use custom protocol for production
41
+ createProtocol('app')
42
+ await win.loadURL('app://./index.html')
43
+ }
44
+
45
+ win.on('closed', () => {
46
+ win = null
47
+ })
48
+ }
49
+
50
+ // Install Vue Devtools in development
51
+ app.whenReady().then(async () => {
52
+ if (isDevelopment && !process.env.IS_TEST) {
53
+ try {
54
+ await installExtension(VUEJS_DEVTOOLS)
55
+ } catch (e) {
56
+ console.error('Vue Devtools failed to install:', e.toString())
57
+ }
58
+ }
59
+ await createWindow()
60
+ })
61
+
62
+ // Quit when all windows are closed (except on macOS)
63
+ app.on('window-all-closed', () => {
64
+ if (process.platform !== 'darwin') {
65
+ app.quit()
66
+ }
67
+ })
68
+
69
+ app.on('activate', () => {
70
+ if (win === null) {
71
+ createWindow()
72
+ }
73
+ })
74
+
75
+ // Exit cleanly in development mode
76
+ if (isDevelopment) {
77
+ if (process.platform === 'win32') {
78
+ process.on('message', (data) => {
79
+ if (data === 'graceful-exit') {
80
+ app.quit()
81
+ }
82
+ })
83
+ } else {
84
+ process.on('SIGTERM', () => {
85
+ app.quit()
86
+ })
87
+ }
88
+ }
@@ -0,0 +1,4 @@
1
+ import { createApp } from 'vue'
2
+ import App from './App.vue'
3
+
4
+ createApp(App).mount('#app')
@@ -0,0 +1,31 @@
1
+ 'use strict'
2
+
3
+ /**
4
+ * Preload script - runs in a privileged context before the renderer.
5
+ * Use contextBridge to safely expose APIs to the renderer.
6
+ *
7
+ * Docs: https://www.electronjs.org/docs/latest/tutorial/context-isolation
8
+ */
9
+ const { contextBridge, ipcRenderer } = require('electron')
10
+
11
+ // Expose a safe API to the renderer process via window.electronAPI
12
+ contextBridge.exposeInMainWorld('electronAPI', {
13
+ // Example: send a message to the main process
14
+ sendMessage: (channel, data) => {
15
+ const allowedChannels = ['app:minimize', 'app:maximize', 'app:close', 'app:ready']
16
+ if (allowedChannels.includes(channel)) {
17
+ ipcRenderer.send(channel, data)
18
+ }
19
+ },
20
+
21
+ // Example: receive a message from the main process
22
+ onMessage: (channel, callback) => {
23
+ const allowedChannels = ['app:update-available', 'app:update-downloaded']
24
+ if (allowedChannels.includes(channel)) {
25
+ ipcRenderer.on(channel, (_event, ...args) => callback(...args))
26
+ }
27
+ },
28
+
29
+ // Expose app version
30
+ getVersion: () => ipcRenderer.invoke('app:get-version'),
31
+ })
@@ -0,0 +1,36 @@
1
+ import { defineConfig } from 'vite'
2
+ import vue from '@vitejs/plugin-vue'
3
+ import { createElectronPlugin } from 'vite-plugin-electron-builder'
4
+ import path from 'path'
5
+
6
+ // https://vitejs.dev/config/
7
+ export default defineConfig({
8
+ plugins: [
9
+ vue(),
10
+ createElectronPlugin({
11
+ // Path to Electron main process entry
12
+ mainProcessFile: 'src/background.js',
13
+
14
+ // Output directory for compiled main process
15
+ outputDir: 'dist_electron',
16
+
17
+ // Optional: path to preload script
18
+ preload: 'src/preload.js',
19
+
20
+ // Optional: electron-builder overrides
21
+ builderOptions: {
22
+ appId: 'com.example.myapp',
23
+ productName: 'My Vue Electron App',
24
+ linux: { target: ['AppImage', 'deb'] },
25
+ win: { target: ['nsis'] },
26
+ mac: { target: ['dmg'] },
27
+ },
28
+ }),
29
+ ],
30
+
31
+ resolve: {
32
+ alias: {
33
+ '@': path.resolve(__dirname, 'src'),
34
+ },
35
+ },
36
+ })