Skip to content

Commit 2cc9824

Browse files
committed
build: releaseSrc and releaseSrcDebug npm builds electron appimage in linux
1 parent d151339 commit 2cc9824

7 files changed

Lines changed: 182 additions & 62 deletions

File tree

package.json

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,19 @@
66
"scripts": {
77
"tauri": "tauri",
88
"tauriBuildDemoApp": "node src-build/createDemoReleaseConfig.js && tauri build --config ./src-tauri/tauri-local.conf.json",
9-
"_createSrcReleaseConfig": "node src-build/createSrcReleaseConfig.js",
109
"_createDistReleaseConfig": "node src-build/createDistReleaseConfig.js",
1110
"_createDistBundleReleaseConfig": "node src-build/createDistBundleReleaseConfig.js",
1211
"_createDistTestReleaseConfig": "node src-build/createDistTestReleaseConfig.js",
1312
"_ci-createDistReleaseConfig": "node src-build/ci-createDistReleaseConfig.js",
1413
"_ci-env-warn": "echo !!!This script is supposed to executed in github actions only. Ignore if you are seeing this message in a github actions log.",
15-
"releaseSrc": "npm run _make_src-node && npm run _createSrcReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json",
16-
"releaseSrcDebug": "npm run _make_src-node && npm run _createSrcReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json --debug --verbose",
14+
"releaseSrc": "node src-build/createSrcRelease.js",
15+
"releaseSrcDebug": "node src-build/createSrcRelease.js --debug",
1716
"releaseDist": "npm run _make_src-node && npm run _createDistReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json",
1817
"releaseDistBundle": "npm run _make_src-node && npm run _createDistBundleReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json --verbose",
1918
"releaseDistDebug": "npm run _make_src-node && npm run _createDistReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json --debug --verbose",
2019
"releaseDistTest": "npm run _make_src-node && npm run _createDistTestReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json",
2120
"releaseDistTestDebug": "npm run _make_src-node && npm run _createDistTestReleaseConfig && tauri build --config ./src-tauri/tauri-local.conf.json --debug",
2221
"_make_src-node": "node ./src-build/makeSrcNode.js ../phoenix/src-node",
23-
"_copy_phoenix-dist": "cd ../phoenix && npm run release:prod && cd ../phoenix-desktop && shx rm -rf src-electron/phoenix-dist && shx cp -r ../phoenix/dist src-electron/phoenix-dist",
24-
"build:electron": "npm run _make_src-node && npm run _copy_phoenix-dist && cd src-electron && npm run build:appimage",
2522
"_ci_make_src-node": "node ./src-build/makeSrcNode.js phoenix/src-node",
2623
"_ci-clonePhoenixForTests": "npm run _ci-env-warn && node ./src-build/clonePhoenixForTests.js",
2724
"_ci-cloneAndBuildPhoenix": "npm run _ci-env-warn && node ./src-build/clonePhoenix.js && cd phoenix && npm ci && npm run build && cd ..",

src-build/createSrcRelease.js

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
import { execSync } from 'child_process';
2+
import { fileURLToPath } from 'url';
3+
import { dirname, join } from 'path';
4+
import fs from 'fs';
5+
import * as os from 'os';
6+
import chalk from 'chalk';
7+
import { getPlatformDetails } from './utils.js';
8+
9+
const __filename = fileURLToPath(import.meta.url);
10+
const __dirname = dirname(__filename);
11+
const projectRoot = join(__dirname, '..');
12+
13+
// Parse command line args
14+
const args = process.argv.slice(2);
15+
const isDebug = args.includes('--debug');
16+
const { platform } = getPlatformDetails();
17+
18+
// Determine target from CLI or auto-detect
19+
let target;
20+
if (args.includes('electron')) {
21+
target = 'electron';
22+
} else if (args.includes('tauri')) {
23+
target = 'tauri';
24+
} else {
25+
// Auto-detect: Linux uses Electron, Windows/Mac use Tauri
26+
target = (platform === 'linux') ? 'electron' : 'tauri';
27+
}
28+
29+
// Print override instructions
30+
console.log(chalk.cyan('\n=== Phoenix Code Release Build ===\n'));
31+
console.log(`Platform: ${platform}, Target: ${target}${isDebug ? ' (debug)' : ''}\n`);
32+
console.log(chalk.gray('To force a different target:'));
33+
console.log(chalk.gray(` npm run releaseSrc -- tauri # Force Tauri build`));
34+
console.log(chalk.gray(` npm run releaseSrc -- electron # Force Electron build`));
35+
console.log(chalk.gray(` npm run releaseSrcDebug -- tauri # Force Tauri debug build\n`));
36+
37+
// Warn about non-standard platform/target combinations
38+
const recommendedTarget = (platform === 'linux') ? 'electron' : 'tauri';
39+
if (target !== recommendedTarget) {
40+
const y = chalk.yellow;
41+
const b = chalk.bold.yellow;
42+
const line1 = ` Building ${target} on ${platform} is not officially supported.`;
43+
const line2 = ` Recommended: npm run releaseSrc (auto-detects ${recommendedTarget} for ${platform})`;
44+
const width = Math.max(50, line1.length, line2.length) + 2;
45+
const border = '═'.repeat(width);
46+
const pad = (str) => str + ' '.repeat(width - str.length);
47+
48+
console.warn(y(`╔${border}╗`));
49+
console.warn(y('║') + b(pad(' ⚠️ NON-STANDARD PLATFORM CONFIGURATION')) + y('║'));
50+
console.warn(y(`╠${border}╣`));
51+
console.warn(y('║') + y(pad(line1)) + y('║'));
52+
console.warn(y('║') + y(pad(line2)) + y('║'));
53+
console.warn(y(`╚${border}╝\n`));
54+
}
55+
56+
function run(cmd, options = {}) {
57+
console.log(chalk.blue(`> ${cmd}`));
58+
execSync(cmd, { stdio: 'inherit', ...options });
59+
}
60+
61+
function setupSrcNode(targetDir) {
62+
console.log(chalk.cyan('\n=== Setting up src-node ===\n'));
63+
const srcNodeSource = join(projectRoot, '..', 'phoenix', 'src-node');
64+
const destPath = join(projectRoot, targetDir, 'src-node');
65+
66+
console.log(`Setting up ${destPath}...`);
67+
run(`shx rm -rf "${destPath}"`);
68+
run(`shx cp -r "${srcNodeSource}" "${destPath}"`);
69+
console.log('Installing production dependencies...');
70+
execSync('npm ci --production', { cwd: destPath, stdio: 'inherit' });
71+
// Remove unsupported musl binaries
72+
execSync(`shx rm -f "${destPath}/node_modules/@msgpackr-extract/msgpackr-extract-linux-*/*.musl.node"`, { stdio: 'pipe' });
73+
execSync(`shx rm -f "${destPath}/node_modules/@lmdb/lmdb-linux-*/*.musl.node"`, { stdio: 'pipe' });
74+
}
75+
76+
function createTauriConfig() {
77+
console.log(chalk.cyan('\n=== Creating Tauri Config ===\n'));
78+
const tauriConfigPath = join(projectRoot, 'src-tauri', 'tauri.conf.json');
79+
const tauriLocalConfigPath = join(projectRoot, 'src-tauri', 'tauri-local.conf.json');
80+
81+
console.log('Reading config file:', tauriConfigPath);
82+
let configJson = JSON.parse(fs.readFileSync(tauriConfigPath));
83+
84+
console.log(chalk.cyan('!Only creating executables. Installers are disabled.\n'));
85+
configJson.tauri.bundle.active = false;
86+
configJson.build.distDir = '../../phoenix/src/';
87+
88+
const phoenixVersion = configJson.package.version;
89+
if (os.platform() === 'win32') {
90+
configJson.tauri.windows[0].url = `https://phtauri.localhost/v${phoenixVersion}/`;
91+
configJson.tauri.windows[2].url = `https://phtauri.localhost/v${phoenixVersion}/drop-files.html`;
92+
} else {
93+
configJson.tauri.windows[0].url = `phtauri://localhost/v${phoenixVersion}/`;
94+
configJson.tauri.windows[2].url = `phtauri://localhost/v${phoenixVersion}/drop-files.html`;
95+
}
96+
97+
if (os.platform() === 'darwin') {
98+
configJson.tauri.bundle.icon = [
99+
"icons-mac/32x32.png", "icons-mac/128x128.png",
100+
"icons-mac/128x128@2x.png", "icons-mac/icon.icns", "icons-mac/icon.ico"
101+
];
102+
}
103+
104+
console.log('Window Boot url:', configJson.tauri.windows[0].url);
105+
fs.writeFileSync(tauriLocalConfigPath, JSON.stringify(configJson, null, 4));
106+
}
107+
108+
function buildTauri() {
109+
console.log(chalk.cyan('\n=== Building Tauri ===\n'));
110+
setupSrcNode('src-tauri');
111+
createTauriConfig();
112+
const debugFlags = isDebug ? '--debug --verbose' : '';
113+
run(`tauri build --config ./src-tauri/tauri-local.conf.json ${debugFlags}`.trim());
114+
}
115+
116+
function createElectronConfig() {
117+
console.log(chalk.cyan('\n=== Creating Electron Config ===\n'));
118+
const electronDir = join(projectRoot, 'src-electron');
119+
const configPath = join(electronDir, 'config.json');
120+
const configDevPath = join(electronDir, 'config-dev.json');
121+
const configEffectivePath = join(electronDir, 'config-effective.json');
122+
123+
console.log('Merging config.json + config-dev.json -> config-effective.json');
124+
const baseConfig = JSON.parse(fs.readFileSync(configPath));
125+
const devConfig = JSON.parse(fs.readFileSync(configDevPath));
126+
127+
// Merge: config-dev.json overrides config.json
128+
const effectiveConfig = { ...baseConfig, ...devConfig };
129+
130+
console.log('phoenixLoadURL:', effectiveConfig.phoenixLoadURL);
131+
console.log('gaMetricsURL:', effectiveConfig.gaMetricsURL);
132+
fs.writeFileSync(configEffectivePath, JSON.stringify(effectiveConfig, null, 2));
133+
}
134+
135+
function buildElectron() {
136+
console.log(chalk.cyan('\n=== Building Electron AppImage ===\n'));
137+
setupSrcNode('src-electron');
138+
createElectronConfig();
139+
140+
const phoenixDir = join(projectRoot, '..', 'phoenix');
141+
const phoenixDistSrc = join(phoenixDir, 'dist');
142+
const phoenixDistDest = join(projectRoot, 'src-electron', 'phoenix-dist');
143+
144+
// Build phoenix production dist
145+
console.log('Building Phoenix production dist...');
146+
run('npm run release:prod', { cwd: phoenixDir });
147+
148+
// Copy dist to electron
149+
console.log('Copying phoenix dist...');
150+
run(`shx rm -rf "${phoenixDistDest}"`);
151+
run(`shx cp -r "${phoenixDistSrc}" "${phoenixDistDest}"`);
152+
153+
// Build AppImage
154+
console.log('Building AppImage...');
155+
run('npm run build:appimage', { cwd: join(projectRoot, 'src-electron') });
156+
}
157+
158+
async function main() {
159+
if (target === 'tauri') {
160+
buildTauri();
161+
} else {
162+
buildElectron();
163+
}
164+
165+
console.log(chalk.green('\n=== Release build complete! ===\n'));
166+
}
167+
168+
main().catch(err => {
169+
console.error(chalk.red('Build failed:'), err);
170+
process.exit(1);
171+
});

src-build/createSrcReleaseConfig.js

Lines changed: 0 additions & 46 deletions
This file was deleted.

src-electron/config-dev.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"phoenixLoadURL": "phtauri://localhost/",
3+
"gaMetricsURL": "phtauri://localhost/desktop-metrics.html"
4+
}

src-electron/config-prod.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
"identifier": "io.phcode",
33
"stage": "production",
44
"productName": "Phoenix Code",
5+
"phoenixLoadURL": "phtauri://localhost/",
56
"gaMetricsURL": "https://phcode.dev/desktop-metrics.html"
67
}

src-electron/config-staging.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"identifier": "io.phcode.staging",
33
"stage": "stage",
44
"productName": "Phoenix Code Pre-release",
5+
"phoenixLoadURL": "phtauri://localhost/",
56
"trustedElectronDomains": ["phtauri://localhost/", "https://phcode.dev/", "https://staging.phcode.dev/"],
67
"gaMetricsURL": "https://staging.phcode.dev/desktop-metrics.html"
78
}

src-electron/main.js

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -210,25 +210,17 @@ app.whenReady().then(async () => {
210210
Menu.setApplicationMenu(null);
211211

212212
// Register phtauri:// protocol for serving Phoenix files
213-
// In dev: serves from ../phoenix/ repo (phtauri://localhost/src/ -> ../phoenix/src/)
214-
// In packaged: serves from resources/phoenix-dist/ (phtauri://localhost/src/ -> phoenix-dist/)
213+
// In dev: serves from ../phoenix/ (URL includes /src/ prefix from config.json)
214+
// In packaged: serves from resources/phoenix-dist (URL has no /src/ prefix)
215215
const phoenixBasePath = app.isPackaged
216216
? path.join(process.resourcesPath, 'phoenix-dist')
217-
: path.resolve(__dirname, '..', '..', 'phoenix', 'src');
217+
: path.resolve(__dirname, '..', '..', 'phoenix');
218218

219219
protocol.handle('phtauri', (request) => {
220220
try {
221221
const url = new URL(request.url);
222-
// phtauri://localhost/src/index.html -> strip /src prefix
223222
let requestedPath = decodeURIComponent(url.pathname);
224223

225-
// Strip /src/ prefix since phoenix-dist already contains src contents
226-
if (requestedPath.startsWith('/src/')) {
227-
requestedPath = requestedPath.substring(4); // Remove '/src'
228-
} else if (requestedPath === '/src') {
229-
requestedPath = '/';
230-
}
231-
232224
// Serve index.html for directory requests
233225
if (requestedPath.endsWith('/')) {
234226
requestedPath += 'index.html';

0 commit comments

Comments
 (0)