mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-04-25 08:46:22 +02:00
136 lines
4.4 KiB
JavaScript
136 lines
4.4 KiB
JavaScript
import { build } from 'esbuild';
|
|
import fs from 'fs';
|
|
import path from 'path';
|
|
import dotenv from 'dotenv';
|
|
|
|
const desktopEnv = dotenv.config().parsed || {};
|
|
|
|
const STANDALONE_ROOT = path.join(
|
|
'..', 'surfsense_web', '.next', 'standalone', 'surfsense_web'
|
|
);
|
|
|
|
/**
|
|
* electron-builder cannot follow symlinks when packaging into ASAR.
|
|
* Recursively walk the standalone output and replace every symlink
|
|
* with a real copy (or remove it if the target doesn't exist).
|
|
*/
|
|
function resolveAllSymlinks(dir) {
|
|
if (!fs.existsSync(dir)) return;
|
|
|
|
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
const full = path.join(dir, entry.name);
|
|
if (entry.isSymbolicLink()) {
|
|
const target = fs.readlinkSync(full);
|
|
const resolved = path.resolve(dir, target);
|
|
if (fs.existsSync(resolved)) {
|
|
fs.rmSync(full, { recursive: true, force: true });
|
|
fs.cpSync(resolved, full, { recursive: true });
|
|
console.log(`Resolved symlink: ${full}`);
|
|
} else {
|
|
fs.rmSync(full, { force: true });
|
|
console.log(`Removed broken symlink: ${full}`);
|
|
}
|
|
} else if (entry.isDirectory()) {
|
|
resolveAllSymlinks(full);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* pnpm's .pnpm/ virtual store uses symlinks for sibling dependency resolution.
|
|
* After resolveAllSymlinks converts everything to real copies, packages can no
|
|
* longer find their dependencies through the pnpm structure. We flatten the
|
|
* tree into a standard npm-like layout: every package from .pnpm/*/node_modules/
|
|
* gets hoisted to the top-level node_modules/. This lets Node.js standard
|
|
* module resolution find all dependencies (e.g. next → styled-jsx).
|
|
*/
|
|
function flattenPnpmStore(nodeModulesDir) {
|
|
const pnpmDir = path.join(nodeModulesDir, '.pnpm');
|
|
if (!fs.existsSync(pnpmDir)) return;
|
|
|
|
console.log('Flattening pnpm store to top-level node_modules...');
|
|
let hoisted = 0;
|
|
|
|
for (const storePkg of fs.readdirSync(pnpmDir, { withFileTypes: true })) {
|
|
if (!storePkg.isDirectory() || storePkg.name === 'node_modules') continue;
|
|
|
|
const innerNM = path.join(pnpmDir, storePkg.name, 'node_modules');
|
|
if (!fs.existsSync(innerNM)) continue;
|
|
|
|
for (const dep of fs.readdirSync(innerNM, { withFileTypes: true })) {
|
|
const depName = dep.name;
|
|
// Handle scoped packages (@org/pkg)
|
|
if (depName.startsWith('@') && dep.isDirectory()) {
|
|
const scopeDir = path.join(innerNM, depName);
|
|
for (const scopedPkg of fs.readdirSync(scopeDir, { withFileTypes: true })) {
|
|
const fullName = `${depName}/${scopedPkg.name}`;
|
|
const src = path.join(scopeDir, scopedPkg.name);
|
|
const dest = path.join(nodeModulesDir, depName, scopedPkg.name);
|
|
if (!fs.existsSync(dest)) {
|
|
fs.mkdirSync(path.join(nodeModulesDir, depName), { recursive: true });
|
|
fs.cpSync(src, dest, { recursive: true });
|
|
hoisted++;
|
|
}
|
|
}
|
|
} else if (dep.isDirectory() || dep.isFile()) {
|
|
const dest = path.join(nodeModulesDir, depName);
|
|
if (!fs.existsSync(dest)) {
|
|
fs.cpSync(path.join(innerNM, depName), dest, { recursive: true });
|
|
hoisted++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Remove the .pnpm directory — no longer needed
|
|
fs.rmSync(pnpmDir, { recursive: true, force: true });
|
|
console.log(`Hoisted ${hoisted} packages, removed .pnpm/`);
|
|
}
|
|
|
|
function resolveStandaloneSymlinks() {
|
|
console.log('Resolving symlinks in standalone output...');
|
|
resolveAllSymlinks(STANDALONE_ROOT);
|
|
flattenPnpmStore(path.join(STANDALONE_ROOT, 'node_modules'));
|
|
}
|
|
|
|
async function buildElectron() {
|
|
if (fs.existsSync('dist')) {
|
|
fs.rmSync('dist', { recursive: true });
|
|
console.log('Cleaned dist/');
|
|
}
|
|
fs.mkdirSync('dist', { recursive: true });
|
|
|
|
const shared = {
|
|
bundle: true,
|
|
platform: 'node',
|
|
target: 'node18',
|
|
external: ['electron'],
|
|
sourcemap: true,
|
|
minify: false,
|
|
define: {
|
|
'process.env.HOSTED_FRONTEND_URL': JSON.stringify(
|
|
process.env.HOSTED_FRONTEND_URL || desktopEnv.HOSTED_FRONTEND_URL || 'https://surfsense.net'
|
|
),
|
|
},
|
|
};
|
|
|
|
await build({
|
|
...shared,
|
|
entryPoints: ['src/main.ts'],
|
|
outfile: 'dist/main.js',
|
|
});
|
|
|
|
await build({
|
|
...shared,
|
|
entryPoints: ['src/preload.ts'],
|
|
outfile: 'dist/preload.js',
|
|
});
|
|
|
|
console.log('Electron build complete');
|
|
resolveStandaloneSymlinks();
|
|
}
|
|
|
|
buildElectron().catch((err) => {
|
|
console.error(err);
|
|
process.exit(1);
|
|
});
|