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

187 lines
5.0 KiB
JavaScript

const fs = require('fs')
const path = require('path')
function getProjectDir(projectPath) {
return projectPath
}
function getSrcDir(projectPath) {
const dir = path.join(projectPath, '.web2app', 'src')
fs.mkdirSync(dir, { recursive: true })
return dir
}
function getConfigPath(projectPath) {
return path.join(projectPath, '.web2app', 'project.json')
}
function getDistDir(projectPath) {
const dir = path.join(projectPath, '.web2app', 'dist')
fs.mkdirSync(dir, { recursive: true })
return dir
}
function createProject(name, dir) {
const projectPath = path.join(dir, name)
if (fs.existsSync(projectPath)) {
throw new Error(`目录 ${projectPath} 已存在`)
}
fs.mkdirSync(path.join(projectPath, '.web2app', 'src'), { recursive: true })
fs.mkdirSync(path.join(projectPath, '.web2app', 'dist'), { recursive: true })
const config = {
name,
version: '1.0.0',
description: '',
author: '',
entry: 'index.html',
backendEntry: '',
windowWidth: 1200,
windowHeight: 800,
minWidth: 800,
minHeight: 600,
resizable: true,
icon: '',
copyright: '',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString()
}
fs.writeFileSync(getConfigPath(projectPath), JSON.stringify(config, null, 2))
return { projectPath, config }
}
function loadProject(projectPath) {
const configPath = getConfigPath(projectPath)
if (!fs.existsSync(configPath)) {
throw new Error('不是有效的 Web2App 项目')
}
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
const srcDir = getSrcDir(projectPath)
const files = readFileTree(srcDir)
return { projectPath, config, files }
}
function saveProject(projectPath, data) {
const configPath = getConfigPath(projectPath)
const existing = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
const updated = { ...existing, ...data, updatedAt: new Date().toISOString() }
fs.writeFileSync(configPath, JSON.stringify(updated, null, 2))
return updated
}
function importFiles(projectPath, files) {
const srcDir = getSrcDir(projectPath)
const imported = []
for (const filePath of files) {
const stat = fs.statSync(filePath)
if (stat.isDirectory()) {
const destDir = path.join(srcDir, path.basename(filePath))
copyDirSync(filePath, destDir)
imported.push({ source: filePath, dest: destDir })
} else {
const destPath = path.join(srcDir, path.basename(filePath))
fs.copyFileSync(filePath, destPath)
imported.push({ source: filePath, dest: destPath })
}
}
return readFileTree(srcDir)
}
function removeFile(projectPath, relativePath) {
const srcDir = getSrcDir(projectPath)
const fullPath = path.join(srcDir, relativePath)
if (!fs.existsSync(fullPath)) {
throw new Error(`文件不存在: ${relativePath}`)
}
const stat = fs.statSync(fullPath)
if (stat.isDirectory()) {
fs.rmSync(fullPath, { recursive: true, force: true })
} else {
fs.unlinkSync(fullPath)
}
return readFileTree(srcDir)
}
function setProjectIcon(projectPath, iconPath) {
const srcDir = getSrcDir(projectPath)
const ext = path.extname(iconPath)
const destName = `app-icon${ext}`
const destPath = path.join(srcDir, destName)
fs.copyFileSync(iconPath, destPath)
const config = JSON.parse(fs.readFileSync(getConfigPath(projectPath), 'utf-8'))
config.icon = destName
fs.writeFileSync(getConfigPath(projectPath), JSON.stringify(config, null, 2))
return config
}
function readFileTree(dirPath, basePath = '') {
const items = []
if (!fs.existsSync(dirPath)) return items
const entries = fs.readdirSync(dirPath, { withFileTypes: true })
for (const entry of entries) {
if (entry.name.startsWith('.')) continue
const relativePath = basePath ? path.join(basePath, entry.name) : entry.name
const fullPath = path.join(dirPath, entry.name)
if (entry.isDirectory()) {
items.push({
name: entry.name,
path: relativePath,
type: 'directory',
children: readFileTree(fullPath, relativePath)
})
} else {
items.push({
name: entry.name,
path: relativePath,
type: 'file',
size: fs.statSync(fullPath).size,
ext: path.extname(entry.name).toLowerCase()
})
}
}
items.sort((a, b) => {
if (a.type !== b.type) return a.type === 'directory' ? -1 : 1
return a.name.localeCompare(b.name)
})
return items
}
function copyDirSync(src, dest) {
fs.mkdirSync(dest, { recursive: true })
const entries = fs.readdirSync(src, { withFileTypes: true })
for (const entry of entries) {
if (entry.name.startsWith('.')) continue
const srcPath = path.join(src, entry.name)
const destPath = path.join(dest, entry.name)
if (entry.isDirectory()) {
copyDirSync(srcPath, destPath)
} else {
fs.copyFileSync(srcPath, destPath)
}
}
}
module.exports = {
createProject,
loadProject,
saveProject,
importFiles,
removeFile,
setProjectIcon,
getSrcDir,
getDistDir,
getConfigPath,
getProjectDir
}