/* * Copyright (C) 2026 Fluxer Contributors * * This file is part of Fluxer. * * Fluxer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Fluxer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Fluxer. If not, see . */ import * as fs from 'node:fs'; import * as path from 'node:path'; import * as esbuild from 'esbuild'; const ROOT_DIR = path.resolve(import.meta.dirname, '..'); const SRC_DIR = path.join(ROOT_DIR, 'src'); const DIST_DIR = path.join(ROOT_DIR, 'dist'); const isProduction = process.env.NODE_ENV === 'production'; const electronExternals = [ 'electron', 'electron-log', 'electron-squirrel-startup', 'electron-webauthn-mac', 'update-electron-app', '@electron-webauthn/native', 'uiohook-napi', 'node-mac-permissions', ]; const pathAliasPlugin = { name: 'path-alias', setup(build) { build.onResolve({filter: /^@electron\//}, (args) => { const relativePath = args.path.replace(/^@electron\//, ''); const absolutePath = path.join(SRC_DIR, relativePath); const extensions = ['.tsx', '.ts', '.js', '.jsx']; for (const ext of extensions) { const fullPath = absolutePath + ext; if (fs.existsSync(fullPath)) { return {path: fullPath}; } } for (const ext of extensions) { const indexPath = path.join(absolutePath, `index${ext}`); if (fs.existsSync(indexPath)) { return {path: indexPath}; } } return {path: `${absolutePath}.tsx`}; }); }, }; async function buildMain() { console.log('Building main process...'); await esbuild.build({ entryPoints: [path.join(SRC_DIR, 'main', 'index.tsx')], bundle: true, platform: 'node', target: 'node20', format: 'esm', outfile: path.join(DIST_DIR, 'main', 'index.js'), minify: isProduction, sourcemap: true, external: electronExternals, plugins: [pathAliasPlugin], define: { 'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development'), }, banner: { js: `import { createRequire } from 'module'; const require = createRequire(import.meta.url);`, }, }); console.log('Main process build complete.'); } async function buildPreload() { console.log('Building preload script...'); await esbuild.build({ entryPoints: [path.join(SRC_DIR, 'preload', 'index.tsx')], bundle: true, platform: 'node', target: 'node20', format: 'cjs', outfile: path.join(DIST_DIR, 'preload', 'index.js'), minify: isProduction, sourcemap: true, external: electronExternals, plugins: [pathAliasPlugin], define: { 'process.env.NODE_ENV': JSON.stringify(isProduction ? 'production' : 'development'), }, }); console.log('Preload script build complete.'); } async function build() { console.log(`Building Electron app (${isProduction ? 'production' : 'development'})...`); if (fs.existsSync(DIST_DIR)) { fs.rmSync(DIST_DIR, {recursive: true}); } fs.mkdirSync(path.join(DIST_DIR, 'main'), {recursive: true}); fs.mkdirSync(path.join(DIST_DIR, 'preload'), {recursive: true}); await Promise.all([buildMain(), buildPreload()]); console.log('Build complete!'); } build().catch((error) => { console.error('Build failed:', error); process.exit(1); });