Files
Web2App/template/main.js
gmh01 2f3ec636e0 feat: 完成 Web2App 核心功能实现
- Electron 主进程:窗口管理、IPC、项目读写、打包引擎
- Vue 3 前端:4 个视图页面、3 个组件、Pinia 状态管理
- 生成应用模板:Express 后端 + Electron 窗口
- 支持资源导入、应用配置、跨平台打包
2026-07-23 18:25:35 +08:00

121 lines
3.0 KiB
JavaScript

const { app, BrowserWindow, Tray, Menu, nativeImage } = require('electron')
const path = require('path')
const fs = require('fs')
const express = require('express')
const cors = require('cors')
let mainWindow
let tray
let server
const FRONTEND_DIR = path.join(__dirname, 'frontend')
const BACKEND_DIR = path.join(__dirname, 'backend')
const ICON_PATH = path.join(__dirname, 'icon.png')
function startBackend() {
return new Promise((resolve, reject) => {
const serverApp = express()
serverApp.use(cors())
serverApp.use(express.json())
const backendEntry = path.join(BACKEND_DIR, 'server.js')
if (fs.existsSync(backendEntry)) {
try {
const userApi = require(backendEntry)
if (typeof userApi === 'function') {
userApi(serverApp)
} else if (userApi && typeof userApi.setup === 'function') {
userApi.setup(serverApp)
}
} catch (err) {
console.error('后端加载失败:', err)
}
}
server = serverApp.listen(0, () => {
const port = server.address().port
console.log(`后端服务运行于端口: ${port}`)
resolve(port)
})
})
}
function createWindow(port) {
const icon = fs.existsSync(ICON_PATH) ? nativeImage.createFromPath(ICON_PATH) : undefined
mainWindow = new BrowserWindow({
width: 1200,
height: 800,
minWidth: 800,
minHeight: 600,
icon,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true,
nodeIntegration: false
},
show: false
})
const indexPath = path.join(FRONTEND_DIR, 'index.html')
if (fs.existsSync(indexPath)) {
mainWindow.loadFile(indexPath)
} else {
mainWindow.loadURL(`http://localhost:${port}`)
}
mainWindow.once('ready-to-show', () => {
mainWindow.show()
})
mainWindow.on('close', (event) => {
if (tray) {
event.preventDefault()
mainWindow.hide()
}
})
}
function setupTray() {
const iconPath = path.join(__dirname, 'tray-icon.png')
const icon = fs.existsSync(iconPath)
? nativeImage.createFromPath(iconPath).resize({ width: 16, height: 16 })
: nativeImage.createEmpty()
tray = new Tray(icon)
const contextMenu = Menu.buildFromTemplate([
{ label: '显示', click: () => mainWindow.show() },
{ label: '退出', click: () => { app.isQuitting = true; app.quit() } }
])
tray.setToolTip('Web2App Generated Application')
tray.setContextMenu(contextMenu)
tray.on('click', () => mainWindow.show())
}
app.whenReady().then(async () => {
try {
const port = await startBackend()
createWindow(port)
setupTray()
} catch (err) {
console.error('启动失败:', err)
createWindow(3000)
setupTray()
}
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow(3000)
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
app.on('before-quit', () => {
app.isQuitting = true
if (server) server.close()
})