UNPKG

mixone

Version:

A cross-platform desktop application framework that enables development using JavaScript, HTML5, Electron API and Node.js. Build Windows, macOS and Linux apps with Vue/React and system APIs - that's why we call it mixone.A powerful Electron development in

267 lines (245 loc) 8.08 kB
const { spawn, exec } = require('child_process'); const path = require('path'); const fs = require('fs'); const chokidar = require('chokidar'); const iconv = require('iconv-lite'); // 新增 FileWatcher 类 class FileWatcher { constructor(electronManager, watchDir, ignorePatterns) { this.electronManager = electronManager; this.watchDir = watchDir; this.ignorePatterns = ignorePatterns; this.watcher = null; this.reloadDebounce = null; } initialize() { this.watcher = chokidar.watch(this.watchDir, { ignored: this.ignorePatterns, ignoreInitial: true, awaitWriteFinish: { stabilityThreshold: 500, pollInterval: 100 } }); this.watcher.on('all', this.handleFileChange.bind(this)); this.watcher.on('error', this.handleError.bind(this)); } async handleFileChange(event, filePath) { if (['add', 'change', 'unlink'].includes(event)) { console.log(`🔄 检测到 ${filePath} ${event},触发重启...`); clearTimeout(this.reloadDebounce); this.reloadDebounce = setTimeout(async () => { await this.electronManager.restart(); }, 50); } } handleError(error) { console.error('文件监听错误:', error); } async close() { if (this.watcher) { await this.watcher.close(); // console.log('✅ 已关闭文件监听器'); } } } // 新增 Electron 进程管理类 class ElectronManager { constructor() { this.electronProcess = null; this.restarting = false; // 新增状态文件路径属性 this.stateFilePath = path.join(require('os').tmpdir(), 'window-states.txt'); } // 启动 Electron 进程 start(args = []) { const defaultArgs = ['electron','.', '--dev']; console.log('启动 Electron 进程...',defaultArgs,args); this.electronProcess = spawn('npx', [...defaultArgs, ...args], { stdio: 'inherit', shell: true }); // 监听进程意外退出 this.electronProcess.on('exit', async (code) => { console.log(`Electron 进程已退出,退出码: ${code}`); if (!this.restarting) { await cleanup(); process.exit(code); } }); } // 终止 Electron 进程(返回 Promise) async stop() { if (!this.electronProcess) return; return new Promise((resolve) => { this.restarting = true; // Windows 使用 taskkill 强制终止进程树 exec(`taskkill /F /T /PID ${this.electronProcess.pid}`, (error) => { this.electronProcess = null; this.restarting = false; if (error) console.error('终止进程失败:', error.message); resolve(); }); }); } // 重启应用 async restart() { await this.stop(); this.start([`--window-states=${this.stateFilePath}`]); console.log('✅ Electron 进程已重启'); } } // 在文件顶部声明实例 const electronManager = new ElectronManager(); // 初始化文件监听 const fileWatcher = new FileWatcher( electronManager, path.join(process.cwd(), 'main'), [ /(^|[/\\])\../, '**/node_modules/**', '**/*fn.js' ] ); // 解析命令行参数 const args = process.argv.slice(2); const shouldLaunchElectron = args.includes('--electron'); const shouldOpen = args.includes('--open'); console.log(`是否启动 Electron: ${shouldLaunchElectron}`); console.log(`是否自动打开浏览器: ${shouldOpen}`); let electronStarted = false; // let electronProcess = null; let viteProcess = null; function killProcessOnPort(port) { const { exec } = require('child_process'); exec(`netstat -ano | findstr :${port}`, (err, stdout, stderr) => { if (err || !stdout) { console.log(`未找到占用端口 ${port} 的进程`); return; } // 解析 PID const lines = stdout.trim().split('\n'); const pids = new Set(); lines.forEach(line => { const parts = line.trim().split(/\s+/); const pid = parts[parts.length - 1]; if (pid && !isNaN(pid)) { pids.add(pid); } }); if (pids.size === 0) { console.log(`未找到占用端口 ${port} 的进程`); return; } // 杀掉所有相关进程 pids.forEach(pid => { if(pid==0){ return; } exec(`taskkill /F /PID ${pid}`, (killErr) => { if (killErr) { // console.log(`杀掉进程 ${pid} 失败: ${killErr.message}`); } else { // console.log(`成功杀掉占用端口 ${port} 的进程 PID: ${pid}`); } }); }); }); } // 清理进程的函数 async function cleanup() { // console.log('开始清理进程...'); // 关闭文件监听器 if (fileWatcher) { await fileWatcher.close(); } await electronManager.stop(); // 使用管理器停止 // 如果 Electron 进程存在,杀掉它 // if (electronProcess) { // try { // process.kill(electronProcess.pid); // console.log('✅ Electron 进程已清理'); // } catch (err) { // console.log(`清理 Electron 进程失败: ${err.message}`); // } // } // 查找并杀死所有相关的 node 进程 // try { // // Windows 下使用 taskkill 命令 // exec('taskkill /F /IM node.exe', (error, stdout, stderr) => { // if (error) { // console.log(`清理 node 进程失败: ${error.message}`); // return; // } // console.log('✅ node 进程已清理'); // }); // } catch (err) { // console.log(`执行清理命令失败fail 123: ${err.message}`); // } // 尝试删除 dev-server.json const serverInfoPath = path.resolve(process.cwd(), 'main/dev-server.json'); if (fs.existsSync(serverInfoPath)) { const content = fs.readFileSync(serverInfoPath, 'utf-8'); const json = JSON.parse(content); const url = json.url; // 例如 "http://localhost:5174" const port = url.match(/:(\d+)/) ? url.match(/:(\d+)/)[1] : null; killProcessOnPort(port); } if (fs.existsSync(serverInfoPath)) { try { fs.unlinkSync(serverInfoPath); console.log('✅ 已删除 dev-server.json'); } catch (err) { console.log(`删除 dev-server.json 失败: ${err.message}`); } } // 确保所有进程都有时间被清理 await new Promise(resolve => setTimeout(resolve, 1000)); } // 注册进程退出事件 process.on('SIGINT', async () => { await cleanup(); process.exit(0); }); process.on('SIGTERM', async () => { await cleanup(); process.exit(0); }); process.on('exit', cleanup); // 启动 Vite 服务 const viteArgs = ['vite','--config', 'vite.electron.serve.config.js']; if (shouldOpen) { viteArgs.push('--open'); } console.log('启动 Vite 服务...',viteArgs,path.join(process.cwd(), 'windows')); viteProcess = spawn('npx', viteArgs, { cwd: path.join(process.cwd(), 'windows'), stdio: ['inherit', 'pipe', 'pipe'], shell: true }); // 监听 Vite 服务的输出 viteProcess.stdout.on('data', (data) => { console.log("data -- >") const output = iconv.decode(data, 'utf-8'); process.stdout.write(output); // 检查 dev-server.json 是否存在 const serverInfoPath = path.resolve(process.cwd(), 'main/dev-server.json'); if (!electronStarted && shouldLaunchElectron && fs.existsSync(serverInfoPath)) { electronStarted = true; console.log('✅ Vite 服务已启动,正在启动 Electron...'); electronManager.start(); // 使用管理器启动 fileWatcher.initialize(); } }); // 监听 Vite 服务的错误 viteProcess.stderr.on('data', (data) => { console.log("data err -- >",data.toString()) const output = iconv.decode(data, 'utf-8'); process.stdout.write(output); }); // 监听 Vite 服务退出 viteProcess.on('exit', async (code) => { console.log(`Vite 服务已退出,退出码: ${code}`); await cleanup(); process.exit(code); });