electrobun 0.0.19-beta.7 → 0.0.19-beta.71
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/BUILD.md +90 -0
- package/bin/electrobun.cjs +165 -0
- package/debug.js +5 -0
- package/dist/api/browser/builtinrpcSchema.ts +19 -0
- package/dist/api/browser/index.ts +409 -0
- package/dist/api/browser/rpc/webview.ts +79 -0
- package/dist/api/browser/stylesAndElements.ts +3 -0
- package/dist/api/browser/webviewtag.ts +534 -0
- package/dist/api/bun/core/ApplicationMenu.ts +66 -0
- package/dist/api/bun/core/BrowserView.ts +349 -0
- package/dist/api/bun/core/BrowserWindow.ts +191 -0
- package/dist/api/bun/core/ContextMenu.ts +67 -0
- package/dist/api/bun/core/Paths.ts +5 -0
- package/dist/api/bun/core/Socket.ts +181 -0
- package/dist/api/bun/core/Tray.ts +107 -0
- package/dist/api/bun/core/Updater.ts +395 -0
- package/dist/api/bun/core/Utils.ts +48 -0
- package/dist/api/bun/events/ApplicationEvents.ts +14 -0
- package/dist/api/bun/events/event.ts +29 -0
- package/dist/api/bun/events/eventEmitter.ts +45 -0
- package/dist/api/bun/events/trayEvents.ts +9 -0
- package/dist/api/bun/events/webviewEvents.ts +16 -0
- package/dist/api/bun/events/windowEvents.ts +12 -0
- package/dist/api/bun/index.ts +45 -0
- package/dist/api/bun/proc/linux.md +43 -0
- package/dist/api/bun/proc/native.ts +1217 -0
- package/dist/api/shared/platform.ts +48 -0
- package/dist/main.js +12 -0
- package/package.json +13 -7
- package/src/cli/index.ts +621 -203
- package/templates/hello-world/README.md +57 -0
- package/templates/hello-world/bun.lock +63 -0
- package/templates/hello-world/electrobun.config +17 -0
- package/templates/hello-world/package.json +16 -0
- package/templates/hello-world/src/bun/index.ts +15 -0
- package/templates/hello-world/src/mainview/index.css +124 -0
- package/templates/hello-world/src/mainview/index.html +47 -0
- package/templates/hello-world/src/mainview/index.ts +5 -0
- package/bin/electrobun +0 -0
package/src/cli/index.ts
CHANGED
|
@@ -2,48 +2,23 @@ import { join, dirname, basename } from "path";
|
|
|
2
2
|
import {
|
|
3
3
|
existsSync,
|
|
4
4
|
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
5
6
|
cpSync,
|
|
6
7
|
rmdirSync,
|
|
7
8
|
mkdirSync,
|
|
8
9
|
createWriteStream,
|
|
9
10
|
unlinkSync,
|
|
11
|
+
readdirSync,
|
|
10
12
|
} from "fs";
|
|
11
13
|
import { execSync } from "child_process";
|
|
12
14
|
import tar from "tar";
|
|
13
15
|
import { ZstdInit } from "@oneidentity/zstd-js/wasm";
|
|
14
|
-
import {
|
|
16
|
+
import { OS, ARCH } from '../shared/platform';
|
|
17
|
+
import { getTemplate, getTemplateNames } from './templates/embedded';
|
|
15
18
|
// import { loadBsdiff, loadBspatch } from 'bsdiff-wasm';
|
|
16
19
|
// MacOS named pipes hang at around 4KB
|
|
17
20
|
const MAX_CHUNK_SIZE = 1024 * 2;
|
|
18
21
|
|
|
19
|
-
// TODO: dedup with built.ts
|
|
20
|
-
const OS: 'win' | 'linux' | 'macos' = getPlatform();
|
|
21
|
-
const ARCH: 'arm64' | 'x64' = getArch();
|
|
22
|
-
|
|
23
|
-
function getPlatform() {
|
|
24
|
-
switch (platform()) {
|
|
25
|
-
case "win32":
|
|
26
|
-
return 'win';
|
|
27
|
-
case "darwin":
|
|
28
|
-
return 'macos';
|
|
29
|
-
case 'linux':
|
|
30
|
-
return 'linux';
|
|
31
|
-
default:
|
|
32
|
-
throw 'unsupported platform';
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function getArch() {
|
|
37
|
-
switch (arch()) {
|
|
38
|
-
case "arm64":
|
|
39
|
-
return 'arm64';
|
|
40
|
-
case "x64":
|
|
41
|
-
return 'x64';
|
|
42
|
-
default:
|
|
43
|
-
throw 'unsupported arch'
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
22
|
|
|
48
23
|
const binExt = OS === 'win' ? '.exe' : '';
|
|
49
24
|
|
|
@@ -56,48 +31,88 @@ const configPath = join(projectRoot, configName);
|
|
|
56
31
|
const indexOfElectrobun = process.argv.findIndex((arg) =>
|
|
57
32
|
arg.includes("electrobun")
|
|
58
33
|
);
|
|
59
|
-
const commandArg = process.argv[indexOfElectrobun + 1] || "
|
|
34
|
+
const commandArg = process.argv[indexOfElectrobun + 1] || "build";
|
|
60
35
|
|
|
61
36
|
const ELECTROBUN_DEP_PATH = join(projectRoot, "node_modules", "electrobun");
|
|
62
37
|
|
|
63
38
|
// When debugging electrobun with the example app use the builds (dev or release) right from the source folder
|
|
64
39
|
// For developers using electrobun cli via npm use the release versions in /dist
|
|
65
40
|
// This lets us not have to commit src build folders to git and provide pre-built binaries
|
|
66
|
-
const PATHS = {
|
|
67
|
-
BUN_BINARY: join(ELECTROBUN_DEP_PATH, "dist", "bun") + binExt,
|
|
68
|
-
LAUNCHER_DEV: join(ELECTROBUN_DEP_PATH, "dist", "electrobun") + binExt,
|
|
69
|
-
LAUNCHER_RELEASE: join(ELECTROBUN_DEP_PATH, "dist", "launcher") + binExt,
|
|
70
|
-
MAIN_JS: join(ELECTROBUN_DEP_PATH, "dist", "main.js"),
|
|
71
|
-
NATIVE_WRAPPER_MACOS: join(
|
|
72
|
-
ELECTROBUN_DEP_PATH,
|
|
73
|
-
"dist",
|
|
74
|
-
"libNativeWrapper.dylib"
|
|
75
|
-
),
|
|
76
|
-
NATIVE_WRAPPER_WIN: join(ELECTROBUN_DEP_PATH, "dist", "libNativeWrapper.dll"),
|
|
77
|
-
NATIVE_WRAPPER_LINUX: join(ELECTROBUN_DEP_PATH, "dist", "libNativeWrapper.so"),
|
|
78
|
-
WEBVIEW2LOADER_WIN: join(ELECTROBUN_DEP_PATH, "dist", "WebView2Loader.dll"),
|
|
79
|
-
BSPATCH: join(ELECTROBUN_DEP_PATH, "dist", "bspatch") + binExt,
|
|
80
|
-
EXTRACTOR: join(ELECTROBUN_DEP_PATH, "dist", "extractor") + binExt,
|
|
81
|
-
BSDIFF: join(ELECTROBUN_DEP_PATH, "dist", "bsdiff") + binExt,
|
|
82
|
-
CEF_FRAMEWORK_MACOS: join(
|
|
83
|
-
ELECTROBUN_DEP_PATH,
|
|
84
|
-
"dist",
|
|
85
|
-
"cef",
|
|
86
|
-
"Chromium Embedded Framework.framework"
|
|
87
|
-
),
|
|
88
|
-
CEF_HELPER_MACOS: join(ELECTROBUN_DEP_PATH, "dist", "cef", "process_helper"),
|
|
89
|
-
CEF_HELPER_WIN: join(ELECTROBUN_DEP_PATH, "dist", "cef", "process_helper.exe"),
|
|
90
|
-
CEF_HELPER_LINUX: join(ELECTROBUN_DEP_PATH, "dist", "cef", "process_helper"),
|
|
91
|
-
CEF_DIR: join(ELECTROBUN_DEP_PATH, "dist", "cef"),
|
|
92
|
-
};
|
|
93
41
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
42
|
+
// Function to get platform-specific paths
|
|
43
|
+
function getPlatformPaths(targetOS: 'macos' | 'win' | 'linux', targetArch: 'arm64' | 'x64') {
|
|
44
|
+
const binExt = targetOS === 'win' ? '.exe' : '';
|
|
45
|
+
const platformDistDir = join(ELECTROBUN_DEP_PATH, `dist-${targetOS}-${targetArch}`);
|
|
46
|
+
const sharedDistDir = join(ELECTROBUN_DEP_PATH, "dist");
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
// Platform-specific binaries (from dist-OS-ARCH/)
|
|
50
|
+
BUN_BINARY: join(platformDistDir, "bun") + binExt,
|
|
51
|
+
LAUNCHER_DEV: join(platformDistDir, "electrobun") + binExt,
|
|
52
|
+
LAUNCHER_RELEASE: join(platformDistDir, "launcher") + binExt,
|
|
53
|
+
NATIVE_WRAPPER_MACOS: join(platformDistDir, "libNativeWrapper.dylib"),
|
|
54
|
+
NATIVE_WRAPPER_WIN: join(platformDistDir, "libNativeWrapper.dll"),
|
|
55
|
+
NATIVE_WRAPPER_LINUX: join(platformDistDir, "libNativeWrapper.so"),
|
|
56
|
+
NATIVE_WRAPPER_LINUX_CEF: join(platformDistDir, "libNativeWrapper_cef.so"),
|
|
57
|
+
WEBVIEW2LOADER_WIN: join(platformDistDir, "WebView2Loader.dll"),
|
|
58
|
+
BSPATCH: join(platformDistDir, "bspatch") + binExt,
|
|
59
|
+
EXTRACTOR: join(platformDistDir, "extractor") + binExt,
|
|
60
|
+
BSDIFF: join(platformDistDir, "bsdiff") + binExt,
|
|
61
|
+
CEF_FRAMEWORK_MACOS: join(platformDistDir, "cef", "Chromium Embedded Framework.framework"),
|
|
62
|
+
CEF_HELPER_MACOS: join(platformDistDir, "cef", "process_helper"),
|
|
63
|
+
CEF_HELPER_WIN: join(platformDistDir, "cef", "process_helper.exe"),
|
|
64
|
+
CEF_HELPER_LINUX: join(platformDistDir, "cef", "process_helper"),
|
|
65
|
+
CEF_DIR: join(platformDistDir, "cef"),
|
|
66
|
+
|
|
67
|
+
// Shared platform-independent files (from dist/)
|
|
68
|
+
// These work with existing package.json and development workflow
|
|
69
|
+
MAIN_JS: join(sharedDistDir, "main.js"),
|
|
70
|
+
API_DIR: join(sharedDistDir, "api"),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Default PATHS for host platform (backward compatibility)
|
|
75
|
+
const PATHS = getPlatformPaths(OS, ARCH);
|
|
76
|
+
|
|
77
|
+
async function ensureCoreDependencies(targetOS?: 'macos' | 'win' | 'linux', targetArch?: 'arm64' | 'x64') {
|
|
78
|
+
// Use provided target platform or default to host platform
|
|
79
|
+
const platformOS = targetOS || OS;
|
|
80
|
+
const platformArch = targetArch || ARCH;
|
|
81
|
+
|
|
82
|
+
// Get platform-specific paths
|
|
83
|
+
const platformPaths = getPlatformPaths(platformOS, platformArch);
|
|
84
|
+
|
|
85
|
+
// Check platform-specific binaries
|
|
86
|
+
const requiredBinaries = [
|
|
87
|
+
platformPaths.BUN_BINARY,
|
|
88
|
+
platformPaths.LAUNCHER_RELEASE,
|
|
89
|
+
// Platform-specific native wrapper
|
|
90
|
+
platformOS === 'macos' ? platformPaths.NATIVE_WRAPPER_MACOS :
|
|
91
|
+
platformOS === 'win' ? platformPaths.NATIVE_WRAPPER_WIN :
|
|
92
|
+
platformPaths.NATIVE_WRAPPER_LINUX
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
// Check shared files (main.js should be in shared dist/)
|
|
96
|
+
const requiredSharedFiles = [
|
|
97
|
+
platformPaths.MAIN_JS
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const missingBinaries = requiredBinaries.filter(file => !existsSync(file));
|
|
101
|
+
const missingSharedFiles = requiredSharedFiles.filter(file => !existsSync(file));
|
|
102
|
+
|
|
103
|
+
// If only shared files are missing, that's expected in production (they come via npm)
|
|
104
|
+
if (missingBinaries.length === 0 && missingSharedFiles.length > 0) {
|
|
105
|
+
console.log(`Shared files missing (expected in production): ${missingSharedFiles.map(f => f.replace(ELECTROBUN_DEP_PATH, '.')).join(', ')}`);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Only download if platform-specific binaries are missing
|
|
109
|
+
if (missingBinaries.length === 0) {
|
|
97
110
|
return;
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
|
|
113
|
+
// Show which binaries are missing
|
|
114
|
+
console.log(`Core dependencies not found for ${platformOS}-${platformArch}. Missing files:`, missingBinaries.map(f => f.replace(ELECTROBUN_DEP_PATH, '.')).join(', '));
|
|
115
|
+
console.log(`Downloading core binaries for ${platformOS}-${platformArch}...`);
|
|
101
116
|
|
|
102
117
|
// Get the current Electrobun version from package.json
|
|
103
118
|
const packageJsonPath = join(ELECTROBUN_DEP_PATH, 'package.json');
|
|
@@ -112,61 +127,153 @@ async function ensureCoreDependencies() {
|
|
|
112
127
|
}
|
|
113
128
|
}
|
|
114
129
|
|
|
115
|
-
const platformName =
|
|
116
|
-
const archName =
|
|
117
|
-
const
|
|
130
|
+
const platformName = platformOS === 'macos' ? 'darwin' : platformOS === 'win' ? 'win' : 'linux';
|
|
131
|
+
const archName = platformArch;
|
|
132
|
+
const coreTarballUrl = `https://github.com/blackboardsh/electrobun/releases/download/${version}/electrobun-core-${platformName}-${archName}.tar.gz`;
|
|
118
133
|
|
|
119
|
-
console.log(`Downloading core binaries from: ${
|
|
134
|
+
console.log(`Downloading core binaries from: ${coreTarballUrl}`);
|
|
120
135
|
|
|
121
136
|
try {
|
|
122
|
-
// Download
|
|
123
|
-
const response = await fetch(
|
|
137
|
+
// Download core binaries tarball
|
|
138
|
+
const response = await fetch(coreTarballUrl);
|
|
124
139
|
if (!response.ok) {
|
|
125
140
|
throw new Error(`Failed to download binaries: ${response.status} ${response.statusText}`);
|
|
126
141
|
}
|
|
127
142
|
|
|
128
143
|
// Create temp file
|
|
129
|
-
const tempFile = join(ELECTROBUN_DEP_PATH,
|
|
144
|
+
const tempFile = join(ELECTROBUN_DEP_PATH, `core-${platformOS}-${platformArch}-temp.tar.gz`);
|
|
130
145
|
const fileStream = createWriteStream(tempFile);
|
|
131
146
|
|
|
132
147
|
// Write response to file
|
|
133
148
|
if (response.body) {
|
|
134
149
|
const reader = response.body.getReader();
|
|
150
|
+
let totalBytes = 0;
|
|
135
151
|
while (true) {
|
|
136
152
|
const { done, value } = await reader.read();
|
|
137
153
|
if (done) break;
|
|
138
|
-
|
|
154
|
+
const buffer = Buffer.from(value);
|
|
155
|
+
fileStream.write(buffer);
|
|
156
|
+
totalBytes += buffer.length;
|
|
139
157
|
}
|
|
158
|
+
console.log(`Downloaded ${totalBytes} bytes for ${platformOS}-${platformArch}`);
|
|
140
159
|
}
|
|
141
|
-
fileStream.end();
|
|
142
160
|
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
161
|
+
// Ensure file is properly closed before proceeding
|
|
162
|
+
await new Promise((resolve, reject) => {
|
|
163
|
+
fileStream.end((err) => {
|
|
164
|
+
if (err) reject(err);
|
|
165
|
+
else resolve(null);
|
|
166
|
+
});
|
|
148
167
|
});
|
|
149
168
|
|
|
169
|
+
// Verify the downloaded file exists and has content
|
|
170
|
+
if (!existsSync(tempFile)) {
|
|
171
|
+
throw new Error(`Downloaded file not found: ${tempFile}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const fileSize = require('fs').statSync(tempFile).size;
|
|
175
|
+
if (fileSize === 0) {
|
|
176
|
+
throw new Error(`Downloaded file is empty: ${tempFile}`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
console.log(`Verified download: ${tempFile} (${fileSize} bytes)`);
|
|
180
|
+
|
|
181
|
+
// Extract to platform-specific dist directory
|
|
182
|
+
console.log(`Extracting core dependencies for ${platformOS}-${platformArch}...`);
|
|
183
|
+
const platformDistPath = join(ELECTROBUN_DEP_PATH, `dist-${platformOS}-${platformArch}`);
|
|
184
|
+
mkdirSync(platformDistPath, { recursive: true });
|
|
185
|
+
|
|
186
|
+
// Use Windows native tar.exe on Windows due to npm tar library issues
|
|
187
|
+
if (OS === 'win') {
|
|
188
|
+
console.log('Using Windows native tar.exe for reliable extraction...');
|
|
189
|
+
execSync(`tar -xf "${tempFile}" -C "${platformDistPath}"`, {
|
|
190
|
+
stdio: 'inherit',
|
|
191
|
+
cwd: platformDistPath
|
|
192
|
+
});
|
|
193
|
+
} else {
|
|
194
|
+
await tar.x({
|
|
195
|
+
file: tempFile,
|
|
196
|
+
cwd: platformDistPath,
|
|
197
|
+
preservePaths: false,
|
|
198
|
+
strip: 0,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// NOTE: We no longer copy main.js from platform-specific downloads
|
|
203
|
+
// Platform-specific downloads should only contain native binaries
|
|
204
|
+
// main.js and api/ should be shipped via npm in the shared dist/ folder
|
|
205
|
+
|
|
150
206
|
// Clean up temp file
|
|
151
207
|
unlinkSync(tempFile);
|
|
152
208
|
|
|
153
|
-
|
|
209
|
+
// Debug: List what was actually extracted
|
|
210
|
+
try {
|
|
211
|
+
const extractedFiles = readdirSync(platformDistPath);
|
|
212
|
+
console.log(`Extracted files to ${platformDistPath}:`, extractedFiles);
|
|
213
|
+
|
|
214
|
+
// Check if files are in subdirectories
|
|
215
|
+
for (const file of extractedFiles) {
|
|
216
|
+
const filePath = join(platformDistPath, file);
|
|
217
|
+
const stat = require('fs').statSync(filePath);
|
|
218
|
+
if (stat.isDirectory()) {
|
|
219
|
+
const subFiles = readdirSync(filePath);
|
|
220
|
+
console.log(` ${file}/: ${subFiles.join(', ')}`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
} catch (e) {
|
|
224
|
+
console.error('Could not list extracted files:', e);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Verify extraction completed successfully - check platform-specific binaries only
|
|
228
|
+
const requiredBinaries = [
|
|
229
|
+
platformPaths.BUN_BINARY,
|
|
230
|
+
platformPaths.LAUNCHER_RELEASE,
|
|
231
|
+
platformOS === 'macos' ? platformPaths.NATIVE_WRAPPER_MACOS :
|
|
232
|
+
platformOS === 'win' ? platformPaths.NATIVE_WRAPPER_WIN :
|
|
233
|
+
platformPaths.NATIVE_WRAPPER_LINUX
|
|
234
|
+
];
|
|
235
|
+
|
|
236
|
+
const missingBinaries = requiredBinaries.filter(file => !existsSync(file));
|
|
237
|
+
if (missingBinaries.length > 0) {
|
|
238
|
+
console.error(`Missing binaries after extraction: ${missingBinaries.map(f => f.replace(ELECTROBUN_DEP_PATH, '.')).join(', ')}`);
|
|
239
|
+
console.error('This suggests the tarball structure is different than expected');
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// For development: if main.js doesn't exist in shared dist/, copy from platform-specific download as fallback
|
|
243
|
+
const sharedDistPath = join(ELECTROBUN_DEP_PATH, 'dist');
|
|
244
|
+
const extractedMainJs = join(platformDistPath, 'main.js');
|
|
245
|
+
const sharedMainJs = join(sharedDistPath, 'main.js');
|
|
246
|
+
|
|
247
|
+
if (existsSync(extractedMainJs) && !existsSync(sharedMainJs)) {
|
|
248
|
+
console.log('Development fallback: copying main.js from platform-specific download to shared dist/');
|
|
249
|
+
mkdirSync(sharedDistPath, { recursive: true });
|
|
250
|
+
cpSync(extractedMainJs, sharedMainJs);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
console.log(`Core dependencies for ${platformOS}-${platformArch} downloaded and cached successfully`);
|
|
154
254
|
|
|
155
|
-
} catch (error) {
|
|
156
|
-
console.error(
|
|
255
|
+
} catch (error: any) {
|
|
256
|
+
console.error(`Failed to download core dependencies for ${platformOS}-${platformArch}:`, error.message);
|
|
157
257
|
console.error('Please ensure you have an internet connection and the release exists.');
|
|
158
258
|
process.exit(1);
|
|
159
259
|
}
|
|
160
260
|
}
|
|
161
261
|
|
|
162
|
-
async function ensureCEFDependencies() {
|
|
262
|
+
async function ensureCEFDependencies(targetOS?: 'macos' | 'win' | 'linux', targetArch?: 'arm64' | 'x64') {
|
|
263
|
+
// Use provided target platform or default to host platform
|
|
264
|
+
const platformOS = targetOS || OS;
|
|
265
|
+
const platformArch = targetArch || ARCH;
|
|
266
|
+
|
|
267
|
+
// Get platform-specific paths
|
|
268
|
+
const platformPaths = getPlatformPaths(platformOS, platformArch);
|
|
269
|
+
|
|
163
270
|
// Check if CEF dependencies already exist
|
|
164
|
-
if (existsSync(
|
|
165
|
-
console.log(
|
|
271
|
+
if (existsSync(platformPaths.CEF_DIR)) {
|
|
272
|
+
console.log(`CEF dependencies found for ${platformOS}-${platformArch}, using cached version`);
|
|
166
273
|
return;
|
|
167
274
|
}
|
|
168
275
|
|
|
169
|
-
console.log(
|
|
276
|
+
console.log(`CEF dependencies not found for ${platformOS}-${platformArch}, downloading...`);
|
|
170
277
|
|
|
171
278
|
// Get the current Electrobun version from package.json
|
|
172
279
|
const packageJsonPath = join(ELECTROBUN_DEP_PATH, 'package.json');
|
|
@@ -181,8 +288,8 @@ async function ensureCEFDependencies() {
|
|
|
181
288
|
}
|
|
182
289
|
}
|
|
183
290
|
|
|
184
|
-
const platformName =
|
|
185
|
-
const archName =
|
|
291
|
+
const platformName = platformOS === 'macos' ? 'darwin' : platformOS === 'win' ? 'win' : 'linux';
|
|
292
|
+
const archName = platformArch;
|
|
186
293
|
const cefTarballUrl = `https://github.com/blackboardsh/electrobun/releases/download/${version}/electrobun-cef-${platformName}-${archName}.tar.gz`;
|
|
187
294
|
|
|
188
295
|
console.log(`Downloading CEF from: ${cefTarballUrl}`);
|
|
@@ -195,7 +302,7 @@ async function ensureCEFDependencies() {
|
|
|
195
302
|
}
|
|
196
303
|
|
|
197
304
|
// Create temp file
|
|
198
|
-
const tempFile = join(ELECTROBUN_DEP_PATH,
|
|
305
|
+
const tempFile = join(ELECTROBUN_DEP_PATH, `cef-${platformOS}-${platformArch}-temp.tar.gz`);
|
|
199
306
|
const fileStream = createWriteStream(tempFile);
|
|
200
307
|
|
|
201
308
|
// Write response to file
|
|
@@ -209,20 +316,49 @@ async function ensureCEFDependencies() {
|
|
|
209
316
|
}
|
|
210
317
|
fileStream.end();
|
|
211
318
|
|
|
212
|
-
// Extract to dist directory
|
|
213
|
-
console.log(
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
319
|
+
// Extract to platform-specific dist directory
|
|
320
|
+
console.log(`Extracting CEF dependencies for ${platformOS}-${platformArch}...`);
|
|
321
|
+
const platformDistPath = join(ELECTROBUN_DEP_PATH, `dist-${platformOS}-${platformArch}`);
|
|
322
|
+
mkdirSync(platformDistPath, { recursive: true });
|
|
323
|
+
|
|
324
|
+
// Use Windows native tar.exe on Windows due to npm tar library issues
|
|
325
|
+
if (OS === 'win') {
|
|
326
|
+
console.log('Using Windows native tar.exe for reliable extraction...');
|
|
327
|
+
execSync(`tar -xf "${tempFile}" -C "${platformDistPath}"`, {
|
|
328
|
+
stdio: 'inherit',
|
|
329
|
+
cwd: platformDistPath
|
|
330
|
+
});
|
|
331
|
+
} else {
|
|
332
|
+
await tar.x({
|
|
333
|
+
file: tempFile,
|
|
334
|
+
cwd: platformDistPath,
|
|
335
|
+
preservePaths: false,
|
|
336
|
+
strip: 0,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
218
339
|
|
|
219
340
|
// Clean up temp file
|
|
220
341
|
unlinkSync(tempFile);
|
|
221
342
|
|
|
222
|
-
|
|
343
|
+
// Debug: List what was actually extracted for CEF
|
|
344
|
+
try {
|
|
345
|
+
const extractedFiles = readdirSync(platformDistPath);
|
|
346
|
+
console.log(`CEF extracted files to ${platformDistPath}:`, extractedFiles);
|
|
347
|
+
|
|
348
|
+
// Check if CEF directory was created
|
|
349
|
+
const cefDir = join(platformDistPath, 'cef');
|
|
350
|
+
if (existsSync(cefDir)) {
|
|
351
|
+
const cefFiles = readdirSync(cefDir);
|
|
352
|
+
console.log(`CEF directory contents: ${cefFiles.slice(0, 10).join(', ')}${cefFiles.length > 10 ? '...' : ''}`);
|
|
353
|
+
}
|
|
354
|
+
} catch (e) {
|
|
355
|
+
console.error('Could not list CEF extracted files:', e);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
console.log(`CEF dependencies for ${platformOS}-${platformArch} downloaded and cached successfully`);
|
|
223
359
|
|
|
224
|
-
} catch (error) {
|
|
225
|
-
console.error(
|
|
360
|
+
} catch (error: any) {
|
|
361
|
+
console.error(`Failed to download CEF dependencies for ${platformOS}-${platformArch}:`, error.message);
|
|
226
362
|
console.error('Please ensure you have an internet connection and the release exists.');
|
|
227
363
|
process.exit(1);
|
|
228
364
|
}
|
|
@@ -241,10 +377,6 @@ const commandDefaults = {
|
|
|
241
377
|
projectRoot,
|
|
242
378
|
config: "electrobun.config",
|
|
243
379
|
},
|
|
244
|
-
launcher: {
|
|
245
|
-
projectRoot,
|
|
246
|
-
config: "electrobun.config",
|
|
247
|
-
},
|
|
248
380
|
};
|
|
249
381
|
|
|
250
382
|
// todo (yoav): add types for config
|
|
@@ -257,6 +389,7 @@ const defaultConfig = {
|
|
|
257
389
|
build: {
|
|
258
390
|
buildFolder: "build",
|
|
259
391
|
artifactFolder: "artifacts",
|
|
392
|
+
targets: undefined, // Will default to current platform if not specified
|
|
260
393
|
mac: {
|
|
261
394
|
codesign: false,
|
|
262
395
|
notarize: false,
|
|
@@ -267,6 +400,10 @@ const defaultConfig = {
|
|
|
267
400
|
},
|
|
268
401
|
icons: "icon.iconset",
|
|
269
402
|
},
|
|
403
|
+
bun: {
|
|
404
|
+
entrypoint: "src/bun/index.ts",
|
|
405
|
+
external: [],
|
|
406
|
+
},
|
|
270
407
|
},
|
|
271
408
|
scripts: {
|
|
272
409
|
postBuild: "",
|
|
@@ -286,7 +423,10 @@ if (!command) {
|
|
|
286
423
|
const config = getConfig();
|
|
287
424
|
|
|
288
425
|
const envArg =
|
|
289
|
-
process.argv.find((arg) => arg.startsWith("env="))?.split("=")[1] || "";
|
|
426
|
+
process.argv.find((arg) => arg.startsWith("--env="))?.split("=")[1] || "";
|
|
427
|
+
|
|
428
|
+
const targetsArg =
|
|
429
|
+
process.argv.find((arg) => arg.startsWith("--targets="))?.split("=")[1] || "";
|
|
290
430
|
|
|
291
431
|
const validEnvironments = ["dev", "canary", "stable"];
|
|
292
432
|
|
|
@@ -294,8 +434,175 @@ const validEnvironments = ["dev", "canary", "stable"];
|
|
|
294
434
|
const buildEnvironment: "dev" | "canary" | "stable" =
|
|
295
435
|
validEnvironments.includes(envArg) ? envArg : "dev";
|
|
296
436
|
|
|
437
|
+
// Determine build targets
|
|
438
|
+
type BuildTarget = { os: 'macos' | 'win' | 'linux', arch: 'arm64' | 'x64' };
|
|
439
|
+
|
|
440
|
+
function parseBuildTargets(): BuildTarget[] {
|
|
441
|
+
// If explicit targets provided via CLI
|
|
442
|
+
if (targetsArg) {
|
|
443
|
+
if (targetsArg === 'current') {
|
|
444
|
+
return [{ os: OS, arch: ARCH }];
|
|
445
|
+
} else if (targetsArg === 'all') {
|
|
446
|
+
return parseConfigTargets();
|
|
447
|
+
} else {
|
|
448
|
+
// Parse comma-separated targets like "macos-arm64,win-x64"
|
|
449
|
+
return targetsArg.split(',').map(target => {
|
|
450
|
+
const [os, arch] = target.trim().split('-') as [string, string];
|
|
451
|
+
if (!['macos', 'win', 'linux'].includes(os) || !['arm64', 'x64'].includes(arch)) {
|
|
452
|
+
console.error(`Invalid target: ${target}. Format should be: os-arch (e.g., macos-arm64)`);
|
|
453
|
+
process.exit(1);
|
|
454
|
+
}
|
|
455
|
+
return { os, arch } as BuildTarget;
|
|
456
|
+
});
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Default behavior: always build for current platform only
|
|
461
|
+
// This ensures predictable, fast builds unless explicitly requesting multi-platform
|
|
462
|
+
return [{ os: OS, arch: ARCH }];
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function parseConfigTargets(): BuildTarget[] {
|
|
466
|
+
// If config has targets, use them
|
|
467
|
+
if (config.build.targets && config.build.targets.length > 0) {
|
|
468
|
+
return config.build.targets.map(target => {
|
|
469
|
+
if (target === 'current') {
|
|
470
|
+
return { os: OS, arch: ARCH };
|
|
471
|
+
}
|
|
472
|
+
const [os, arch] = target.split('-') as [string, string];
|
|
473
|
+
if (!['macos', 'win', 'linux'].includes(os) || !['arm64', 'x64'].includes(arch)) {
|
|
474
|
+
console.error(`Invalid target in config: ${target}. Format should be: os-arch (e.g., macos-arm64)`);
|
|
475
|
+
process.exit(1);
|
|
476
|
+
}
|
|
477
|
+
return { os, arch } as BuildTarget;
|
|
478
|
+
});
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// If no config targets and --targets=all, use all available platforms
|
|
482
|
+
if (targetsArg === 'all') {
|
|
483
|
+
console.log('No targets specified in config, using all available platforms');
|
|
484
|
+
return [
|
|
485
|
+
{ os: 'macos', arch: 'arm64' },
|
|
486
|
+
{ os: 'macos', arch: 'x64' },
|
|
487
|
+
{ os: 'win', arch: 'x64' },
|
|
488
|
+
{ os: 'linux', arch: 'x64' },
|
|
489
|
+
{ os: 'linux', arch: 'arm64' }
|
|
490
|
+
];
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Default to current platform
|
|
494
|
+
return [{ os: OS, arch: ARCH }];
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
const buildTargets = parseBuildTargets();
|
|
498
|
+
|
|
499
|
+
// Show build targets to user
|
|
500
|
+
if (buildTargets.length === 1) {
|
|
501
|
+
console.log(`Building for ${buildTargets[0].os}-${buildTargets[0].arch} (${buildEnvironment})`);
|
|
502
|
+
} else {
|
|
503
|
+
const targetList = buildTargets.map(t => `${t.os}-${t.arch}`).join(', ');
|
|
504
|
+
console.log(`Building for multiple targets: ${targetList} (${buildEnvironment})`);
|
|
505
|
+
console.log(`Running ${buildTargets.length} parallel builds...`);
|
|
506
|
+
|
|
507
|
+
// Spawn parallel build processes
|
|
508
|
+
const buildPromises = buildTargets.map(async (target) => {
|
|
509
|
+
const targetString = `${target.os}-${target.arch}`;
|
|
510
|
+
const prefix = `[${targetString}]`;
|
|
511
|
+
|
|
512
|
+
try {
|
|
513
|
+
// Try to find the electrobun binary in node_modules/.bin or use bunx
|
|
514
|
+
const electrobunBin = join(projectRoot, 'node_modules', '.bin', 'electrobun');
|
|
515
|
+
let command: string[];
|
|
516
|
+
|
|
517
|
+
if (existsSync(electrobunBin)) {
|
|
518
|
+
command = [electrobunBin, 'build', `--env=${buildEnvironment}`, `--targets=${targetString}`];
|
|
519
|
+
} else {
|
|
520
|
+
// Fallback to bunx which should resolve node_modules binaries
|
|
521
|
+
command = ['bunx', 'electrobun', 'build', `--env=${buildEnvironment}`, `--targets=${targetString}`];
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
console.log(`${prefix} Running:`, command.join(' '));
|
|
525
|
+
|
|
526
|
+
const result = await Bun.spawn(command, {
|
|
527
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
528
|
+
env: process.env,
|
|
529
|
+
cwd: projectRoot // Ensure we're in the right directory
|
|
530
|
+
});
|
|
531
|
+
|
|
532
|
+
// Pipe output with prefix
|
|
533
|
+
if (result.stdout) {
|
|
534
|
+
const reader = result.stdout.getReader();
|
|
535
|
+
while (true) {
|
|
536
|
+
const { done, value } = await reader.read();
|
|
537
|
+
if (done) break;
|
|
538
|
+
const text = new TextDecoder().decode(value);
|
|
539
|
+
// Add prefix to each line
|
|
540
|
+
const prefixedText = text.split('\n').map(line =>
|
|
541
|
+
line ? `${prefix} ${line}` : line
|
|
542
|
+
).join('\n');
|
|
543
|
+
process.stdout.write(prefixedText);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
if (result.stderr) {
|
|
548
|
+
const reader = result.stderr.getReader();
|
|
549
|
+
while (true) {
|
|
550
|
+
const { done, value } = await reader.read();
|
|
551
|
+
if (done) break;
|
|
552
|
+
const text = new TextDecoder().decode(value);
|
|
553
|
+
const prefixedText = text.split('\n').map(line =>
|
|
554
|
+
line ? `${prefix} ${line}` : line
|
|
555
|
+
).join('\n');
|
|
556
|
+
process.stderr.write(prefixedText);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const exitCode = await result.exited;
|
|
561
|
+
return { target, exitCode, success: exitCode === 0 };
|
|
562
|
+
|
|
563
|
+
} catch (error) {
|
|
564
|
+
console.error(`${prefix} Failed to start build:`, error);
|
|
565
|
+
return { target, exitCode: 1, success: false, error };
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
// Wait for all builds to complete
|
|
570
|
+
const results = await Promise.allSettled(buildPromises);
|
|
571
|
+
|
|
572
|
+
// Report final results
|
|
573
|
+
console.log('\n=== Build Results ===');
|
|
574
|
+
let allSucceeded = true;
|
|
575
|
+
|
|
576
|
+
for (const result of results) {
|
|
577
|
+
if (result.status === 'fulfilled') {
|
|
578
|
+
const { target, success, exitCode } = result.value;
|
|
579
|
+
const status = success ? '✅ SUCCESS' : '❌ FAILED';
|
|
580
|
+
console.log(`${target.os}-${target.arch}: ${status} (exit code: ${exitCode})`);
|
|
581
|
+
if (!success) allSucceeded = false;
|
|
582
|
+
} else {
|
|
583
|
+
console.log(`Build rejected: ${result.reason}`);
|
|
584
|
+
allSucceeded = false;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
if (!allSucceeded) {
|
|
589
|
+
console.log('\nSome builds failed. Check the output above for details.');
|
|
590
|
+
process.exit(1);
|
|
591
|
+
} else {
|
|
592
|
+
console.log('\nAll builds completed successfully! 🎉');
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
process.exit(0);
|
|
596
|
+
}
|
|
597
|
+
|
|
297
598
|
// todo (yoav): dev builds should include the branch name, and/or allow configuration via external config
|
|
298
|
-
|
|
599
|
+
// For now, assume single target build (we'll refactor for multi-target later)
|
|
600
|
+
const currentTarget = buildTargets[0];
|
|
601
|
+
const buildSubFolder = `${buildEnvironment}-${currentTarget.os}-${currentTarget.arch}`;
|
|
602
|
+
|
|
603
|
+
// Use target OS/ARCH for build logic (instead of current machine's OS/ARCH)
|
|
604
|
+
const targetOS = currentTarget.os;
|
|
605
|
+
const targetARCH = currentTarget.arch;
|
|
299
606
|
|
|
300
607
|
const buildFolder = join(projectRoot, config.build.buildFolder, buildSubFolder);
|
|
301
608
|
|
|
@@ -370,16 +677,71 @@ const appFileName = (
|
|
|
370
677
|
)
|
|
371
678
|
.replace(/\s/g, "")
|
|
372
679
|
.replace(/\./g, "-");
|
|
373
|
-
const bundleFileName =
|
|
680
|
+
const bundleFileName = targetOS === 'macos' ? `${appFileName}.app` : appFileName;
|
|
374
681
|
|
|
375
682
|
// const logPath = `/Library/Logs/Electrobun/ExampleApp/dev/out.log`;
|
|
376
683
|
|
|
377
684
|
let proc = null;
|
|
378
685
|
|
|
379
686
|
if (commandArg === "init") {
|
|
380
|
-
|
|
381
|
-
|
|
687
|
+
const projectName = process.argv[indexOfElectrobun + 2] || "my-electrobun-app";
|
|
688
|
+
const templateName = process.argv.find(arg => arg.startsWith("--template="))?.split("=")[1] || "hello-world";
|
|
689
|
+
|
|
690
|
+
console.log(`🚀 Initializing Electrobun project: ${projectName}`);
|
|
691
|
+
|
|
692
|
+
// Validate template name
|
|
693
|
+
const availableTemplates = getTemplateNames();
|
|
694
|
+
if (!availableTemplates.includes(templateName)) {
|
|
695
|
+
console.error(`❌ Template "${templateName}" not found.`);
|
|
696
|
+
console.log(`Available templates: ${availableTemplates.join(", ")}`);
|
|
697
|
+
process.exit(1);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const template = getTemplate(templateName);
|
|
701
|
+
if (!template) {
|
|
702
|
+
console.error(`❌ Could not load template "${templateName}"`);
|
|
703
|
+
process.exit(1);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Create project directory
|
|
707
|
+
const projectPath = join(process.cwd(), projectName);
|
|
708
|
+
if (existsSync(projectPath)) {
|
|
709
|
+
console.error(`❌ Directory "${projectName}" already exists.`);
|
|
710
|
+
process.exit(1);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
mkdirSync(projectPath, { recursive: true });
|
|
714
|
+
|
|
715
|
+
// Extract template files
|
|
716
|
+
let fileCount = 0;
|
|
717
|
+
for (const [relativePath, content] of Object.entries(template.files)) {
|
|
718
|
+
const fullPath = join(projectPath, relativePath);
|
|
719
|
+
const dir = dirname(fullPath);
|
|
720
|
+
|
|
721
|
+
// Create directory if it doesn't exist
|
|
722
|
+
mkdirSync(dir, { recursive: true });
|
|
723
|
+
|
|
724
|
+
// Write file
|
|
725
|
+
writeFileSync(fullPath, content, 'utf-8');
|
|
726
|
+
fileCount++;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
console.log(`✅ Created ${fileCount} files from "${templateName}" template`);
|
|
730
|
+
console.log(`📁 Project created at: ${projectPath}`);
|
|
731
|
+
console.log("");
|
|
732
|
+
console.log("📦 Next steps:");
|
|
733
|
+
console.log(` cd ${projectName}`);
|
|
734
|
+
console.log(" bun install");
|
|
735
|
+
console.log(" bunx electrobun dev");
|
|
736
|
+
console.log("");
|
|
737
|
+
console.log("🎉 Happy building with Electrobun!");
|
|
382
738
|
} else if (commandArg === "build") {
|
|
739
|
+
// Ensure core binaries are available for the target platform before starting build
|
|
740
|
+
await ensureCoreDependencies(currentTarget.os, currentTarget.arch);
|
|
741
|
+
|
|
742
|
+
// Get platform-specific paths for the current target
|
|
743
|
+
const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);
|
|
744
|
+
|
|
383
745
|
// refresh build folder
|
|
384
746
|
if (existsSync(buildFolder)) {
|
|
385
747
|
rmdirSync(buildFolder, { recursive: true });
|
|
@@ -403,7 +765,7 @@ if (commandArg === "init") {
|
|
|
403
765
|
appBundleMacOSPath,
|
|
404
766
|
appBundleFolderResourcesPath,
|
|
405
767
|
appBundleFolderFrameworksPath,
|
|
406
|
-
} = createAppBundle(appFileName, buildFolder);
|
|
768
|
+
} = createAppBundle(appFileName, buildFolder, targetOS);
|
|
407
769
|
|
|
408
770
|
const appBundleAppCodePath = join(appBundleFolderResourcesPath, "app");
|
|
409
771
|
|
|
@@ -473,29 +835,27 @@ if (commandArg === "init") {
|
|
|
473
835
|
// mkdirSync(destLauncherFolder, {recursive: true});
|
|
474
836
|
// }
|
|
475
837
|
// cpSync(zigLauncherBinarySource, zigLauncherDestination, {recursive: true, dereference: true});
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
// console.info('creating folder: ', destFolder);
|
|
486
|
-
mkdirSync(destLauncherFolder, { recursive: true });
|
|
487
|
-
}
|
|
838
|
+
// Only copy launcher for non-dev builds
|
|
839
|
+
if (buildEnvironment !== "dev") {
|
|
840
|
+
const bunCliLauncherBinarySource = targetPaths.LAUNCHER_RELEASE;
|
|
841
|
+
const bunCliLauncherDestination = join(appBundleMacOSPath, "launcher") + binExt;
|
|
842
|
+
const destLauncherFolder = dirname(bunCliLauncherDestination);
|
|
843
|
+
if (!existsSync(destLauncherFolder)) {
|
|
844
|
+
// console.info('creating folder: ', destFolder);
|
|
845
|
+
mkdirSync(destLauncherFolder, { recursive: true });
|
|
846
|
+
}
|
|
488
847
|
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
848
|
+
cpSync(bunCliLauncherBinarySource, bunCliLauncherDestination, {
|
|
849
|
+
recursive: true,
|
|
850
|
+
dereference: true,
|
|
851
|
+
});
|
|
852
|
+
}
|
|
493
853
|
|
|
494
|
-
cpSync(
|
|
854
|
+
cpSync(targetPaths.MAIN_JS, join(appBundleMacOSPath, 'main.js'));
|
|
495
855
|
|
|
496
856
|
// Bun runtime binary
|
|
497
857
|
// todo (yoav): this only works for the current architecture
|
|
498
|
-
const bunBinarySourcePath =
|
|
858
|
+
const bunBinarySourcePath = targetPaths.BUN_BINARY;
|
|
499
859
|
// Note: .bin/bun binary in node_modules is a symlink to the versioned one in another place
|
|
500
860
|
// in node_modules, so we have to dereference here to get the actual binary in the bundle.
|
|
501
861
|
const bunBinaryDestInBundlePath = join(appBundleMacOSPath, "bun") + binExt;
|
|
@@ -507,8 +867,8 @@ if (commandArg === "init") {
|
|
|
507
867
|
cpSync(bunBinarySourcePath, bunBinaryDestInBundlePath, { dereference: true });
|
|
508
868
|
|
|
509
869
|
// copy native wrapper dynamic library
|
|
510
|
-
if (
|
|
511
|
-
const nativeWrapperMacosSource =
|
|
870
|
+
if (targetOS === 'macos') {
|
|
871
|
+
const nativeWrapperMacosSource = targetPaths.NATIVE_WRAPPER_MACOS;
|
|
512
872
|
const nativeWrapperMacosDestination = join(
|
|
513
873
|
appBundleMacOSPath,
|
|
514
874
|
"libNativeWrapper.dylib"
|
|
@@ -516,8 +876,8 @@ if (commandArg === "init") {
|
|
|
516
876
|
cpSync(nativeWrapperMacosSource, nativeWrapperMacosDestination, {
|
|
517
877
|
dereference: true,
|
|
518
878
|
});
|
|
519
|
-
} else if (
|
|
520
|
-
const nativeWrapperMacosSource =
|
|
879
|
+
} else if (targetOS === 'win') {
|
|
880
|
+
const nativeWrapperMacosSource = targetPaths.NATIVE_WRAPPER_WIN;
|
|
521
881
|
const nativeWrapperMacosDestination = join(
|
|
522
882
|
appBundleMacOSPath,
|
|
523
883
|
"libNativeWrapper.dll"
|
|
@@ -526,7 +886,7 @@ if (commandArg === "init") {
|
|
|
526
886
|
dereference: true,
|
|
527
887
|
});
|
|
528
888
|
|
|
529
|
-
const webview2LibSource =
|
|
889
|
+
const webview2LibSource = targetPaths.WEBVIEW2LOADER_WIN;
|
|
530
890
|
const webview2LibDestination = join(
|
|
531
891
|
appBundleMacOSPath,
|
|
532
892
|
"WebView2Loader.dll"
|
|
@@ -534,30 +894,34 @@ if (commandArg === "init") {
|
|
|
534
894
|
// copy webview2 system webview library
|
|
535
895
|
cpSync(webview2LibSource, webview2LibDestination);
|
|
536
896
|
|
|
537
|
-
} else if (
|
|
538
|
-
|
|
897
|
+
} else if (targetOS === 'linux') {
|
|
898
|
+
// Choose the appropriate native wrapper based on bundleCEF setting
|
|
899
|
+
const useCEF = config.build.linux?.bundleCEF;
|
|
900
|
+
const nativeWrapperLinuxSource = useCEF ? targetPaths.NATIVE_WRAPPER_LINUX_CEF : targetPaths.NATIVE_WRAPPER_LINUX;
|
|
539
901
|
const nativeWrapperLinuxDestination = join(
|
|
540
902
|
appBundleMacOSPath,
|
|
541
903
|
"libNativeWrapper.so"
|
|
542
904
|
);
|
|
905
|
+
|
|
543
906
|
if (existsSync(nativeWrapperLinuxSource)) {
|
|
544
907
|
cpSync(nativeWrapperLinuxSource, nativeWrapperLinuxDestination, {
|
|
545
908
|
dereference: true,
|
|
546
909
|
});
|
|
910
|
+
console.log(`Using ${useCEF ? 'CEF' : 'GTK'} native wrapper for Linux`);
|
|
911
|
+
} else {
|
|
912
|
+
throw new Error(`Native wrapper not found: ${nativeWrapperLinuxSource}`);
|
|
547
913
|
}
|
|
548
914
|
}
|
|
549
915
|
|
|
550
|
-
// Ensure core binaries are available
|
|
551
|
-
await ensureCoreDependencies();
|
|
552
916
|
|
|
553
917
|
// Download CEF binaries if needed when bundleCEF is enabled
|
|
554
|
-
if ((
|
|
555
|
-
(
|
|
556
|
-
(
|
|
918
|
+
if ((targetOS === 'macos' && config.build.mac?.bundleCEF) ||
|
|
919
|
+
(targetOS === 'win' && config.build.win?.bundleCEF) ||
|
|
920
|
+
(targetOS === 'linux' && config.build.linux?.bundleCEF)) {
|
|
557
921
|
|
|
558
|
-
await ensureCEFDependencies();
|
|
559
|
-
if (
|
|
560
|
-
const cefFrameworkSource =
|
|
922
|
+
await ensureCEFDependencies(currentTarget.os, currentTarget.arch);
|
|
923
|
+
if (targetOS === 'macos') {
|
|
924
|
+
const cefFrameworkSource = targetPaths.CEF_FRAMEWORK_MACOS;
|
|
561
925
|
const cefFrameworkDestination = join(
|
|
562
926
|
appBundleFolderFrameworksPath,
|
|
563
927
|
"Chromium Embedded Framework.framework"
|
|
@@ -578,7 +942,7 @@ if (commandArg === "init") {
|
|
|
578
942
|
"bun Helper (Renderer)",
|
|
579
943
|
];
|
|
580
944
|
|
|
581
|
-
const helperSourcePath =
|
|
945
|
+
const helperSourcePath = targetPaths.CEF_HELPER_MACOS;
|
|
582
946
|
cefHelperNames.forEach((helperName) => {
|
|
583
947
|
const destinationPath = join(
|
|
584
948
|
appBundleFolderFrameworksPath,
|
|
@@ -598,10 +962,9 @@ if (commandArg === "init") {
|
|
|
598
962
|
dereference: true,
|
|
599
963
|
});
|
|
600
964
|
});
|
|
601
|
-
} else if (
|
|
602
|
-
// Copy CEF DLLs from dist/cef/ to the main executable directory
|
|
603
|
-
const
|
|
604
|
-
const cefSourcePath = join(electrobunDistPath, "cef");
|
|
965
|
+
} else if (targetOS === 'win') {
|
|
966
|
+
// Copy CEF DLLs from platform-specific dist/cef/ to the main executable directory
|
|
967
|
+
const cefSourcePath = targetPaths.CEF_DIR;
|
|
605
968
|
const cefDllFiles = [
|
|
606
969
|
'libcef.dll',
|
|
607
970
|
'chrome_elf.dll',
|
|
@@ -641,7 +1004,7 @@ if (commandArg === "init") {
|
|
|
641
1004
|
});
|
|
642
1005
|
|
|
643
1006
|
// Copy CEF resources to MacOS/cef/ subdirectory for other resources like locales
|
|
644
|
-
const cefResourcesSource =
|
|
1007
|
+
const cefResourcesSource = targetPaths.CEF_DIR;
|
|
645
1008
|
const cefResourcesDestination = join(appBundleMacOSPath, 'cef');
|
|
646
1009
|
|
|
647
1010
|
if (existsSync(cefResourcesSource)) {
|
|
@@ -660,7 +1023,7 @@ if (commandArg === "init") {
|
|
|
660
1023
|
"bun Helper (Renderer)",
|
|
661
1024
|
];
|
|
662
1025
|
|
|
663
|
-
const helperSourcePath =
|
|
1026
|
+
const helperSourcePath = targetPaths.CEF_HELPER_WIN;
|
|
664
1027
|
if (existsSync(helperSourcePath)) {
|
|
665
1028
|
cefHelperNames.forEach((helperName) => {
|
|
666
1029
|
const destinationPath = join(appBundleMacOSPath, `${helperName}.exe`);
|
|
@@ -670,10 +1033,9 @@ if (commandArg === "init") {
|
|
|
670
1033
|
} else {
|
|
671
1034
|
console.log(`WARNING: Missing CEF helper: ${helperSourcePath}`);
|
|
672
1035
|
}
|
|
673
|
-
} else if (
|
|
674
|
-
// Copy CEF shared libraries from dist/cef/ to the main executable directory
|
|
675
|
-
const
|
|
676
|
-
const cefSourcePath = join(electrobunDistPath, "cef");
|
|
1036
|
+
} else if (targetOS === 'linux') {
|
|
1037
|
+
// Copy CEF shared libraries from platform-specific dist/cef/ to the main executable directory
|
|
1038
|
+
const cefSourcePath = targetPaths.CEF_DIR;
|
|
677
1039
|
|
|
678
1040
|
if (existsSync(cefSourcePath)) {
|
|
679
1041
|
const cefSoFiles = [
|
|
@@ -759,12 +1121,12 @@ if (commandArg === "init") {
|
|
|
759
1121
|
"bun Helper (Renderer)",
|
|
760
1122
|
];
|
|
761
1123
|
|
|
762
|
-
const helperSourcePath =
|
|
1124
|
+
const helperSourcePath = targetPaths.CEF_HELPER_LINUX;
|
|
763
1125
|
if (existsSync(helperSourcePath)) {
|
|
764
1126
|
cefHelperNames.forEach((helperName) => {
|
|
765
1127
|
const destinationPath = join(appBundleMacOSPath, helperName);
|
|
766
1128
|
cpSync(helperSourcePath, destinationPath);
|
|
767
|
-
console.log(`Copied CEF helper: ${helperName}`);
|
|
1129
|
+
// console.log(`Copied CEF helper: ${helperName}`);
|
|
768
1130
|
});
|
|
769
1131
|
} else {
|
|
770
1132
|
console.log(`WARNING: Missing CEF helper: ${helperSourcePath}`);
|
|
@@ -775,7 +1137,7 @@ if (commandArg === "init") {
|
|
|
775
1137
|
|
|
776
1138
|
|
|
777
1139
|
// copy native bindings
|
|
778
|
-
const bsPatchSource =
|
|
1140
|
+
const bsPatchSource = targetPaths.BSPATCH;
|
|
779
1141
|
const bsPatchDestination = join(appBundleMacOSPath, "bspatch") + binExt;
|
|
780
1142
|
const bsPatchDestFolder = dirname(bsPatchDestination);
|
|
781
1143
|
if (!existsSync(bsPatchDestFolder)) {
|
|
@@ -871,12 +1233,21 @@ if (commandArg === "init") {
|
|
|
871
1233
|
|
|
872
1234
|
// Run postBuild script
|
|
873
1235
|
if (config.scripts.postBuild) {
|
|
874
|
-
|
|
875
|
-
|
|
1236
|
+
// Use host platform's bun binary for running scripts, not target platform's
|
|
1237
|
+
const hostPaths = getPlatformPaths(OS, ARCH);
|
|
1238
|
+
|
|
1239
|
+
Bun.spawnSync([hostPaths.BUN_BINARY, config.scripts.postBuild], {
|
|
876
1240
|
stdio: ["ignore", "inherit", "inherit"],
|
|
877
1241
|
env: {
|
|
878
1242
|
...process.env,
|
|
879
1243
|
ELECTROBUN_BUILD_ENV: buildEnvironment,
|
|
1244
|
+
ELECTROBUN_OS: targetOS, // Use target OS for environment variables
|
|
1245
|
+
ELECTROBUN_ARCH: targetARCH, // Use target ARCH for environment variables
|
|
1246
|
+
ELECTROBUN_BUILD_DIR: buildFolder,
|
|
1247
|
+
ELECTROBUN_APP_NAME: appFileName,
|
|
1248
|
+
ELECTROBUN_APP_VERSION: config.app.version,
|
|
1249
|
+
ELECTROBUN_APP_IDENTIFIER: config.app.identifier,
|
|
1250
|
+
ELECTROBUN_ARTIFACT_DIR: artifactFolder,
|
|
880
1251
|
},
|
|
881
1252
|
});
|
|
882
1253
|
}
|
|
@@ -920,8 +1291,9 @@ if (commandArg === "init") {
|
|
|
920
1291
|
);
|
|
921
1292
|
|
|
922
1293
|
// todo (yoav): add these to config
|
|
1294
|
+
// Only codesign/notarize when building macOS targets on macOS host
|
|
923
1295
|
const shouldCodesign =
|
|
924
|
-
buildEnvironment !== "dev" && config.build.mac.codesign;
|
|
1296
|
+
buildEnvironment !== "dev" && targetOS === 'macos' && OS === 'macos' && config.build.mac.codesign;
|
|
925
1297
|
const shouldNotarize = shouldCodesign && config.build.mac.notarize;
|
|
926
1298
|
|
|
927
1299
|
if (shouldCodesign) {
|
|
@@ -956,6 +1328,8 @@ if (commandArg === "init") {
|
|
|
956
1328
|
// 6.5. code sign and notarize the dmg
|
|
957
1329
|
// 7. copy artifacts to directory [self-extractor dmg, zstd app bundle, bsdiff patch, update.json]
|
|
958
1330
|
|
|
1331
|
+
// Platform suffix is only used for folder names, not file names
|
|
1332
|
+
const platformSuffix = `-${targetOS}-${targetARCH}`;
|
|
959
1333
|
const tarPath = `${appBundleFolderPath}.tar`;
|
|
960
1334
|
|
|
961
1335
|
// tar the signed and notarized app bundle
|
|
@@ -988,19 +1362,22 @@ if (commandArg === "init") {
|
|
|
988
1362
|
await ZstdInit().then(async ({ ZstdSimple, ZstdStream }) => {
|
|
989
1363
|
// Note: Simple is much faster than stream, but stream is better for large files
|
|
990
1364
|
// todo (yoav): consider a file size cutoff to switch to stream instead of simple.
|
|
1365
|
+
const useStream = tarball.size > 100 * 1024 * 1024;
|
|
1366
|
+
|
|
991
1367
|
if (tarball.size > 0) {
|
|
992
|
-
|
|
1368
|
+
// Uint8 array filestream of the tar file
|
|
993
1369
|
|
|
994
1370
|
const data = new Uint8Array(tarBuffer);
|
|
1371
|
+
|
|
995
1372
|
const compressionLevel = 22;
|
|
996
1373
|
const compressedData = ZstdSimple.compress(data, compressionLevel);
|
|
997
1374
|
|
|
998
1375
|
console.log(
|
|
999
1376
|
"compressed",
|
|
1000
|
-
|
|
1377
|
+
data.length,
|
|
1001
1378
|
"bytes",
|
|
1002
1379
|
"from",
|
|
1003
|
-
|
|
1380
|
+
tarBuffer.byteLength,
|
|
1004
1381
|
"bytes"
|
|
1005
1382
|
);
|
|
1006
1383
|
|
|
@@ -1012,7 +1389,7 @@ if (commandArg === "init") {
|
|
|
1012
1389
|
// now and it needs the same name as the original app bundle.
|
|
1013
1390
|
rmdirSync(appBundleFolderPath, { recursive: true });
|
|
1014
1391
|
|
|
1015
|
-
const selfExtractingBundle = createAppBundle(appFileName, buildFolder);
|
|
1392
|
+
const selfExtractingBundle = createAppBundle(appFileName, buildFolder, targetOS);
|
|
1016
1393
|
const compressedTarballInExtractingBundlePath = join(
|
|
1017
1394
|
selfExtractingBundle.appBundleFolderResourcesPath,
|
|
1018
1395
|
`${hash}.tar.zst`
|
|
@@ -1021,7 +1398,7 @@ if (commandArg === "init") {
|
|
|
1021
1398
|
// copy the zstd tarball to the self-extracting app bundle
|
|
1022
1399
|
cpSync(compressedTarPath, compressedTarballInExtractingBundlePath);
|
|
1023
1400
|
|
|
1024
|
-
const selfExtractorBinSourcePath =
|
|
1401
|
+
const selfExtractorBinSourcePath = targetPaths.EXTRACTOR;
|
|
1025
1402
|
const selfExtractorBinDestinationPath = join(
|
|
1026
1403
|
selfExtractingBundle.appBundleMacOSPath,
|
|
1027
1404
|
"launcher"
|
|
@@ -1053,28 +1430,45 @@ if (commandArg === "init") {
|
|
|
1053
1430
|
console.log("skipping notarization");
|
|
1054
1431
|
}
|
|
1055
1432
|
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1433
|
+
// DMG creation for macOS only
|
|
1434
|
+
if (targetOS === 'macos') {
|
|
1435
|
+
console.log("creating dmg...");
|
|
1436
|
+
// make a dmg
|
|
1437
|
+
const dmgPath = join(buildFolder, `${appFileName}.dmg`);
|
|
1438
|
+
artifactsToUpload.push(dmgPath);
|
|
1439
|
+
// hdiutil create -volname "YourAppName" -srcfolder /path/to/YourApp.app -ov -format UDZO YourAppName.dmg
|
|
1440
|
+
// Note: use ULFO (lzfse) for better compatibility with large CEF frameworks and modern macOS
|
|
1441
|
+
execSync(
|
|
1442
|
+
`hdiutil create -volname "${appFileName}" -srcfolder ${escapePathForTerminal(
|
|
1443
|
+
appBundleFolderPath
|
|
1444
|
+
)} -ov -format ULFO ${escapePathForTerminal(dmgPath)}`
|
|
1445
|
+
);
|
|
1067
1446
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1447
|
+
if (shouldCodesign) {
|
|
1448
|
+
codesignAppBundle(dmgPath);
|
|
1449
|
+
} else {
|
|
1450
|
+
console.log("skipping codesign");
|
|
1451
|
+
}
|
|
1073
1452
|
|
|
1074
|
-
|
|
1075
|
-
|
|
1453
|
+
if (shouldNotarize) {
|
|
1454
|
+
notarizeAndStaple(dmgPath);
|
|
1455
|
+
} else {
|
|
1456
|
+
console.log("skipping notarization");
|
|
1457
|
+
}
|
|
1076
1458
|
} else {
|
|
1077
|
-
|
|
1459
|
+
// For Windows and Linux, add the self-extracting bundle directly
|
|
1460
|
+
const platformBundlePath = join(buildFolder, `${appFileName}${platformSuffix}${targetOS === 'win' ? '.exe' : ''}`);
|
|
1461
|
+
// Copy the self-extracting bundle to platform-specific filename
|
|
1462
|
+
if (targetOS === 'win') {
|
|
1463
|
+
// On Windows, create a self-extracting exe
|
|
1464
|
+
// For now, just copy the bundle folder
|
|
1465
|
+
artifactsToUpload.push(compressedTarPath);
|
|
1466
|
+
} else if (targetOS === 'linux') {
|
|
1467
|
+
// On Linux, create a tar.gz of the bundle
|
|
1468
|
+
const linuxTarPath = join(buildFolder, `${appFileName}.tar.gz`);
|
|
1469
|
+
execSync(`tar -czf ${escapePathForTerminal(linuxTarPath)} -C ${escapePathForTerminal(buildFolder)} ${escapePathForTerminal(basename(appBundleFolderPath))}`);
|
|
1470
|
+
artifactsToUpload.push(linuxTarPath);
|
|
1471
|
+
}
|
|
1078
1472
|
}
|
|
1079
1473
|
|
|
1080
1474
|
// refresh artifacts folder
|
|
@@ -1093,39 +1487,48 @@ if (commandArg === "init") {
|
|
|
1093
1487
|
// the download button or display on your marketing site or in the app.
|
|
1094
1488
|
version: config.app.version,
|
|
1095
1489
|
hash: hash.toString(),
|
|
1490
|
+
platform: OS,
|
|
1491
|
+
arch: ARCH,
|
|
1096
1492
|
// channel: buildEnvironment,
|
|
1097
1493
|
// bucketUrl: config.release.bucketUrl
|
|
1098
1494
|
});
|
|
1099
1495
|
|
|
1100
|
-
|
|
1496
|
+
// update.json (no platform suffix in filename, platform is in folder name)
|
|
1497
|
+
await Bun.write(join(artifactFolder, 'update.json'), updateJsonContent);
|
|
1101
1498
|
|
|
1102
1499
|
// generate bsdiff
|
|
1103
1500
|
// https://storage.googleapis.com/eggbun-static/electrobun-playground/canary/ElectrobunPlayground-canary.app.tar.zst
|
|
1104
1501
|
console.log("bucketUrl: ", config.release.bucketUrl);
|
|
1105
1502
|
|
|
1106
1503
|
console.log("generating a patch from the previous version...");
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1504
|
+
|
|
1505
|
+
// Skip patch generation if bucketUrl is not configured
|
|
1506
|
+
if (!config.release.bucketUrl || config.release.bucketUrl.trim() === '') {
|
|
1507
|
+
console.log("No bucketUrl configured, skipping patch generation");
|
|
1508
|
+
console.log("To enable patch generation, configure bucketUrl in your electrobun.config");
|
|
1509
|
+
} else {
|
|
1510
|
+
const urlToPrevUpdateJson = join(
|
|
1511
|
+
config.release.bucketUrl,
|
|
1512
|
+
buildSubFolder,
|
|
1513
|
+
'update.json'
|
|
1514
|
+
);
|
|
1515
|
+
const cacheBuster = Math.random().toString(36).substring(7);
|
|
1516
|
+
const updateJsonResponse = await fetch(
|
|
1517
|
+
urlToPrevUpdateJson + `?${cacheBuster}`
|
|
1518
|
+
).catch((err) => {
|
|
1519
|
+
console.log("bucketURL not found: ", err);
|
|
1520
|
+
});
|
|
1118
1521
|
|
|
1119
1522
|
const urlToLatestTarball = join(
|
|
1120
1523
|
config.release.bucketUrl,
|
|
1121
|
-
|
|
1524
|
+
buildSubFolder,
|
|
1122
1525
|
`${appFileName}.app.tar.zst`
|
|
1123
1526
|
);
|
|
1124
1527
|
|
|
1125
1528
|
|
|
1126
1529
|
// attempt to get the previous version to create a patch file
|
|
1127
|
-
if (updateJsonResponse.ok) {
|
|
1128
|
-
const prevUpdateJson = await updateJsonResponse
|
|
1530
|
+
if (updateJsonResponse && updateJsonResponse.ok) {
|
|
1531
|
+
const prevUpdateJson = await updateJsonResponse!.json();
|
|
1129
1532
|
|
|
1130
1533
|
const prevHash = prevUpdateJson.hash;
|
|
1131
1534
|
console.log("PREVIOUS HASH", prevHash);
|
|
@@ -1164,7 +1567,7 @@ if (commandArg === "init") {
|
|
|
1164
1567
|
console.log("diff previous and new tarballs...");
|
|
1165
1568
|
// Run it as a separate process to leverage multi-threadedness
|
|
1166
1569
|
// especially for creating multiple diffs in parallel
|
|
1167
|
-
const bsdiffpath =
|
|
1570
|
+
const bsdiffpath = targetPaths.BSDIFF;
|
|
1168
1571
|
const patchFilePath = join(buildFolder, `${prevHash}.patch`);
|
|
1169
1572
|
artifactsToUpload.push(patchFilePath);
|
|
1170
1573
|
const result = Bun.spawnSync(
|
|
@@ -1181,6 +1584,7 @@ if (commandArg === "init") {
|
|
|
1181
1584
|
console.log("prevoius version not found at: ", urlToLatestTarball);
|
|
1182
1585
|
console.log("skipping diff generation");
|
|
1183
1586
|
}
|
|
1587
|
+
} // End of bucketUrl validation block
|
|
1184
1588
|
|
|
1185
1589
|
// compress all the upload files
|
|
1186
1590
|
console.log("copying artifacts...");
|
|
@@ -1209,10 +1613,7 @@ if (commandArg === "init") {
|
|
|
1209
1613
|
// todo (yoav): rename to start
|
|
1210
1614
|
|
|
1211
1615
|
// run the project in dev mode
|
|
1212
|
-
// this runs the
|
|
1213
|
-
// there is another copy of the cli in the app bundle that will execute the app
|
|
1214
|
-
// the two cli processes communicate via named pipes and together manage the dev
|
|
1215
|
-
// lifecycle and debug functionality
|
|
1616
|
+
// this runs the bundled bun binary with main.js directly
|
|
1216
1617
|
|
|
1217
1618
|
// Note: this cli will be a bun single-file-executable
|
|
1218
1619
|
// Note: we want to use the version of bun that's packaged with electrobun
|
|
@@ -1290,7 +1691,12 @@ function getConfig() {
|
|
|
1290
1691
|
if (existsSync(configPath)) {
|
|
1291
1692
|
const configFileContents = readFileSync(configPath, "utf8");
|
|
1292
1693
|
// Note: we want this to hard fail if there's a syntax error
|
|
1293
|
-
|
|
1694
|
+
try {
|
|
1695
|
+
loadedConfig = JSON.parse(configFileContents);
|
|
1696
|
+
} catch (error) {
|
|
1697
|
+
console.error("Failed to parse config file:", error);
|
|
1698
|
+
console.error("using default config instead");
|
|
1699
|
+
}
|
|
1294
1700
|
}
|
|
1295
1701
|
|
|
1296
1702
|
// todo (yoav): write a deep clone fn
|
|
@@ -1312,6 +1718,18 @@ function getConfig() {
|
|
|
1312
1718
|
...(loadedConfig?.build?.mac?.entitlements || {}),
|
|
1313
1719
|
},
|
|
1314
1720
|
},
|
|
1721
|
+
win: {
|
|
1722
|
+
...defaultConfig.build.win,
|
|
1723
|
+
...(loadedConfig?.build?.win || {}),
|
|
1724
|
+
},
|
|
1725
|
+
linux: {
|
|
1726
|
+
...defaultConfig.build.linux,
|
|
1727
|
+
...(loadedConfig?.build?.linux || {}),
|
|
1728
|
+
},
|
|
1729
|
+
bun: {
|
|
1730
|
+
...defaultConfig.build.bun,
|
|
1731
|
+
...(loadedConfig?.build?.bun || {}),
|
|
1732
|
+
}
|
|
1315
1733
|
},
|
|
1316
1734
|
scripts: {
|
|
1317
1735
|
...defaultConfig.scripts,
|
|
@@ -1473,8 +1891,8 @@ function notarizeAndStaple(appOrDmgPath: string) {
|
|
|
1473
1891
|
// have the same name but different subfolders in our build directory. or I guess delete the first one after tar/compression and then create the other one.
|
|
1474
1892
|
// either way you can pass in the parent folder here for that flexibility.
|
|
1475
1893
|
// for intel/arm builds on mac we'll probably have separate subfolders as well and build them in parallel.
|
|
1476
|
-
function createAppBundle(bundleName: string, parentFolder: string) {
|
|
1477
|
-
if (
|
|
1894
|
+
function createAppBundle(bundleName: string, parentFolder: string, targetOS: 'macos' | 'win' | 'linux') {
|
|
1895
|
+
if (targetOS === 'macos') {
|
|
1478
1896
|
// macOS bundle structure
|
|
1479
1897
|
const bundleFileName = `${bundleName}.app`;
|
|
1480
1898
|
const appBundleFolderPath = join(parentFolder, bundleFileName);
|
|
@@ -1501,7 +1919,7 @@ function createAppBundle(bundleName: string, parentFolder: string) {
|
|
|
1501
1919
|
appBundleFolderResourcesPath,
|
|
1502
1920
|
appBundleFolderFrameworksPath,
|
|
1503
1921
|
};
|
|
1504
|
-
} else if (
|
|
1922
|
+
} else if (targetOS === 'linux' || targetOS === 'win') {
|
|
1505
1923
|
// Linux/Windows simpler structure
|
|
1506
1924
|
const appBundleFolderPath = join(parentFolder, bundleName);
|
|
1507
1925
|
const appBundleFolderContentsPath = appBundleFolderPath; // No Contents folder needed
|
|
@@ -1522,6 +1940,6 @@ function createAppBundle(bundleName: string, parentFolder: string) {
|
|
|
1522
1940
|
appBundleFolderFrameworksPath,
|
|
1523
1941
|
};
|
|
1524
1942
|
} else {
|
|
1525
|
-
throw new Error(`Unsupported OS: ${
|
|
1943
|
+
throw new Error(`Unsupported OS: ${targetOS}`);
|
|
1526
1944
|
}
|
|
1527
1945
|
}
|