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

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.
@@ -1,125 +0,0 @@
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>
@@ -1,88 +0,0 @@
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
- }
@@ -1,4 +0,0 @@
1
- import { createApp } from 'vue'
2
- import App from './App.vue'
3
-
4
- createApp(App).mount('#app')
@@ -1,31 +0,0 @@
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
- })
@@ -1,36 +0,0 @@
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
- })
package/index.d.ts DELETED
@@ -1,180 +0,0 @@
1
- import type { Plugin, UserConfig } from 'vite'
2
-
3
- // ─── Option Types ─────────────────────────────────────────────────────────────
4
-
5
- export interface ElectronBuilderOptions {
6
- /**
7
- * Relative path to the Electron main process entry file.
8
- * @default 'src/background.js'
9
- */
10
- mainProcessFile?: string
11
-
12
- /**
13
- * Output directory for the compiled main process and packaged app.
14
- * @default 'dist_electron'
15
- */
16
- outputDir?: string
17
-
18
- /**
19
- * Output directory for the Vite renderer build.
20
- * @default 'dist'
21
- */
22
- rendererOutputDir?: string
23
-
24
- /**
25
- * Path to the preload script (relative to project root).
26
- * When set, it is compiled alongside the main process.
27
- */
28
- preload?: string
29
-
30
- /**
31
- * Additional glob patterns to watch for main-process hot-reload.
32
- * Defaults to watching src/background.{js,ts} and src/preload/**
33
- */
34
- mainProcessWatch?: string[]
35
-
36
- /**
37
- * Enable Node integration in the renderer process.
38
- * ⚠ Keep this false in production for security.
39
- * @default false
40
- */
41
- nodeIntegration?: boolean
42
-
43
- /**
44
- * Enable context isolation between main and renderer processes.
45
- * @default true
46
- */
47
- contextIsolation?: boolean
48
-
49
- /**
50
- * Custom Electron protocol scheme used in production (e.g. 'app').
51
- * @default 'app'
52
- */
53
- customFileProtocol?: string
54
-
55
- /**
56
- * Extra Electron CLI flags appended during `electron:serve`.
57
- * @example ['--inspect=5858', '--remote-debugging-port=9222']
58
- */
59
- electronCliArgs?: string[]
60
-
61
- /**
62
- * Native (C++ addon) module names to externalize from the esbuild bundle.
63
- * These will be loaded at runtime from node_modules instead.
64
- * @default []
65
- */
66
- externals?: string[]
67
-
68
- /**
69
- * electron-builder configuration overrides applied during packaging.
70
- */
71
- builderOptions?: ElectronBuilderConfig
72
-
73
- /**
74
- * Additional Vite config applied to the main-process compilation step.
75
- */
76
- mainProcessViteConfig?: Partial<UserConfig>
77
-
78
- /**
79
- * Set to true if you want to skip TypeScript compilation for the main process.
80
- * @default false
81
- */
82
- disableMainProcessTypescript?: boolean
83
- }
84
-
85
- // ─── Result Types ─────────────────────────────────────────────────────────────
86
-
87
- export interface ServeResult {
88
- /** Gracefully stop Electron and the file watcher. */
89
- stop: () => Promise<void>
90
- }
91
-
92
- // ─── Primary API ──────────────────────────────────────────────────────────────
93
-
94
- /**
95
- * The main Vite plugin. Add this to your vite.config.js plugins array.
96
- *
97
- * @example
98
- * // vite.config.js
99
- * import { defineConfig } from 'vite'
100
- * import vue from '@vitejs/plugin-vue'
101
- * import { createElectronPlugin } from 'vite-plugin-electron-builder'
102
- *
103
- * export default defineConfig({
104
- * plugins: [
105
- * vue(),
106
- * createElectronPlugin({ mainProcessFile: 'src/background.js' })
107
- * ]
108
- * })
109
- */
110
- export function createElectronPlugin(options?: ElectronBuilderOptions): Plugin
111
-
112
- // ─── Lower-level Plugin Hooks ─────────────────────────────────────────────────
113
-
114
- /**
115
- * Vite plugin that handles the development serve phase only.
116
- * Use `createElectronPlugin` instead unless you need fine-grained control.
117
- */
118
- export function electronServePlugin(options?: ElectronBuilderOptions): Plugin
119
-
120
- /**
121
- * Vite plugin that handles the production build phase only.
122
- * Use `createElectronPlugin` instead unless you need fine-grained control.
123
- */
124
- export function electronBuildPlugin(options?: ElectronBuilderOptions): Plugin
125
-
126
- // ─── Build Utilities ─────────────────────────────────────────────────────────
127
-
128
- /**
129
- * Compile the Electron main process (and optional preload) using esbuild.
130
- * Called automatically during build; exposed for custom pipelines.
131
- */
132
- export function buildMain(options?: ElectronBuilderOptions): Promise<void>
133
-
134
- /**
135
- * Package the app with electron-builder after the renderer has been built.
136
- * Called automatically during build; exposed for custom pipelines.
137
- */
138
- export function buildRenderer(options?: ElectronBuilderOptions): Promise<void>
139
-
140
- /**
141
- * Start the Electron development server with hot-reload.
142
- * Compiles the main process, launches Electron, and watches source files.
143
- */
144
- export function serve(options?: ElectronBuilderOptions): Promise<void>
145
-
146
- // ─── Helpers ─────────────────────────────────────────────────────────────────
147
-
148
- /**
149
- * Register a secure custom file protocol in the Electron main process.
150
- * Prevents path traversal and falls back to index.html for SPA routing.
151
- *
152
- * @param scheme Protocol name, e.g. 'app'
153
- * @param basePath Override the directory from which files are served.
154
- *
155
- * @example
156
- * // src/background.js
157
- * import { createProtocol } from 'vite-plugin-electron-builder/lib/protocol'
158
- *
159
- * app.whenReady().then(() => {
160
- * createProtocol('app')
161
- * win.loadURL('app://./index.html')
162
- * })
163
- */
164
- export function createProtocol(scheme: string, basePath?: string): void
165
-
166
- /**
167
- * Scan node_modules for packages that contain native (.node) binaries.
168
- * Useful for automatically populating the `externals` option.
169
- *
170
- * @param projectRoot Absolute path to the project root (default: cwd)
171
- */
172
- export function getNativeDeps(projectRoot?: string): Promise<string[]>
173
-
174
- /**
175
- * Normalise plugin options, applying all defaults.
176
- * Useful for tooling that needs to introspect resolved config.
177
- */
178
- export function getConfig(
179
- options?: ElectronBuilderOptions
180
- ): Required<ElectronBuilderOptions>
package/lib/build.js DELETED
@@ -1,128 +0,0 @@
1
- 'use strict'
2
-
3
- const path = require('path')
4
- const fs = require('fs-extra')
5
- const chalk = require('chalk')
6
- const { build: electronBuilderBuild } = require('electron-builder')
7
-
8
- /**
9
- * Build the Electron main process using esbuild.
10
- * @param {object} options
11
- * @param {string} [options.mainProcessFile] - entry point
12
- * @param {string} [options.outputDir] - output dir (default: dist-electron)
13
- * @param {'development'|'production'} [options.mode]
14
- */
15
- async function buildMain(options = {}) {
16
- const outputDir = options.outputDir || 'dist_electron'
17
- const mode = options.mode || 'production'
18
- const cwd = process.cwd()
19
-
20
- const possibleEntries = [
21
- options.mainProcessFile,
22
- path.join(cwd, 'src/background.ts'),
23
- path.join(cwd, 'src/background.js'),
24
- path.join(cwd, 'src/main/index.ts'),
25
- path.join(cwd, 'src/main/index.js'),
26
- path.join(cwd, 'electron/main.ts'),
27
- path.join(cwd, 'electron/main.js'),
28
- ].filter(Boolean)
29
-
30
- const entry = possibleEntries.find((p) => fs.existsSync(p))
31
- if (!entry) {
32
- console.warn(chalk.yellow('[electron-builder] No main process entry found.'))
33
- return
34
- }
35
-
36
- await fs.ensureDir(path.join(cwd, outputDir))
37
-
38
- const esbuild = requireEsbuild()
39
- if (!esbuild) {
40
- throw new Error('[electron-builder] esbuild is required. Run: npm install -D esbuild')
41
- }
42
-
43
- await esbuild.build({
44
- entryPoints: [entry],
45
- bundle: true,
46
- platform: 'node',
47
- target: `node${process.versions.node.split('.')[0]}`,
48
- outfile: path.join(cwd, outputDir, 'main.js'),
49
- external: ['electron', ...getExternalModules(cwd)],
50
- define: { 'process.env.NODE_ENV': JSON.stringify(mode) },
51
- sourcemap: mode === 'development',
52
- minify: mode === 'production',
53
- })
54
-
55
- const preloadEntry = findPreload(cwd)
56
- if (preloadEntry) {
57
- await esbuild.build({
58
- entryPoints: [preloadEntry],
59
- bundle: true,
60
- platform: 'node',
61
- target: `node${process.versions.node.split('.')[0]}`,
62
- outfile: path.join(cwd, outputDir, 'preload.js'),
63
- external: ['electron'],
64
- sourcemap: mode === 'development',
65
- minify: mode === 'production',
66
- })
67
- console.log(chalk.green('[electron-builder] Preload script compiled'))
68
- }
69
-
70
- console.log(chalk.green('[electron-builder] Main process compiled'))
71
- }
72
-
73
- /**
74
- * Package the app using electron-builder
75
- * @param {object} options
76
- * @param {string} [options.rendererOutputDir] - Vite build output (default: 'dist')
77
- * @param {string} [options.electronOutputDir] - compiled main output (default: 'dist_electron')
78
- * @param {object} [options.builderOptions] - electron-builder config overrides
79
- */
80
- async function buildRenderer(options = {}) {
81
- const cwd = process.cwd()
82
- const rendererOutput = options.rendererOutputDir || 'dist'
83
- const electronOutput = options.electronOutputDir || 'dist_electron'
84
-
85
- console.log(chalk.blue('[electron-builder] Packaging with electron-builder...'))
86
-
87
- const builderConfig = {
88
- directories: {
89
- output: path.join(cwd, electronOutput, 'release'),
90
- app: cwd,
91
- },
92
- files: [
93
- `${rendererOutput}/**/*`,
94
- `${electronOutput}/main.js`,
95
- `${electronOutput}/preload.js`,
96
- 'package.json',
97
- ],
98
- ...(options.builderOptions || {}),
99
- }
100
-
101
- const result = await electronBuilderBuild({ config: builderConfig })
102
- console.log(chalk.green('[electron-builder] Packaging complete:'), result)
103
- }
104
-
105
- function requireEsbuild() {
106
- try { return require('esbuild') } catch { return null }
107
- }
108
-
109
- function findPreload(cwd) {
110
- const candidates = [
111
- path.join(cwd, 'src/preload.ts'),
112
- path.join(cwd, 'src/preload.js'),
113
- path.join(cwd, 'src/preload/index.ts'),
114
- path.join(cwd, 'src/preload/index.js'),
115
- path.join(cwd, 'electron/preload.ts'),
116
- path.join(cwd, 'electron/preload.js'),
117
- ]
118
- return candidates.find((p) => fs.existsSync(p)) || null
119
- }
120
-
121
- function getExternalModules(cwd) {
122
- try {
123
- const pkg = require(path.join(cwd, 'package.json'))
124
- return Object.keys(pkg.dependencies || {})
125
- } catch { return [] }
126
- }
127
-
128
- module.exports = { buildMain, buildRenderer }
package/lib/config.js DELETED
@@ -1,25 +0,0 @@
1
- 'use strict'
2
-
3
- /**
4
- * Normalize and apply defaults to plugin options.
5
- * @param {import('..').ElectronBuilderOptions} options
6
- * @returns {Required<import('..').ElectronBuilderOptions>}
7
- */
8
- function getConfig(options = {}) {
9
- return {
10
- mainProcessFile: options.mainProcessFile || 'src/background.js',
11
- outputDir: options.outputDir || 'dist_electron',
12
- mainProcessViteConfig: options.mainProcessViteConfig || {},
13
- rendererViteConfig: options.rendererViteConfig || {},
14
- builderOptions: options.builderOptions || {},
15
- externals: options.externals || [],
16
- nodeIntegration: options.nodeIntegration === true,
17
- contextIsolation: options.contextIsolation !== false,
18
- preload: options.preload || null,
19
- customFileProtocol: options.customFileProtocol || 'app',
20
- disableMainProcessTypescript: options.disableMainProcessTypescript === true,
21
- electronCliArgs: options.electronCliArgs || []
22
- }
23
- }
24
-
25
- module.exports = { getConfig }
package/lib/nativeDeps.js DELETED
@@ -1,85 +0,0 @@
1
- 'use strict'
2
-
3
- const path = require('path')
4
- const fs = require('fs-extra')
5
-
6
- /**
7
- * Detect native (C++ addon) dependencies in the project's node_modules.
8
- * Returns a list of package names that contain .node binaries.
9
- *
10
- * @param {string} projectRoot
11
- * @returns {Promise<string[]>}
12
- */
13
- async function getNativeDeps(projectRoot) {
14
- const pkgJsonPath = path.join(projectRoot, 'package.json')
15
-
16
- if (!fs.existsSync(pkgJsonPath)) {
17
- return []
18
- }
19
-
20
- const pkg = await fs.readJson(pkgJsonPath)
21
- const allDeps = {
22
- ...pkg.dependencies,
23
- ...pkg.optionalDependencies
24
- }
25
-
26
- const nativeDeps = []
27
-
28
- for (const depName of Object.keys(allDeps)) {
29
- const depDir = path.join(projectRoot, 'node_modules', depName)
30
-
31
- if (await isNativeDep(depDir)) {
32
- nativeDeps.push(depName)
33
- }
34
- }
35
-
36
- return nativeDeps
37
- }
38
-
39
- /**
40
- * Check if a package directory contains native bindings.
41
- * @param {string} depDir
42
- * @returns {Promise<boolean>}
43
- */
44
- async function isNativeDep(depDir) {
45
- if (!fs.existsSync(depDir)) return false
46
-
47
- try {
48
- // Check for .node files (compiled native addons)
49
- const files = await walkDir(depDir)
50
- return files.some(f => f.endsWith('.node'))
51
- } catch {
52
- return false
53
- }
54
- }
55
-
56
- /**
57
- * Recursively list files in a directory.
58
- * Skips node_modules sub-directories.
59
- * @param {string} dir
60
- * @returns {Promise<string[]>}
61
- */
62
- async function walkDir(dir) {
63
- const results = []
64
-
65
- if (!fs.existsSync(dir)) return results
66
-
67
- const entries = await fs.readdir(dir, { withFileTypes: true })
68
-
69
- for (const entry of entries) {
70
- if (entry.name === 'node_modules') continue
71
-
72
- const fullPath = path.join(dir, entry.name)
73
-
74
- if (entry.isDirectory()) {
75
- const sub = await walkDir(fullPath)
76
- results.push(...sub)
77
- } else {
78
- results.push(fullPath)
79
- }
80
- }
81
-
82
- return results
83
- }
84
-
85
- module.exports = { getNativeDeps, isNativeDep }