@snoirtrom/electron-vite 6.0.1 → 6.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/bin/bytecode-compiler.cjs +15 -0
- package/bin/electron-bytecode-main.cjs +107 -0
- package/bin/electron-bytecode-preload.cjs +10 -0
- package/bin/rpc-peer.cjs +89 -0
- package/dist/chunks/{lib-B8n2vQeG.js → lib-DaHzt8UE.js} +4 -4
- package/dist/chunks/{lib-CzmB3HUY.js → lib-DyA1RI3R.js} +3 -3
- package/dist/chunks/{lib-FYrM-Sbc.js → lib-ShkGlprt.js} +4 -4
- package/dist/chunks/{lib-CbKPgmtQ.js → lib-wmKiubLV.js} +451 -302
- package/dist/cli.js +4 -4
- package/dist/index.js +7 -7
- package/package.json +19 -20
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const vm = require('node:vm')
|
|
2
|
+
const v8 = require('node:v8')
|
|
3
|
+
|
|
4
|
+
v8.setFlagsFromString('--no-lazy')
|
|
5
|
+
v8.setFlagsFromString('--no-flush-bytecode')
|
|
6
|
+
|
|
7
|
+
const params = ['exports', 'require', 'module', '__filename', '__dirname']
|
|
8
|
+
|
|
9
|
+
module.exports = function compile(code) {
|
|
10
|
+
if (typeof code !== 'string') throw new TypeError('Compilation source must be a string')
|
|
11
|
+
const { cachedData } = vm.compileFunction(code, params, { produceCachedData: true })
|
|
12
|
+
if (!Buffer.isBuffer(cachedData)) throw new Error('V8 did not produce cached data')
|
|
13
|
+
// Explicit wire format works across both Node IPC and Electron structured clone.
|
|
14
|
+
return { sourceLength: code.length, cachedData: cachedData.toString('base64') }
|
|
15
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
const { app, BrowserWindow, ipcMain } = require('electron')
|
|
2
|
+
const path = require('node:path')
|
|
3
|
+
const RpcPeer = require('./rpc-peer.cjs')
|
|
4
|
+
const compile = require('./bytecode-compiler.cjs')
|
|
5
|
+
|
|
6
|
+
if (process.platform === 'darwin') {
|
|
7
|
+
app.dock.hide()
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const channel = 'electron-vite:bytecode:rpc'
|
|
11
|
+
const readyChannel = 'electron-vite:bytecode:ready'
|
|
12
|
+
let win
|
|
13
|
+
let rendererRPC
|
|
14
|
+
let stopping = false
|
|
15
|
+
|
|
16
|
+
function fail(error) {
|
|
17
|
+
console.error(error)
|
|
18
|
+
parentRPC.close(error)
|
|
19
|
+
rendererRPC?.close(error)
|
|
20
|
+
app.exit(1)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const parentRPC = new RpcPeer(
|
|
24
|
+
message =>
|
|
25
|
+
new Promise((resolve, reject) => {
|
|
26
|
+
if (!process.connected || !process.send) return reject(new Error('Parent IPC is disconnected'))
|
|
27
|
+
process.send(message, error => (error ? reject(error) : resolve()))
|
|
28
|
+
})
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
function createRenderer() {
|
|
32
|
+
return new Promise((resolve, reject) => {
|
|
33
|
+
let ready = false
|
|
34
|
+
const timer = setTimeout(() => finish(new Error('Compiler preload readiness timed out')), 30000)
|
|
35
|
+
function finish(error) {
|
|
36
|
+
clearTimeout(timer)
|
|
37
|
+
ipcMain.removeListener(readyChannel, onReady)
|
|
38
|
+
if (error) reject(error)
|
|
39
|
+
else {
|
|
40
|
+
ready = true
|
|
41
|
+
resolve()
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function onReady(event) {
|
|
45
|
+
if (event.sender === win.webContents) finish()
|
|
46
|
+
}
|
|
47
|
+
function onFailure(error) {
|
|
48
|
+
if (stopping) return
|
|
49
|
+
if (ready) fail(error)
|
|
50
|
+
else finish(error)
|
|
51
|
+
}
|
|
52
|
+
ipcMain.on(readyChannel, onReady)
|
|
53
|
+
win = new BrowserWindow({
|
|
54
|
+
show: false,
|
|
55
|
+
webPreferences: {
|
|
56
|
+
preload: path.join(__dirname, 'electron-bytecode-preload.cjs'),
|
|
57
|
+
sandbox: false,
|
|
58
|
+
contextIsolation: true
|
|
59
|
+
}
|
|
60
|
+
})
|
|
61
|
+
rendererRPC = new RpcPeer(message => {
|
|
62
|
+
if (win.isDestroyed()) throw new Error('Compiler window is closed')
|
|
63
|
+
win.webContents.send(channel, message)
|
|
64
|
+
})
|
|
65
|
+
ipcMain.on(channel, (event, message) => {
|
|
66
|
+
if (!win.isDestroyed() && event.sender === win.webContents) void rendererRPC.receive(message)
|
|
67
|
+
})
|
|
68
|
+
win.webContents.on('preload-error', (_event, _path, error) => onFailure(error))
|
|
69
|
+
win.webContents.on('render-process-gone', (_event, details) => {
|
|
70
|
+
onFailure(new Error(`Compiler renderer exited: ${details.reason}`))
|
|
71
|
+
})
|
|
72
|
+
win.on('closed', () => onFailure(new Error('Compiler window closed unexpectedly')))
|
|
73
|
+
win.loadURL('data:text/html,<!doctype html><html></html>').catch(onFailure)
|
|
74
|
+
})
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Register readiness immediately, but only resolve it after the selected backend is usable.
|
|
78
|
+
const initialized = app.whenReady().then(async () => {
|
|
79
|
+
if (process.env.ELECTRON_VITE_RENDERER === '1' || process.env.ELECTRON_VITE_RENDERER === 'true') {
|
|
80
|
+
await createRenderer()
|
|
81
|
+
parentRPC.register('compile', (...args) => rendererRPC.request('compile', ...args))
|
|
82
|
+
} else {
|
|
83
|
+
parentRPC.register('compile', compile)
|
|
84
|
+
}
|
|
85
|
+
return true
|
|
86
|
+
})
|
|
87
|
+
parentRPC.register('ready', () => initialized)
|
|
88
|
+
initialized.catch(fail)
|
|
89
|
+
|
|
90
|
+
process.on('message', message => {
|
|
91
|
+
if (message?.type === 'shutdown') {
|
|
92
|
+
stopping = true
|
|
93
|
+
app.quit()
|
|
94
|
+
} else {
|
|
95
|
+
void parentRPC.receive(message)
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
process.on('disconnect', () => {
|
|
99
|
+
stopping = true
|
|
100
|
+
app.quit()
|
|
101
|
+
})
|
|
102
|
+
app.on('before-quit', () => {
|
|
103
|
+
stopping = true
|
|
104
|
+
parentRPC.close()
|
|
105
|
+
rendererRPC?.close()
|
|
106
|
+
})
|
|
107
|
+
if (!process.send) fail(new Error('Bytecode compiler must be launched with an IPC channel'))
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { ipcRenderer } = require('electron')
|
|
2
|
+
const RpcPeer = require('./rpc-peer.cjs')
|
|
3
|
+
const compile = require('./bytecode-compiler.cjs')
|
|
4
|
+
|
|
5
|
+
const channel = 'electron-vite:bytecode:rpc'
|
|
6
|
+
const rpc = new RpcPeer(message => ipcRenderer.send(channel, message))
|
|
7
|
+
rpc.register('ready', () => true)
|
|
8
|
+
rpc.register('compile', compile)
|
|
9
|
+
ipcRenderer.on(channel, (_event, message) => void rpc.receive(message))
|
|
10
|
+
ipcRenderer.send('electron-vite:bytecode:ready')
|
package/bin/rpc-peer.cjs
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
// Transport-independent peer. Messages must be JSON serializable.
|
|
2
|
+
class RpcPeer {
|
|
3
|
+
constructor(send, timeout = 30000) {
|
|
4
|
+
this.send = send
|
|
5
|
+
this.timeout = timeout
|
|
6
|
+
this.methods = new Map()
|
|
7
|
+
this.pending = new Map()
|
|
8
|
+
this.nextId = 0
|
|
9
|
+
this.closed = false
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
register(cmd, method) {
|
|
13
|
+
this.methods.set(cmd, method)
|
|
14
|
+
return this
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
request(cmd, ...args) {
|
|
18
|
+
if (this.closed) return Promise.reject(new Error('RPC connection is closed'))
|
|
19
|
+
const invocationId = this.nextId++
|
|
20
|
+
return new Promise((resolve, reject) => {
|
|
21
|
+
const timer = setTimeout(() => {
|
|
22
|
+
this.pending.delete(invocationId)
|
|
23
|
+
reject(new Error(`RPC request timed out: ${cmd}`))
|
|
24
|
+
}, this.timeout)
|
|
25
|
+
this.pending.set(invocationId, { resolve, reject, timer })
|
|
26
|
+
Promise.resolve()
|
|
27
|
+
.then(() => this.send({ type: 'request', invocationId, cmd, args }))
|
|
28
|
+
.catch(error => {
|
|
29
|
+
const pending = this.pending.get(invocationId)
|
|
30
|
+
if (!pending) return
|
|
31
|
+
clearTimeout(timer)
|
|
32
|
+
this.pending.delete(invocationId)
|
|
33
|
+
reject(error)
|
|
34
|
+
})
|
|
35
|
+
})
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async receive(message) {
|
|
39
|
+
if (this.closed || !message || !Number.isSafeInteger(message.invocationId)) return
|
|
40
|
+
const { type, invocationId } = message
|
|
41
|
+
if (type === 'response') {
|
|
42
|
+
const pending = this.pending.get(invocationId)
|
|
43
|
+
if (!pending) return
|
|
44
|
+
this.pending.delete(invocationId)
|
|
45
|
+
clearTimeout(pending.timer)
|
|
46
|
+
if (message.error) {
|
|
47
|
+
const error = new Error(message.error.message)
|
|
48
|
+
error.name = message.error.name || 'Error'
|
|
49
|
+
if (message.error.stack) error.stack = message.error.stack
|
|
50
|
+
pending.reject(error)
|
|
51
|
+
} else {
|
|
52
|
+
pending.resolve(message.result)
|
|
53
|
+
}
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
if (type !== 'request' || typeof message.cmd !== 'string' || !Array.isArray(message.args)) return
|
|
57
|
+
const response = { type: 'response', invocationId }
|
|
58
|
+
try {
|
|
59
|
+
const method = this.methods.get(message.cmd)
|
|
60
|
+
if (!method) throw new Error(`Invalid method: ${message.cmd}`)
|
|
61
|
+
response.result = await method(...message.args)
|
|
62
|
+
} catch (error) {
|
|
63
|
+
response.error = {
|
|
64
|
+
name: error instanceof Error ? error.name : 'Error',
|
|
65
|
+
message: error instanceof Error ? error.message : String(error),
|
|
66
|
+
stack: error instanceof Error ? error.stack : undefined
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (!this.closed) {
|
|
70
|
+
try {
|
|
71
|
+
await this.send(response)
|
|
72
|
+
} catch (error) {
|
|
73
|
+
this.close(error)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
close(error = new Error('RPC connection is closed')) {
|
|
79
|
+
this.closed = true
|
|
80
|
+
for (const pending of this.pending.values()) {
|
|
81
|
+
clearTimeout(pending.timer)
|
|
82
|
+
pending.reject(error)
|
|
83
|
+
}
|
|
84
|
+
this.pending.clear()
|
|
85
|
+
this.methods.clear()
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
module.exports = RpcPeer
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { build as build$1 } from 'vite';
|
|
2
|
-
import { r as resolveConfig } from './lib-
|
|
2
|
+
import { r as resolveConfig } from './lib-wmKiubLV.js';
|
|
3
3
|
import 'node:path';
|
|
4
|
+
import 'picocolors';
|
|
4
5
|
import 'node:fs';
|
|
5
|
-
import 'node:url';
|
|
6
6
|
import 'node:module';
|
|
7
|
-
import 'picocolors';
|
|
8
|
-
import 'esbuild';
|
|
9
7
|
import 'node:child_process';
|
|
10
8
|
import 'node:crypto';
|
|
11
9
|
import 'node:fs/promises';
|
|
12
10
|
import 'magic-string';
|
|
13
11
|
import '@babel/core';
|
|
12
|
+
import 'node:url';
|
|
13
|
+
import 'rolldown';
|
|
14
14
|
|
|
15
15
|
/**
|
|
16
16
|
* Bundles the electron app for production.
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { createLogger, createServer as createServer$1, mergeConfig, build } from 'vite';
|
|
2
2
|
import colors from 'picocolors';
|
|
3
|
-
import { r as resolveConfig, c as resolveHostname, s as startElectron } from './lib-
|
|
3
|
+
import { r as resolveConfig, c as resolveHostname, s as startElectron } from './lib-wmKiubLV.js';
|
|
4
4
|
import 'node:path';
|
|
5
5
|
import 'node:fs';
|
|
6
|
-
import 'node:url';
|
|
7
6
|
import 'node:module';
|
|
8
|
-
import 'esbuild';
|
|
9
7
|
import 'node:child_process';
|
|
10
8
|
import 'node:crypto';
|
|
11
9
|
import 'node:fs/promises';
|
|
12
10
|
import 'magic-string';
|
|
13
11
|
import '@babel/core';
|
|
12
|
+
import 'node:url';
|
|
13
|
+
import 'rolldown';
|
|
14
14
|
|
|
15
15
|
async function createServer(inlineConfig = {}, options) {
|
|
16
16
|
process.env.NODE_ENV_ELECTRON_VITE = 'development';
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import colors from 'picocolors';
|
|
2
2
|
import { createLogger } from 'vite';
|
|
3
|
-
import { s as startElectron } from './lib-
|
|
4
|
-
import { build } from './lib-
|
|
3
|
+
import { s as startElectron } from './lib-wmKiubLV.js';
|
|
4
|
+
import { build } from './lib-DaHzt8UE.js';
|
|
5
5
|
import 'node:path';
|
|
6
6
|
import 'node:fs';
|
|
7
|
-
import 'node:url';
|
|
8
7
|
import 'node:module';
|
|
9
|
-
import 'esbuild';
|
|
10
8
|
import 'node:child_process';
|
|
11
9
|
import 'node:crypto';
|
|
12
10
|
import 'node:fs/promises';
|
|
13
11
|
import 'magic-string';
|
|
14
12
|
import '@babel/core';
|
|
13
|
+
import 'node:url';
|
|
14
|
+
import 'rolldown';
|
|
15
15
|
|
|
16
16
|
async function preview(inlineConfig = {}, options) {
|
|
17
17
|
if (!options.skipBuild) {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import { pathToFileURL } from 'node:url';
|
|
4
|
-
import { createRequire, builtinModules } from 'node:module';
|
|
5
2
|
import colors from 'picocolors';
|
|
6
3
|
import { loadEnv as loadEnv$1, mergeConfig, normalizePath, version, build, createLogger } from 'vite';
|
|
7
|
-
import
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { createRequire, builtinModules } from 'node:module';
|
|
8
6
|
import { spawn } from 'node:child_process';
|
|
9
|
-
import { createHash } from 'node:crypto';
|
|
7
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
10
8
|
import fs$1 from 'node:fs/promises';
|
|
11
9
|
import MagicString from 'magic-string';
|
|
12
10
|
import * as babel from '@babel/core';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { rolldown } from 'rolldown';
|
|
13
13
|
|
|
14
14
|
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-function-type */
|
|
15
15
|
function isObject(value) {
|
|
@@ -69,27 +69,54 @@ function isFilePathESM(filePath) {
|
|
|
69
69
|
return pkg?.type === 'module';
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Isolate configuration data without cloning plugins or runtime instances.
|
|
74
|
+
* Plugins may capture their own object in hooks, so their identity must survive.
|
|
75
|
+
*/
|
|
76
|
+
function cloneConfig(config) {
|
|
77
|
+
const seen = new WeakMap();
|
|
78
|
+
const pluginArrays = new WeakMap();
|
|
79
|
+
function clone(value, plugins = false) {
|
|
80
|
+
if (value === null || typeof value !== 'object')
|
|
81
|
+
return value;
|
|
82
|
+
const cache = plugins ? pluginArrays : seen;
|
|
83
|
+
if (cache.has(value))
|
|
84
|
+
return cache.get(value);
|
|
85
|
+
if (Array.isArray(value)) {
|
|
86
|
+
const result = new Array(value.length);
|
|
87
|
+
cache.set(value, result);
|
|
88
|
+
value.forEach((item, index) => {
|
|
89
|
+
result[index] = clone(item, plugins);
|
|
90
|
+
});
|
|
91
|
+
return result;
|
|
80
92
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
93
|
+
// Preserve plugin objects, promises and other opaque plugin options.
|
|
94
|
+
if (plugins)
|
|
95
|
+
return value;
|
|
96
|
+
if (value instanceof RegExp) {
|
|
97
|
+
const result = new RegExp(value);
|
|
98
|
+
result.lastIndex = value.lastIndex;
|
|
99
|
+
cache.set(value, result);
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
const prototype = Object.getPrototypeOf(value);
|
|
103
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
104
|
+
return value;
|
|
105
|
+
const result = Object.create(prototype);
|
|
106
|
+
cache.set(value, result);
|
|
107
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
108
|
+
if (!Object.prototype.propertyIsEnumerable.call(value, key))
|
|
109
|
+
continue;
|
|
110
|
+
Object.defineProperty(result, key, {
|
|
111
|
+
value: clone(value[key], key === 'plugins'),
|
|
112
|
+
enumerable: true,
|
|
113
|
+
configurable: true,
|
|
114
|
+
writable: true
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
return result;
|
|
91
118
|
}
|
|
92
|
-
return
|
|
119
|
+
return clone(config);
|
|
93
120
|
}
|
|
94
121
|
async function asyncFlatten(arr) {
|
|
95
122
|
do {
|
|
@@ -160,6 +187,7 @@ function getElectronPath() {
|
|
|
160
187
|
function getElectronNodeTarget() {
|
|
161
188
|
const electronVer = getElectronMajorVer();
|
|
162
189
|
const nodeVer = {
|
|
190
|
+
'45': '24.21',
|
|
163
191
|
'44': '24.20',
|
|
164
192
|
'41': '24.14',
|
|
165
193
|
'40': '24.14',
|
|
@@ -193,6 +221,7 @@ function getElectronNodeTarget() {
|
|
|
193
221
|
function getElectronChromeTarget() {
|
|
194
222
|
const electronVer = getElectronMajorVer();
|
|
195
223
|
const chromeVer = {
|
|
224
|
+
'45': '156',
|
|
196
225
|
'44': '152',
|
|
197
226
|
'41': '146',
|
|
198
227
|
'40': '144',
|
|
@@ -1165,124 +1194,223 @@ function externalizeDepsPlugin(options = {}) {
|
|
|
1165
1194
|
};
|
|
1166
1195
|
}
|
|
1167
1196
|
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
const
|
|
1179
|
-
|
|
1180
|
-
|
|
1197
|
+
class ElectronCompiler {
|
|
1198
|
+
options;
|
|
1199
|
+
ps;
|
|
1200
|
+
rpcMap = new Map();
|
|
1201
|
+
invocationId = 0;
|
|
1202
|
+
starting;
|
|
1203
|
+
stopping;
|
|
1204
|
+
ready = false;
|
|
1205
|
+
constructor(options) {
|
|
1206
|
+
this.options = options;
|
|
1207
|
+
for (const timeout of [options.timeout, options.shutdownTimeout]) {
|
|
1208
|
+
if (timeout !== undefined && (!Number.isFinite(timeout) || timeout <= 0)) {
|
|
1209
|
+
throw new RangeError('ElectronCompiler timeouts must be positive finite numbers');
|
|
1210
|
+
}
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
start() {
|
|
1214
|
+
if (this.stopping)
|
|
1215
|
+
return Promise.reject(new Error('ElectronCompiler is stopping'));
|
|
1216
|
+
if (this.starting)
|
|
1217
|
+
return this.starting;
|
|
1218
|
+
if (this.ready)
|
|
1219
|
+
return Promise.resolve();
|
|
1220
|
+
if (this.ps)
|
|
1221
|
+
return Promise.reject(new Error('Previous Electron process has not closed; await stop() first'));
|
|
1222
|
+
this.starting = this.initialize().finally(() => {
|
|
1223
|
+
this.starting = undefined;
|
|
1224
|
+
});
|
|
1225
|
+
return this.starting;
|
|
1226
|
+
}
|
|
1227
|
+
async initialize() {
|
|
1228
|
+
const env = { ...process.env, ...this.options.env, ELECTRON_VITE_RPC: 'true' };
|
|
1229
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
1230
|
+
const ps = spawn(this.options.path, this.options.args, {
|
|
1231
|
+
stdio: ['ignore', 'inherit', 'inherit', 'ipc'],
|
|
1232
|
+
windowsHide: true,
|
|
1233
|
+
env
|
|
1181
1234
|
});
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1235
|
+
this.ps = ps;
|
|
1236
|
+
ps.on('message', (message) => {
|
|
1237
|
+
if (this.ps !== ps || !message || message.type !== 'response')
|
|
1238
|
+
return;
|
|
1239
|
+
const pending = this.rpcMap.get(message.invocationId);
|
|
1240
|
+
if (!pending)
|
|
1241
|
+
return;
|
|
1242
|
+
clearTimeout(pending.timer);
|
|
1243
|
+
this.rpcMap.delete(message.invocationId);
|
|
1244
|
+
if (message.error) {
|
|
1245
|
+
const error = new Error(message.error.message);
|
|
1246
|
+
error.name = message.error.name;
|
|
1247
|
+
if (message.error.stack)
|
|
1248
|
+
error.stack = message.error.stack;
|
|
1249
|
+
pending.reject(error);
|
|
1250
|
+
}
|
|
1251
|
+
else
|
|
1252
|
+
pending.resolve(message.result);
|
|
1253
|
+
});
|
|
1254
|
+
ps.on('error', error => {
|
|
1255
|
+
if (this.ps === ps)
|
|
1256
|
+
this.rejectPending(error);
|
|
1257
|
+
});
|
|
1258
|
+
ps.on('disconnect', () => {
|
|
1259
|
+
if (this.ps === ps)
|
|
1260
|
+
this.rejectPending(new Error('Electron IPC disconnected'));
|
|
1261
|
+
});
|
|
1262
|
+
ps.on('exit', (code, signal) => {
|
|
1263
|
+
if (this.ps === ps)
|
|
1264
|
+
this.rejectPending(new Error('Electron exited (code ' + code + ', signal ' + signal + ')'));
|
|
1265
|
+
});
|
|
1266
|
+
ps.on('close', () => {
|
|
1267
|
+
if (this.ps === ps) {
|
|
1268
|
+
this.rejectPending(new Error('Electron process closed'));
|
|
1269
|
+
this.ps = undefined;
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
try {
|
|
1273
|
+
await this.sendRequest('ready', []);
|
|
1274
|
+
if (!ps.connected || this.stopping)
|
|
1275
|
+
throw new Error('Electron stopped during initialization');
|
|
1276
|
+
this.ready = true;
|
|
1185
1277
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
});
|
|
1190
|
-
proc.stdout.on('error', err => {
|
|
1191
|
-
console.error(err);
|
|
1192
|
-
});
|
|
1193
|
-
proc.stdout.on('end', () => {
|
|
1194
|
-
resolve(data);
|
|
1195
|
-
});
|
|
1278
|
+
catch (error) {
|
|
1279
|
+
await this.stop();
|
|
1280
|
+
throw error;
|
|
1196
1281
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1282
|
+
}
|
|
1283
|
+
compile(code) {
|
|
1284
|
+
return this.request('compile', code);
|
|
1285
|
+
}
|
|
1286
|
+
async request(cmd, ...args) {
|
|
1287
|
+
if (!this.ready || this.stopping)
|
|
1288
|
+
throw new Error('ElectronCompiler is not ready; await start() first');
|
|
1289
|
+
return this.sendRequest(cmd, args);
|
|
1290
|
+
}
|
|
1291
|
+
sendRequest(cmd, args) {
|
|
1292
|
+
const ps = this.ps;
|
|
1293
|
+
if (!ps?.connected)
|
|
1294
|
+
return Promise.reject(new Error('Electron IPC is not connected'));
|
|
1295
|
+
const invocationId = this.invocationId++;
|
|
1296
|
+
return new Promise((resolve, reject) => {
|
|
1297
|
+
const fail = (error) => {
|
|
1298
|
+
const pending = this.rpcMap.get(invocationId);
|
|
1299
|
+
if (!pending)
|
|
1300
|
+
return;
|
|
1301
|
+
clearTimeout(pending.timer);
|
|
1302
|
+
this.rpcMap.delete(invocationId);
|
|
1303
|
+
reject(error);
|
|
1304
|
+
};
|
|
1305
|
+
const timer = setTimeout(() => fail(new Error('Electron RPC timed out: ' + cmd)), this.options.timeout ?? 30000);
|
|
1306
|
+
this.rpcMap.set(invocationId, { resolve, reject, timer });
|
|
1307
|
+
try {
|
|
1308
|
+
ps.send({ type: 'request', invocationId, cmd, args }, error => {
|
|
1309
|
+
if (error)
|
|
1310
|
+
fail(error);
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
catch (error) {
|
|
1314
|
+
fail(error instanceof Error ? error : new Error(String(error)));
|
|
1315
|
+
}
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
rejectPending(error) {
|
|
1319
|
+
this.ready = false;
|
|
1320
|
+
for (const pending of this.rpcMap.values()) {
|
|
1321
|
+
clearTimeout(pending.timer);
|
|
1322
|
+
pending.reject(error);
|
|
1204
1323
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1324
|
+
this.rpcMap.clear();
|
|
1325
|
+
}
|
|
1326
|
+
stop() {
|
|
1327
|
+
if (this.stopping)
|
|
1328
|
+
return this.stopping;
|
|
1329
|
+
this.rejectPending(new Error('ElectronCompiler stopped'));
|
|
1330
|
+
const ps = this.ps;
|
|
1331
|
+
if (!ps)
|
|
1332
|
+
return Promise.resolve();
|
|
1333
|
+
this.stopping = new Promise(resolve => {
|
|
1334
|
+
const timer = setTimeout(() => ps.kill('SIGKILL'), this.options.shutdownTimeout ?? 3000);
|
|
1335
|
+
ps.once('close', () => {
|
|
1336
|
+
clearTimeout(timer);
|
|
1337
|
+
resolve();
|
|
1338
|
+
});
|
|
1339
|
+
if (ps.connected) {
|
|
1340
|
+
try {
|
|
1341
|
+
ps.send({ type: 'shutdown' }, error => {
|
|
1342
|
+
if (error)
|
|
1343
|
+
ps.kill();
|
|
1344
|
+
});
|
|
1345
|
+
}
|
|
1346
|
+
catch {
|
|
1347
|
+
ps.kill();
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
else
|
|
1351
|
+
ps.kill();
|
|
1352
|
+
}).finally(() => {
|
|
1353
|
+
this.stopping = undefined;
|
|
1210
1354
|
});
|
|
1211
|
-
|
|
1355
|
+
return this.stopping;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// Inspired by https://github.com/bytenode/bytenode
|
|
1360
|
+
const _require$1 = createRequire(import.meta.url);
|
|
1361
|
+
function getBytecodeCompilerPath() {
|
|
1362
|
+
return path.join(path.dirname(_require$1.resolve('electron-vite/package.json')), 'bin', 'electron-bytecode-main.cjs');
|
|
1363
|
+
}
|
|
1364
|
+
// Versioned envelope: magic/version (8), UTF-16 source length (4), module ID (16), V8 cache.
|
|
1365
|
+
// Keep our metadata separate from the private V8 cache header.
|
|
1366
|
+
async function compileToBytecode(compiler, code) {
|
|
1367
|
+
const id = randomBytes(16);
|
|
1368
|
+
// Reserve enough source space for an untruncated, per-artifact placeholder identity.
|
|
1369
|
+
const source = code + '\n/*' + id.toString('hex') + '*/';
|
|
1370
|
+
const result = await compiler.compile(source);
|
|
1371
|
+
const header = Buffer.alloc(28);
|
|
1372
|
+
header.write('EVBC0001', 0, 'ascii');
|
|
1373
|
+
header.writeUInt32LE(result.sourceLength, 8);
|
|
1374
|
+
id.copy(header, 12);
|
|
1375
|
+
return Buffer.concat([header, Buffer.from(result.cachedData, 'base64')]);
|
|
1212
1376
|
}
|
|
1213
1377
|
const bytecodeModuleLoaderCode = [
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
` setFlagHashHeader(bytecodeBuffer);`,
|
|
1251
|
-
` const length = buffer2Number(getSourceHashHeader(bytecodeBuffer));`,
|
|
1252
|
-
` let dummyCode = "";`,
|
|
1253
|
-
` if (length > 1) {`,
|
|
1254
|
-
` dummyCode = "\\"" + "\\u200b".repeat(length - 2) + "\\"";`,
|
|
1255
|
-
` }`,
|
|
1256
|
-
` const script = new vm.Script(dummyCode, {`,
|
|
1257
|
-
` filename: filename,`,
|
|
1258
|
-
` lineOffset: 0,`,
|
|
1259
|
-
` displayErrors: true,`,
|
|
1260
|
-
` cachedData: bytecodeBuffer`,
|
|
1261
|
-
` });`,
|
|
1262
|
-
` if (script.cachedDataRejected) {`,
|
|
1263
|
-
` throw new Error("Invalid or incompatible cached data (cachedDataRejected)");`,
|
|
1264
|
-
` }`,
|
|
1265
|
-
` const require = function (id) {`,
|
|
1266
|
-
` return module.require(id);`,
|
|
1267
|
-
` };`,
|
|
1268
|
-
` require.resolve = function (request, options) {`,
|
|
1269
|
-
` return Module._resolveFilename(request, module, false, options);`,
|
|
1270
|
-
` };`,
|
|
1271
|
-
` if (process.mainModule) {`,
|
|
1272
|
-
` require.main = process.mainModule;`,
|
|
1273
|
-
` }`,
|
|
1274
|
-
` require.extensions = Module._extensions;`,
|
|
1275
|
-
` require.cache = Module._cache;`,
|
|
1276
|
-
` const compiledWrapper = script.runInThisContext({`,
|
|
1277
|
-
` filename: filename,`,
|
|
1278
|
-
` lineOffset: 0,`,
|
|
1279
|
-
` columnOffset: 0,`,
|
|
1280
|
-
` displayErrors: true`,
|
|
1281
|
-
` });`,
|
|
1282
|
-
` const dirname = path.dirname(filename);`,
|
|
1283
|
-
` const args = [module.exports, require, module, filename, dirname, process, global];`,
|
|
1284
|
-
` return compiledWrapper.apply(module.exports, args);`,
|
|
1285
|
-
`};`
|
|
1378
|
+
'"use strict";',
|
|
1379
|
+
'const fs = require("node:fs");',
|
|
1380
|
+
'const path = require("node:path");',
|
|
1381
|
+
'const vm = require("node:vm");',
|
|
1382
|
+
'const v8 = require("node:v8");',
|
|
1383
|
+
'const Module = require("node:module");',
|
|
1384
|
+
'v8.setFlagsFromString("--no-lazy");',
|
|
1385
|
+
'v8.setFlagsFromString("--no-flush-bytecode");',
|
|
1386
|
+
'const params = ["exports", "require", "module", "__filename", "__dirname"];',
|
|
1387
|
+
'Module._extensions[".jsc"] = Module._extensions[".cjsc"] = function (module, filename) {',
|
|
1388
|
+
' const data = fs.readFileSync(filename);',
|
|
1389
|
+
' if (data.length <= 28 || data.toString("ascii", 0, 8) !== "EVBC0001") {',
|
|
1390
|
+
' throw new Error("Invalid electron-vite bytecode format; rebuild the application: " + filename);',
|
|
1391
|
+
' }',
|
|
1392
|
+
' const length = data.readUInt32LE(8);',
|
|
1393
|
+
' const tag = "/*" + data.subarray(12, 28).toString("hex") + "*/";',
|
|
1394
|
+
' if (length < tag.length || length > 0x1fffffff) {',
|
|
1395
|
+
' throw new Error("Invalid bytecode source length: " + filename);',
|
|
1396
|
+
' }',
|
|
1397
|
+
' const placeholder = tag + " ".repeat(length - tag.length);',
|
|
1398
|
+
' const compiledWrapper = vm.compileFunction(placeholder, params, {',
|
|
1399
|
+
' filename,',
|
|
1400
|
+
' cachedData: data.subarray(28)',
|
|
1401
|
+
' });',
|
|
1402
|
+
' if (compiledWrapper.cachedDataRejected) {',
|
|
1403
|
+
' throw new Error("Invalid or incompatible cached data (cachedDataRejected): " + filename);',
|
|
1404
|
+
' }',
|
|
1405
|
+
' const require = function (id) { return module.require(id); };',
|
|
1406
|
+
' require.resolve = function (request, options) {',
|
|
1407
|
+
' return Module._resolveFilename(request, module, false, options);',
|
|
1408
|
+
' };',
|
|
1409
|
+
' if (process.mainModule) require.main = process.mainModule;',
|
|
1410
|
+
' require.extensions = Module._extensions;',
|
|
1411
|
+
' require.cache = Module._cache;',
|
|
1412
|
+
' return compiledWrapper.call(module.exports, module.exports, require, module, filename, path.dirname(filename));',
|
|
1413
|
+
'};'
|
|
1286
1414
|
];
|
|
1287
1415
|
const bytecodeChunkExtensionRE = /.(jsc|cjsc)$/;
|
|
1288
1416
|
/**
|
|
@@ -1309,12 +1437,13 @@ function bytecodePlugin(options = {}) {
|
|
|
1309
1437
|
}
|
|
1310
1438
|
const shouldTransformBytecodeChunk = plugins.length !== 0;
|
|
1311
1439
|
const _transform = (code, sourceMaps = false) => {
|
|
1312
|
-
const re = babel.
|
|
1440
|
+
const re = babel.transformSync(code, { plugins, sourceMaps });
|
|
1313
1441
|
return re ? { code: re.code || '', map: re.map } : null;
|
|
1314
1442
|
};
|
|
1315
1443
|
const useStrict = '"use strict";';
|
|
1316
1444
|
const bytecodeModuleLoader = 'bytecode-loader.cjs';
|
|
1317
1445
|
let supported = false;
|
|
1446
|
+
let isPreload = false;
|
|
1318
1447
|
return {
|
|
1319
1448
|
name: 'vite:bytecode',
|
|
1320
1449
|
apply: 'build',
|
|
@@ -1323,7 +1452,8 @@ function bytecodePlugin(options = {}) {
|
|
|
1323
1452
|
if (supported) {
|
|
1324
1453
|
return;
|
|
1325
1454
|
}
|
|
1326
|
-
|
|
1455
|
+
isPreload = config.plugins.some(p => p.name === 'vite:electron-preload-config-preset');
|
|
1456
|
+
const useInRenderer = config.plugins.some(p => p.name === 'vite:electron-renderer-config-preset');
|
|
1327
1457
|
if (useInRenderer) {
|
|
1328
1458
|
config.logger.warn(colors.yellow('bytecodePlugin does not support renderer.'));
|
|
1329
1459
|
return;
|
|
@@ -1364,76 +1494,91 @@ function bytecodePlugin(options = {}) {
|
|
|
1364
1494
|
};
|
|
1365
1495
|
let bytecodeChunkCount = 0;
|
|
1366
1496
|
const bundles = Object.keys(output);
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1497
|
+
const compiler = new ElectronCompiler({
|
|
1498
|
+
path: getElectronPath(),
|
|
1499
|
+
args: [getBytecodeCompilerPath()],
|
|
1500
|
+
env: { ELECTRON_VITE_RENDERER: isPreload ? '1' : '0' }
|
|
1501
|
+
});
|
|
1502
|
+
try {
|
|
1503
|
+
await compiler.start();
|
|
1504
|
+
for (const name of bundles) {
|
|
1505
|
+
const chunk = output[name];
|
|
1506
|
+
if (chunk.type === 'chunk') {
|
|
1507
|
+
let _code = chunk.code;
|
|
1508
|
+
if (bytecodeRE) {
|
|
1509
|
+
let match;
|
|
1510
|
+
let s;
|
|
1511
|
+
while ((match = bytecodeRE.exec(_code))) {
|
|
1512
|
+
s ||= new MagicString(_code);
|
|
1513
|
+
const [prefix, chunkName] = match;
|
|
1514
|
+
const len = prefix.length + chunkName.length;
|
|
1515
|
+
s.overwrite(match.index, match.index + len, prefix + chunkName + 'c', {
|
|
1516
|
+
contentOnly: true
|
|
1517
|
+
});
|
|
1518
|
+
}
|
|
1519
|
+
if (s) {
|
|
1520
|
+
_code = s.toString();
|
|
1521
|
+
}
|
|
1384
1522
|
}
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
const bytecodeBuffer = await compileToBytecode(_code);
|
|
1388
|
-
this.emitFile({
|
|
1389
|
-
type: 'asset',
|
|
1390
|
-
fileName: name + 'c',
|
|
1391
|
-
source: bytecodeBuffer
|
|
1392
|
-
});
|
|
1393
|
-
if (!removeBundleJS) {
|
|
1523
|
+
if (bytecodeChunks.includes(name)) {
|
|
1524
|
+
const bytecodeBuffer = await compileToBytecode(compiler, _code);
|
|
1394
1525
|
this.emitFile({
|
|
1395
1526
|
type: 'asset',
|
|
1396
|
-
fileName:
|
|
1397
|
-
source:
|
|
1527
|
+
fileName: name + 'c',
|
|
1528
|
+
source: bytecodeBuffer
|
|
1398
1529
|
});
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1530
|
+
if (!removeBundleJS) {
|
|
1531
|
+
this.emitFile({
|
|
1532
|
+
type: 'asset',
|
|
1533
|
+
fileName: '_' + chunk.fileName,
|
|
1534
|
+
source: chunk.code
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
if (chunk.isEntry) {
|
|
1538
|
+
const bytecodeLoaderBlock = getBytecodeLoaderBlock(chunk.fileName);
|
|
1539
|
+
const bytecodeModuleBlock = `require("./${path.basename(name) + 'c'}");`;
|
|
1540
|
+
const code = `${useStrict}\n${bytecodeLoaderBlock}\n${bytecodeModuleBlock}\n`;
|
|
1541
|
+
chunk.code = code;
|
|
1542
|
+
}
|
|
1543
|
+
else {
|
|
1544
|
+
delete output[chunk.fileName];
|
|
1545
|
+
}
|
|
1546
|
+
bytecodeChunkCount += 1;
|
|
1405
1547
|
}
|
|
1406
1548
|
else {
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1549
|
+
if (chunk.isEntry) {
|
|
1550
|
+
let hasBytecodeMoudle = false;
|
|
1551
|
+
const idsToHandle = new Set([...chunk.imports, ...chunk.dynamicImports]);
|
|
1552
|
+
for (const moduleId of idsToHandle) {
|
|
1553
|
+
if (bytecodeChunks.includes(moduleId)) {
|
|
1554
|
+
hasBytecodeMoudle = true;
|
|
1555
|
+
break;
|
|
1556
|
+
}
|
|
1557
|
+
const moduleInfo = this.getModuleInfo(moduleId);
|
|
1558
|
+
if (moduleInfo) {
|
|
1559
|
+
const { importers, dynamicImporters } = moduleInfo;
|
|
1560
|
+
for (const importerId of importers)
|
|
1561
|
+
idsToHandle.add(importerId);
|
|
1562
|
+
for (const importerId of dynamicImporters)
|
|
1563
|
+
idsToHandle.add(importerId);
|
|
1564
|
+
}
|
|
1419
1565
|
}
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
const
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
idsToHandle.add(importerId);
|
|
1566
|
+
if (hasBytecodeMoudle) {
|
|
1567
|
+
const loader = getBytecodeLoaderBlock(chunk.fileName);
|
|
1568
|
+
const strictRE = /^(#![^\n]*\n)?(["'])use strict\2;/;
|
|
1569
|
+
_code = strictRE.test(_code)
|
|
1570
|
+
? _code.replace(strictRE, `$&\n${loader}`)
|
|
1571
|
+
: _code.replace(/^(#![^\n]*\n)?/, `$&${loader}\n`);
|
|
1427
1572
|
}
|
|
1428
1573
|
}
|
|
1429
|
-
|
|
1430
|
-
? _code.replace(/("use strict";)|('use strict';)/, `${useStrict}\n${getBytecodeLoaderBlock(chunk.fileName)}`)
|
|
1431
|
-
: _code;
|
|
1574
|
+
chunk.code = _code;
|
|
1432
1575
|
}
|
|
1433
|
-
chunk.code = _code;
|
|
1434
1576
|
}
|
|
1435
1577
|
}
|
|
1436
|
-
}
|
|
1578
|
+
}
|
|
1579
|
+
finally {
|
|
1580
|
+
await compiler.stop();
|
|
1581
|
+
}
|
|
1437
1582
|
if (bytecodeChunkCount && !_chunks.some(ass => ass.type === 'asset' && ass.fileName === bytecodeModuleLoader)) {
|
|
1438
1583
|
this.emitFile({
|
|
1439
1584
|
type: 'asset',
|
|
@@ -1518,6 +1663,114 @@ function protectStringsPlugin(api) {
|
|
|
1518
1663
|
};
|
|
1519
1664
|
}
|
|
1520
1665
|
|
|
1666
|
+
const CONFIG_FILE_NAME = 'electron.vite.config';
|
|
1667
|
+
function findConfigFile(configRoot, extensions = ['js', 'ts', 'mjs', 'cjs', 'mts', 'cts']) {
|
|
1668
|
+
for (const ext of extensions) {
|
|
1669
|
+
const configFile = path.resolve(configRoot, `${CONFIG_FILE_NAME}.${ext}`);
|
|
1670
|
+
if (fs.existsSync(configFile)) {
|
|
1671
|
+
return configFile;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return '';
|
|
1675
|
+
}
|
|
1676
|
+
async function bundleConfigFile(fileName, isESM) {
|
|
1677
|
+
const dirnameVarName = '__electron_vite_injected_dirname';
|
|
1678
|
+
const filenameVarName = '__electron_vite_injected_filename';
|
|
1679
|
+
const importMetaUrlVarName = '__electron_vite_injected_import_meta_url';
|
|
1680
|
+
const bundle = await rolldown({
|
|
1681
|
+
input: path.resolve(fileName),
|
|
1682
|
+
platform: 'node',
|
|
1683
|
+
transform: {
|
|
1684
|
+
target: 'node20',
|
|
1685
|
+
define: {
|
|
1686
|
+
__dirname: dirnameVarName,
|
|
1687
|
+
__filename: filenameVarName,
|
|
1688
|
+
'import.meta.url': importMetaUrlVarName
|
|
1689
|
+
}
|
|
1690
|
+
},
|
|
1691
|
+
plugins: [
|
|
1692
|
+
{
|
|
1693
|
+
name: 'externalize-deps',
|
|
1694
|
+
resolveId(id) {
|
|
1695
|
+
if (id[0] !== '.' && !path.isAbsolute(id)) {
|
|
1696
|
+
return { id, external: true };
|
|
1697
|
+
}
|
|
1698
|
+
return null;
|
|
1699
|
+
}
|
|
1700
|
+
},
|
|
1701
|
+
{
|
|
1702
|
+
name: 'inject-file-scope-variables',
|
|
1703
|
+
transform: {
|
|
1704
|
+
filter: { id: /\.[cm]?[jt]s$/ },
|
|
1705
|
+
handler(code, id) {
|
|
1706
|
+
const injectValues = `const ${dirnameVarName} = ${JSON.stringify(path.dirname(id))};` +
|
|
1707
|
+
`const ${filenameVarName} = ${JSON.stringify(id)};` +
|
|
1708
|
+
`const ${importMetaUrlVarName} = ${JSON.stringify(pathToFileURL(id).href)};`;
|
|
1709
|
+
return { code: injectValues + code, map: null };
|
|
1710
|
+
}
|
|
1711
|
+
}
|
|
1712
|
+
}
|
|
1713
|
+
]
|
|
1714
|
+
});
|
|
1715
|
+
let result;
|
|
1716
|
+
try {
|
|
1717
|
+
result = await bundle.generate({
|
|
1718
|
+
format: isESM ? 'esm' : 'cjs',
|
|
1719
|
+
sourcemap: 'inline',
|
|
1720
|
+
sourcemapPathTransform(relative, sourcemapPath) {
|
|
1721
|
+
return path.resolve(path.dirname(sourcemapPath), relative);
|
|
1722
|
+
},
|
|
1723
|
+
codeSplitting: false
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
finally {
|
|
1727
|
+
await bundle.close();
|
|
1728
|
+
}
|
|
1729
|
+
const entryChunk = result.output.find((chunk) => chunk.type === 'chunk' && chunk.isEntry);
|
|
1730
|
+
if (!entryChunk) {
|
|
1731
|
+
throw new Error(`Failed to bundle config file: ${fileName}`);
|
|
1732
|
+
}
|
|
1733
|
+
return {
|
|
1734
|
+
code: entryChunk.code,
|
|
1735
|
+
dependencies: entryChunk.moduleIds.filter(id => !id.startsWith('\0'))
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
const _require = createRequire(import.meta.url);
|
|
1739
|
+
async function loadConfigFormBundledFile(fileName, bundledCode, isESM) {
|
|
1740
|
+
if (isESM) {
|
|
1741
|
+
const fileNameTmp = `${fileName}.${Date.now()}-${Math.random().toString(16).slice(2)}.mjs`;
|
|
1742
|
+
fs.writeFileSync(fileNameTmp, bundledCode);
|
|
1743
|
+
const fileUrl = pathToFileURL(fileNameTmp);
|
|
1744
|
+
try {
|
|
1745
|
+
return (await import(fileUrl.href)).default;
|
|
1746
|
+
}
|
|
1747
|
+
finally {
|
|
1748
|
+
try {
|
|
1749
|
+
fs.unlinkSync(fileNameTmp);
|
|
1750
|
+
}
|
|
1751
|
+
catch { }
|
|
1752
|
+
}
|
|
1753
|
+
}
|
|
1754
|
+
else {
|
|
1755
|
+
const extension = path.extname(fileName);
|
|
1756
|
+
const realFileName = fs.realpathSync(fileName);
|
|
1757
|
+
const loaderExt = extension in _require.extensions ? extension : '.js';
|
|
1758
|
+
const defaultLoader = _require.extensions[loaderExt];
|
|
1759
|
+
_require.extensions[loaderExt] = (module, filename) => {
|
|
1760
|
+
if (filename === realFileName) {
|
|
1761
|
+
module._compile(bundledCode, filename);
|
|
1762
|
+
}
|
|
1763
|
+
else {
|
|
1764
|
+
defaultLoader(module, filename);
|
|
1765
|
+
}
|
|
1766
|
+
};
|
|
1767
|
+
delete _require.cache[_require.resolve(fileName)];
|
|
1768
|
+
const raw = _require(fileName);
|
|
1769
|
+
_require.extensions[loaderExt] = defaultLoader;
|
|
1770
|
+
return raw.__esModule ? raw.default : raw;
|
|
1771
|
+
}
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1521
1774
|
function defineConfig(config) {
|
|
1522
1775
|
return config;
|
|
1523
1776
|
}
|
|
@@ -1574,7 +1827,7 @@ class ConfigFactory {
|
|
|
1574
1827
|
}
|
|
1575
1828
|
async build(cleanMode) {
|
|
1576
1829
|
/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
|
|
1577
|
-
const config = mergeConfig(
|
|
1830
|
+
const config = mergeConfig(cloneConfig(this.baseConfig), cloneConfig(this.inlineConfig));
|
|
1578
1831
|
config.mode = this.inlineConfig.mode || config.mode || process.env.NODE_ENV;
|
|
1579
1832
|
if (this.options.outDir) {
|
|
1580
1833
|
resetOutDir(config, this.options.outDir, this.processType());
|
|
@@ -1687,14 +1940,11 @@ async function resolveConfigDrivenPlugins(config) {
|
|
|
1687
1940
|
function isOptions(value) {
|
|
1688
1941
|
return typeof value === 'object' && value !== null;
|
|
1689
1942
|
}
|
|
1690
|
-
const CONFIG_FILE_NAME = 'electron.vite.config';
|
|
1691
1943
|
async function loadConfigFromFile(configEnv, configFile, configRoot = process.cwd(), logLevel, ignoreConfigWarning = false) {
|
|
1692
1944
|
if (configFile && /^vite.config.(js|ts|mjs|cjs|mts|cts)$/.test(configFile)) {
|
|
1693
1945
|
throw new Error(`config file cannot be named ${configFile}.`);
|
|
1694
1946
|
}
|
|
1695
|
-
const resolvedPath = configFile
|
|
1696
|
-
? path.resolve(configFile)
|
|
1697
|
-
: findConfigFile(configRoot, ['js', 'ts', 'mjs', 'cjs', 'mts', 'cts']);
|
|
1947
|
+
const resolvedPath = configFile ? path.resolve(configFile) : findConfigFile(configRoot);
|
|
1698
1948
|
if (!resolvedPath) {
|
|
1699
1949
|
return {
|
|
1700
1950
|
path: '',
|
|
@@ -1705,7 +1955,7 @@ async function loadConfigFromFile(configEnv, configFile, configRoot = process.cw
|
|
|
1705
1955
|
const isESM = isFilePathESM(resolvedPath);
|
|
1706
1956
|
try {
|
|
1707
1957
|
const { code, dependencies } = await bundleConfigFile(resolvedPath, isESM);
|
|
1708
|
-
const configExport = await loadConfigFormBundledFile(
|
|
1958
|
+
const configExport = await loadConfigFormBundledFile(resolvedPath, code, isESM);
|
|
1709
1959
|
const config = await (typeof configExport === 'function' ? configExport(configEnv) : configExport);
|
|
1710
1960
|
if (!isObject(config)) {
|
|
1711
1961
|
throw new Error(`config must export or return an object`);
|
|
@@ -1727,106 +1977,5 @@ async function loadConfigFromFile(configEnv, configFile, configRoot = process.cw
|
|
|
1727
1977
|
throw e;
|
|
1728
1978
|
}
|
|
1729
1979
|
}
|
|
1730
|
-
function findConfigFile(configRoot, extensions) {
|
|
1731
|
-
for (const ext of extensions) {
|
|
1732
|
-
const configFile = path.resolve(configRoot, `${CONFIG_FILE_NAME}.${ext}`);
|
|
1733
|
-
if (fs.existsSync(configFile)) {
|
|
1734
|
-
return configFile;
|
|
1735
|
-
}
|
|
1736
|
-
}
|
|
1737
|
-
return '';
|
|
1738
|
-
}
|
|
1739
|
-
async function bundleConfigFile(fileName, isESM) {
|
|
1740
|
-
const dirnameVarName = '__electron_vite_injected_dirname';
|
|
1741
|
-
const filenameVarName = '__electron_vite_injected_filename';
|
|
1742
|
-
const importMetaUrlVarName = '__electron_vite_injected_import_meta_url';
|
|
1743
|
-
const result = await build$1({
|
|
1744
|
-
absWorkingDir: process.cwd(),
|
|
1745
|
-
entryPoints: [fileName],
|
|
1746
|
-
write: false,
|
|
1747
|
-
target: ['node20'],
|
|
1748
|
-
platform: 'node',
|
|
1749
|
-
bundle: true,
|
|
1750
|
-
format: isESM ? 'esm' : 'cjs',
|
|
1751
|
-
sourcemap: false,
|
|
1752
|
-
metafile: true,
|
|
1753
|
-
define: {
|
|
1754
|
-
__dirname: dirnameVarName,
|
|
1755
|
-
__filename: filenameVarName,
|
|
1756
|
-
'import.meta.url': importMetaUrlVarName
|
|
1757
|
-
},
|
|
1758
|
-
plugins: [
|
|
1759
|
-
{
|
|
1760
|
-
name: 'externalize-deps',
|
|
1761
|
-
setup(build) {
|
|
1762
|
-
build.onResolve({ filter: /.*/ }, args => {
|
|
1763
|
-
const id = args.path;
|
|
1764
|
-
if (id[0] !== '.' && !path.isAbsolute(id)) {
|
|
1765
|
-
return {
|
|
1766
|
-
external: true
|
|
1767
|
-
};
|
|
1768
|
-
}
|
|
1769
|
-
return null;
|
|
1770
|
-
});
|
|
1771
|
-
}
|
|
1772
|
-
},
|
|
1773
|
-
{
|
|
1774
|
-
name: 'replace-import-meta',
|
|
1775
|
-
setup(build) {
|
|
1776
|
-
build.onLoad({ filter: /\.[cm]?[jt]s$/ }, async (args) => {
|
|
1777
|
-
const contents = await fs.promises.readFile(args.path, 'utf8');
|
|
1778
|
-
const injectValues = `const ${dirnameVarName} = ${JSON.stringify(path.dirname(args.path))};` +
|
|
1779
|
-
`const ${filenameVarName} = ${JSON.stringify(args.path)};` +
|
|
1780
|
-
`const ${importMetaUrlVarName} = ${JSON.stringify(pathToFileURL(args.path).href)};`;
|
|
1781
|
-
return {
|
|
1782
|
-
loader: args.path.endsWith('ts') ? 'ts' : 'js',
|
|
1783
|
-
contents: injectValues + contents
|
|
1784
|
-
};
|
|
1785
|
-
});
|
|
1786
|
-
}
|
|
1787
|
-
}
|
|
1788
|
-
]
|
|
1789
|
-
});
|
|
1790
|
-
const { text } = result.outputFiles[0];
|
|
1791
|
-
return {
|
|
1792
|
-
code: text,
|
|
1793
|
-
dependencies: result.metafile ? Object.keys(result.metafile.inputs) : []
|
|
1794
|
-
};
|
|
1795
|
-
}
|
|
1796
|
-
const _require = createRequire(import.meta.url);
|
|
1797
|
-
async function loadConfigFormBundledFile(configRoot, configFile, bundledCode, isESM) {
|
|
1798
|
-
if (isESM) {
|
|
1799
|
-
const fileNameTmp = path.resolve(configRoot, `${CONFIG_FILE_NAME}.${Date.now()}.mjs`);
|
|
1800
|
-
fs.writeFileSync(fileNameTmp, bundledCode);
|
|
1801
|
-
const fileUrl = pathToFileURL(fileNameTmp);
|
|
1802
|
-
try {
|
|
1803
|
-
return (await import(fileUrl.href)).default;
|
|
1804
|
-
}
|
|
1805
|
-
finally {
|
|
1806
|
-
try {
|
|
1807
|
-
fs.unlinkSync(fileNameTmp);
|
|
1808
|
-
}
|
|
1809
|
-
catch { }
|
|
1810
|
-
}
|
|
1811
|
-
}
|
|
1812
|
-
else {
|
|
1813
|
-
const extension = path.extname(configFile);
|
|
1814
|
-
const realFileName = fs.realpathSync(configFile);
|
|
1815
|
-
const loaderExt = extension in _require.extensions ? extension : '.js';
|
|
1816
|
-
const defaultLoader = _require.extensions[loaderExt];
|
|
1817
|
-
_require.extensions[loaderExt] = (module, filename) => {
|
|
1818
|
-
if (filename === realFileName) {
|
|
1819
|
-
module._compile(bundledCode, filename);
|
|
1820
|
-
}
|
|
1821
|
-
else {
|
|
1822
|
-
defaultLoader(module, filename);
|
|
1823
|
-
}
|
|
1824
|
-
};
|
|
1825
|
-
delete _require.cache[_require.resolve(configFile)];
|
|
1826
|
-
const raw = _require(configFile);
|
|
1827
|
-
_require.extensions[loaderExt] = defaultLoader;
|
|
1828
|
-
return raw.__esModule ? raw.default : raw;
|
|
1829
|
-
}
|
|
1830
|
-
}
|
|
1831
1980
|
|
|
1832
1981
|
export { ConfigFactory as C, MainConfigFactory as M, PreloadConfigFactory as P, RendererConfigFactory as R, loadEnv as a, bytecodePlugin as b, resolveHostname as c, defineConfig as d, externalizeDepsPlugin as e, loadConfigFromFile as l, resolveConfig as r, startElectron as s };
|
package/dist/cli.js
CHANGED
|
@@ -2,7 +2,7 @@ import { cac } from 'cac';
|
|
|
2
2
|
import colors from 'picocolors';
|
|
3
3
|
import { createLogger } from 'vite';
|
|
4
4
|
|
|
5
|
-
var version = "6.0.
|
|
5
|
+
var version = "6.0.2";
|
|
6
6
|
|
|
7
7
|
const cli = cac('electron-vite');
|
|
8
8
|
function createInlineConfig(root, options) {
|
|
@@ -61,7 +61,7 @@ cli
|
|
|
61
61
|
if (options.entry) {
|
|
62
62
|
process.env.ELECTRON_ENTRY = options.entry;
|
|
63
63
|
}
|
|
64
|
-
const { createServer } = await import('./chunks/lib-
|
|
64
|
+
const { createServer } = await import('./chunks/lib-DyA1RI3R.js');
|
|
65
65
|
const inlineConfig = createInlineConfig(root, options);
|
|
66
66
|
try {
|
|
67
67
|
await createServer(inlineConfig, { rendererOnly: options.rendererOnly });
|
|
@@ -74,7 +74,7 @@ cli
|
|
|
74
74
|
});
|
|
75
75
|
// build
|
|
76
76
|
cli.command('build [root]', 'build for production').action(async (root, options) => {
|
|
77
|
-
const { build } = await import('./chunks/lib-
|
|
77
|
+
const { build } = await import('./chunks/lib-DaHzt8UE.js');
|
|
78
78
|
const inlineConfig = createInlineConfig(root, options);
|
|
79
79
|
if (options.entry) {
|
|
80
80
|
process.env.ELECTRON_ENTRY = options.entry;
|
|
@@ -94,7 +94,7 @@ cli
|
|
|
94
94
|
.option('--noSandbox', `[boolean] forces renderer process to run un-sandboxed`)
|
|
95
95
|
.option('--skipBuild', `[boolean] skip build`)
|
|
96
96
|
.action(async (root, options) => {
|
|
97
|
-
const { preview } = await import('./chunks/lib-
|
|
97
|
+
const { preview } = await import('./chunks/lib-ShkGlprt.js');
|
|
98
98
|
const inlineConfig = createInlineConfig(root, options);
|
|
99
99
|
if (options.noSandbox) {
|
|
100
100
|
process.env.NO_SANDBOX = '1';
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { createFilter } from 'vite';
|
|
2
2
|
export { createLogger, defineConfig as defineViteConfig, mergeConfig } from 'vite';
|
|
3
|
-
export { C as ConfigFactory, M as MainConfigFactory, P as PreloadConfigFactory, R as RendererConfigFactory, b as bytecodePlugin, d as defineConfig, e as externalizeDepsPlugin, l as loadConfigFromFile, a as loadEnv, r as resolveConfig } from './chunks/lib-
|
|
4
|
-
export { createServer } from './chunks/lib-
|
|
5
|
-
export { build } from './chunks/lib-
|
|
6
|
-
export { preview } from './chunks/lib-
|
|
3
|
+
export { C as ConfigFactory, M as MainConfigFactory, P as PreloadConfigFactory, R as RendererConfigFactory, b as bytecodePlugin, d as defineConfig, e as externalizeDepsPlugin, l as loadConfigFromFile, a as loadEnv, r as resolveConfig } from './chunks/lib-wmKiubLV.js';
|
|
4
|
+
export { createServer } from './chunks/lib-DyA1RI3R.js';
|
|
5
|
+
export { build } from './chunks/lib-DaHzt8UE.js';
|
|
6
|
+
export { preview } from './chunks/lib-ShkGlprt.js';
|
|
7
7
|
import { createRequire } from 'node:module';
|
|
8
8
|
import 'node:path';
|
|
9
|
-
import 'node:fs';
|
|
10
|
-
import 'node:url';
|
|
11
9
|
import 'picocolors';
|
|
12
|
-
import '
|
|
10
|
+
import 'node:fs';
|
|
13
11
|
import 'node:child_process';
|
|
14
12
|
import 'node:crypto';
|
|
15
13
|
import 'node:fs/promises';
|
|
16
14
|
import 'magic-string';
|
|
17
15
|
import '@babel/core';
|
|
16
|
+
import 'node:url';
|
|
17
|
+
import 'rolldown';
|
|
18
18
|
|
|
19
19
|
async function transformWithSWC(code, id, options) {
|
|
20
20
|
const { sourcemap = false, minify = false } = options;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@snoirtrom/electron-vite",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"registry": "https://registry.npmjs.org/"
|
|
6
6
|
},
|
|
@@ -76,36 +76,35 @@
|
|
|
76
76
|
"@rollup/plugin-json": "^6.1.0",
|
|
77
77
|
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
78
78
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
79
|
-
"@swc/core": "^1.
|
|
79
|
+
"@swc/core": "^1.16.2",
|
|
80
80
|
"@types/babel__core": "^7.20.5",
|
|
81
|
-
"@types/node": "^22.
|
|
82
|
-
"eslint": "^10.
|
|
81
|
+
"@types/node": "^22.20.4",
|
|
82
|
+
"eslint": "^10.11.0",
|
|
83
83
|
"eslint-config-prettier": "^10.1.8",
|
|
84
|
-
"eslint-plugin-prettier": "^5.5.
|
|
85
|
-
"globals": "^17.
|
|
86
|
-
"lint-staged": "^
|
|
87
|
-
"prettier": "^3.
|
|
88
|
-
"rollup": "^4.
|
|
89
|
-
"rollup-plugin-dts": "^6.
|
|
84
|
+
"eslint-plugin-prettier": "^5.5.6",
|
|
85
|
+
"globals": "^17.12.0",
|
|
86
|
+
"lint-staged": "^17.5.1",
|
|
87
|
+
"prettier": "^3.9.9",
|
|
88
|
+
"rollup": "^4.63.5",
|
|
89
|
+
"rollup-plugin-dts": "^6.5.1",
|
|
90
90
|
"rollup-plugin-rm": "^1.0.2",
|
|
91
|
-
"simple-git-hooks": "^2.
|
|
91
|
+
"simple-git-hooks": "^2.14.0",
|
|
92
92
|
"tslib": "^2.8.1",
|
|
93
|
-
"typescript": "^
|
|
94
|
-
"typescript-eslint": "^8.
|
|
95
|
-
"vite": "^8.
|
|
93
|
+
"typescript": "^6.0.3",
|
|
94
|
+
"typescript-eslint": "^8.70.1",
|
|
95
|
+
"vite": "^8.3.1"
|
|
96
96
|
},
|
|
97
97
|
"dependencies": {
|
|
98
|
-
"@babel/core": "^7.29.
|
|
99
|
-
"@babel/plugin-transform-arrow-functions": "^7.
|
|
98
|
+
"@babel/core": "^7.29.7",
|
|
99
|
+
"@babel/plugin-transform-arrow-functions": "^7.29.7",
|
|
100
100
|
"cac": "^7.0.0",
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
"
|
|
101
|
+
"magic-string": "^1.4.2",
|
|
102
|
+
"picocolors": "^1.1.1",
|
|
103
|
+
"rolldown": "~1.2.10"
|
|
104
104
|
},
|
|
105
105
|
"pnpm": {
|
|
106
106
|
"onlyBuiltDependencies": [
|
|
107
107
|
"@swc/core",
|
|
108
|
-
"esbuild",
|
|
109
108
|
"simple-git-hooks"
|
|
110
109
|
]
|
|
111
110
|
}
|