process.env.NODE_ENV = "development"; import electron from "electron"; import chalk from "chalk"; import {join} from "path"; import {watch} from "rollup"; import Portfinder from "portfinder"; import config from "../config"; import {say} from "cfonts"; import {spawn} from "child_process"; import type {ChildProcess} from "child_process"; import rollupOptions from "./rollup.config"; const mainOpt = rollupOptions(process.env.NODE_ENV, "main"); const preloadOpt = rollupOptions(process.env.NODE_ENV, "preload"); let electronProcess: ChildProcess | null = null; let manualRestart = false; function logStats(proc: string, data: any) { let log = ""; log += chalk.yellow.bold( `┏ ${proc} ${config.dev.chineseLog ? "编译过程" : "Process"} ${new Array( 19 - proc.length + 1 ).join("-")}` ); log += "\n\n"; if (typeof data === "object") { data .toString({ colors: true, chunks: false, }) .split(/\r?\n/) .forEach((line) => { log += " " + line + "\n"; }); } else { log += ` ${data}\n`; } log += "\n" + chalk.yellow.bold(`┗ ${new Array(28 + 1).join("-")}`) + "\n"; console.log(log); } function removeJunk(chunk: string) { if (config.dev.removeElectronJunk) { // Example: 2018-08-10 22:48:42.866 Electron[90311:4883863] *** WARNING: Textured window if ( /\d+-\d+-\d+ \d+:\d+:\d+\.\d+ Electron(?: Helper)?\[\d+:\d+] /.test(chunk) ) { return false; } // Example: [90789:0810/225804.894349:ERROR:CONSOLE(105)] "Uncaught (in promise) Error: Could not instantiate: ProductRegistryImpl.Registry", source: chrome-devtools://devtools/bundled/inspector.js (105) if (/\[\d+:\d+\/|\d+\.\d+:ERROR:CONSOLE\(\d+\)\]/.test(chunk)) { return false; } // Example: ALSA lib confmisc.c:767:(parse_card) cannot find card '0' if (/ALSA lib [a-z]+\.c:\d+:\([a-z_]+\)/.test(chunk)) { return false; } } return chunk; } function startRenderer(): Promise { return new Promise((resolve, reject) => { Portfinder.basePort = config.dev.port || 9080; Portfinder.getPort(async (err, port) => { if (err) { reject("PortError:" + err); } else { const {createServer} = await import("vite"); const server = await createServer({ configFile: join(__dirname, "vite.config.mts"), }); process.env.PORT = String(port); await server.listen(port); console.log( "\n\n" + chalk.blue( `${ config.dev.chineseLog ? " 正在准备主进程,请等待..." : " Preparing main process, please wait..." }` ) + "\n\n" ); resolve(); } }); }); } function startMain(): Promise { return new Promise((resolve, reject) => { const MainWatcher = watch(mainOpt); MainWatcher.on("change", (filename) => { // 主进程日志部分 logStats( `${config.dev.chineseLog ? "主进程文件变更" : "Main-FileChange"}`, filename ); }); MainWatcher.on("event", (event) => { if (event.code === "END") { if (electronProcess) { manualRestart = true; electronProcess.pid && process.kill(electronProcess.pid); electronProcess = null; startElectron(); setTimeout(() => { manualRestart = false; }, 5000); } resolve(); } else if (event.code === "ERROR") { reject(event.error); } }); }); } function startPreload(): Promise { console.log( "\n\n" + chalk.blue( `${ config.dev.chineseLog ? " 正在准备预加载脚本,请等待..." : " Preparing preLoad File, please wait..." }` ) + "\n\n" ); return new Promise((resolve, reject) => { const PreloadWatcher = watch(preloadOpt); PreloadWatcher.on("change", (filename) => { // 预加载脚本日志部分 logStats( `${ config.dev.chineseLog ? "预加载脚本文件变更" : "preLoad-FileChange" }`, filename ); }); PreloadWatcher.on("event", (event) => { if (event.code === "END") { if (electronProcess) { manualRestart = true; electronProcess.pid && process.kill(electronProcess.pid); electronProcess = null; startElectron(); setTimeout(() => { manualRestart = false; }, 5000); } resolve(); } else if (event.code === "ERROR") { reject(event.error); } }); }); } function startElectron() { let args = [ "--inspect=5858", join(__dirname, "../dist/electron/main/main.js"), ]; // detect yarn or npm and process commandline args accordingly if (process.env.npm_execpath?.endsWith("yarn.js")) { args = args.concat(process.argv.slice(3)); } else if (process.env.npm_execpath?.endsWith("npm-cli.js")) { args = args.concat(process.argv.slice(2)); } electronProcess = spawn(electron as any, args); electronProcess.stdout?.on("data", (data: string) => { electronLog(removeJunk(data), "blue"); }); electronProcess.stderr?.on("data", (data: string) => { electronLog(removeJunk(data), "red"); }); electronProcess.on("close", () => { if (!manualRestart) process.exit(); }); } function electronLog(data: any, color: string) { if (data) { let log = ""; data = data.toString().split(/\r?\n/); data.forEach((line) => { log += ` ${line}\n`; }); console.log( chalk[color].bold( `┏ ${ config.dev.chineseLog ? "主程序日志" : "Electron" } -------------------` ) + "\n\n" + log + chalk[color].bold("┗ ----------------------------") + "\n" ); } } function greeting(arg: string) { const cols = process.stdout.columns; let text: string; text = arg ? arg : "Hi-Sass"; let length = text ? text.length : 0; if (cols > 104) { text = length > 104 ? text.slice(0, 103) : text; } else if (cols > 76) { text = length > 76 ? text.slice(0, 75) : text; } else text = ""; if (text) { say(text, { colors: ["yellow"], font: "simple3d", space: false, }); } else console.log(chalk.yellow.bold("\n electron-vite")); console.log( chalk.blue( `${config.dev.chineseLog ? " 准备启动..." : " getting ready..."}` ) + "\n" ); } async function init() { greeting("Hi-Sass"); try { await startRenderer(); await startMain(); await startPreload(); startElectron(); } catch (error) { console.error(error); process.exit(1); } } init();