17 changed files with 21929 additions and 80 deletions
After Width: | Height: | Size: 2.3 MiB |
@ -0,0 +1,12 @@
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html> |
||||
<html lang=""> |
||||
<head> |
||||
<meta charset="utf-8"> |
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0"> |
||||
<title>Vue App</title> |
||||
<script defer src="js/chunk-vendors.js"></script><script defer src="js/index.js"></script></head> |
||||
<body> |
||||
<div id="app"></div> |
||||
</body> |
||||
</html> |
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,11 +0,0 @@
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<title>GoFaster</title> |
||||
</head> |
||||
<body> |
||||
<div id="app"></div> |
||||
</body> |
||||
</html> |
@ -1,43 +1,66 @@
@@ -1,43 +1,66 @@
|
||||
const { app, BrowserWindow } = require('electron') |
||||
const { app, BrowserWindow, ipcMain } = require('electron') |
||||
const path = require('path') |
||||
|
||||
// 获取项目根目录绝对路径
|
||||
const appRoot = path.resolve(__dirname, '../..') |
||||
console.log('Application root:', appRoot) |
||||
|
||||
let mainWindow |
||||
|
||||
// 开发环境热重载
|
||||
if (process.env.NODE_ENV === 'development') { |
||||
require('electron-reload')(__dirname, { |
||||
electron: path.join(__dirname, 'node_modules', '.bin', 'electron'), |
||||
hardResetMethod: 'exit' |
||||
}); |
||||
} |
||||
|
||||
function createWindow() { |
||||
mainWindow = new BrowserWindow({ |
||||
width: 1200, |
||||
height: 800, |
||||
autoHideMenuBar: true,
|
||||
webPreferences: { |
||||
nodeIntegration: false, |
||||
contextIsolation: true, |
||||
enableRemoteModule: false, |
||||
preload: path.join(__dirname, '../preload.js') |
||||
preload: path.join(appRoot, 'src/preload.js') |
||||
} |
||||
}) |
||||
|
||||
// 开发模式下加载开发服务器
|
||||
// 开发环境下抑制安全警告
|
||||
if (process.env.NODE_ENV === 'development') { |
||||
mainWindow.loadURL('http://localhost:8080') |
||||
mainWindow.webContents.openDevTools() |
||||
} else { |
||||
mainWindow.loadFile(path.join(__dirname, '../public/index.html')) |
||||
mainWindow.webContents.on('did-frame-finish-load', () => { |
||||
mainWindow.webContents.executeJavaScript(` |
||||
console.warn = console.error = () => {}; |
||||
`).catch(err => console.error('抑制警告失败:', err));
|
||||
}); |
||||
} |
||||
|
||||
mainWindow.on('closed', () => { |
||||
mainWindow = null |
||||
const loadPath = path.join(appRoot, 'dist/renderer/index.html') |
||||
console.log('Loading:', loadPath) |
||||
|
||||
mainWindow.loadFile(loadPath).catch(err => { |
||||
console.error('加载失败:', err) |
||||
mainWindow.loadURL(`data:text/html,<h1>加载失败: ${err.toString()}</h1>`) |
||||
}) |
||||
|
||||
mainWindow.webContents.openDevTools() |
||||
} |
||||
|
||||
app.whenReady().then(createWindow) |
||||
app.whenReady().then(() => { |
||||
createWindow() |
||||
|
||||
ipcMain.on('request-status', (event) => { |
||||
const statusData = { /* 你的数据 */ } |
||||
event.sender.send('status-update', statusData) |
||||
}) |
||||
}) |
||||
|
||||
app.on('window-all-closed', () => { |
||||
if (process.platform !== 'darwin') { |
||||
app.quit() |
||||
} |
||||
if (process.platform !== 'darwin') app.quit() |
||||
}) |
||||
|
||||
app.on('activate', () => { |
||||
if (mainWindow === null) { |
||||
createWindow() |
||||
} |
||||
}) |
||||
if (mainWindow === null) createWindow() |
||||
}) |
||||
|
@ -1,7 +1,7 @@
@@ -1,7 +1,7 @@
|
||||
const { contextBridge } = require('electron') |
||||
// preload.js
|
||||
const { contextBridge, ipcRenderer } = require('electron') |
||||
|
||||
// 安全地暴露API给渲染进程
|
||||
contextBridge.exposeInMainWorld('electron', { |
||||
platform: process.platform |
||||
// 可以添加更多安全的API
|
||||
contextBridge.exposeInMainWorld('electronAPI', { |
||||
sendStatusRequest: () => ipcRenderer.send('request-status'), |
||||
onStatusUpdate: (callback) => ipcRenderer.on('status-update', callback) |
||||
}) |
@ -0,0 +1,35 @@
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html> |
||||
<html lang="zh-CN"> |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0"> |
||||
<title><%= htmlWebpackPlugin.options.title %></title> |
||||
<base href="./"> |
||||
<!-- 强化 CSP 策略 --> |
||||
<meta http-equiv="Content-Security-Policy" content=" |
||||
default-src 'self'; |
||||
script-src 'self' 'unsafe-inline'; |
||||
style-src 'self' 'unsafe-inline'; |
||||
img-src 'self' data:; |
||||
font-src 'self'; |
||||
connect-src 'self' ws:; |
||||
object-src 'none'; |
||||
frame-src 'none'; |
||||
base-uri 'self'; |
||||
form-action 'none'; |
||||
"> |
||||
<!-- 全局 polyfill 解决方案 --> |
||||
<script> |
||||
(function() { |
||||
if (typeof global === 'undefined') { |
||||
if (typeof window !== 'undefined') window.global = window; |
||||
else if (typeof self !== 'undefined') self.global = self; |
||||
else if (typeof globalThis !== 'undefined') globalThis.global = globalThis; |
||||
} |
||||
})(); |
||||
</script> |
||||
</head> |
||||
<body> |
||||
<div id="app"></div> |
||||
</body> |
||||
</html> |
After Width: | Height: | Size: 2.3 MiB |
@ -0,0 +1,75 @@
@@ -0,0 +1,75 @@
|
||||
<!-- src/components/StatusBar.vue --> |
||||
<template> |
||||
<div class="status-bar"> |
||||
<div class="status-item">服务地址: {{ serverUrl }}</div> |
||||
<div class="status-item">用户: {{ userInfo }}</div> |
||||
<div class="status-item">最近错误: {{ errorCount }}</div> |
||||
<div class="status-item">版本: {{ appVersion }}</div> |
||||
<div class="status-item">内存: {{ memoryUsage }} MB</div> |
||||
</div> |
||||
</template> |
||||
|
||||
<script> |
||||
import { ref, onMounted, onUnmounted } from 'vue'; |
||||
|
||||
export default { |
||||
name: 'StatusBar', |
||||
setup() { |
||||
const serverUrl = ref(process.env.NODE_ENV === 'development' ? 'http://localhost:8080' : window.location.href); |
||||
const userInfo = ref('未登录'); |
||||
const errorCount = ref(0); |
||||
const appVersion = ref(process.env.VUE_APP_VERSION || '1.0.0'); |
||||
const memoryUsage = ref(0); |
||||
|
||||
// 更新内存使用情况 |
||||
let intervalId; |
||||
onMounted(() => { |
||||
intervalId = setInterval(() => { |
||||
if (window.performance && window.performance.memory) { |
||||
memoryUsage.value = (window.performance.memory.usedJSHeapSize / (1024 * 1024)).toFixed(2); |
||||
} |
||||
}, 2000); |
||||
}); |
||||
|
||||
onUnmounted(() => { |
||||
clearInterval(intervalId); |
||||
}); |
||||
|
||||
// 监听主进程消息 |
||||
window.electronAPI?.onStatusUpdate((event, data) => { |
||||
if (data.userInfo) userInfo.value = data.userInfo; |
||||
if (data.errorCount !== undefined) errorCount.value = data.errorCount; |
||||
}); |
||||
|
||||
return { |
||||
serverUrl, |
||||
userInfo, |
||||
errorCount, |
||||
appVersion, |
||||
memoryUsage |
||||
}; |
||||
} |
||||
}; |
||||
</script> |
||||
|
||||
<style scoped> |
||||
.status-bar { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
height: 24px; |
||||
background-color: #333; |
||||
color: #fff; |
||||
display: flex; |
||||
align-items: center; |
||||
padding: 0 10px; |
||||
font-size: 12px; |
||||
border-top: 1px solid #444; |
||||
z-index: 1000; |
||||
} |
||||
|
||||
.status-item { |
||||
margin-right: 20px; |
||||
} |
||||
</style> |
@ -1,55 +1,86 @@
@@ -1,55 +1,86 @@
|
||||
const path = require('path') |
||||
const { defineConfig } = require('@vue/cli-service') |
||||
|
||||
const appRoot = path.resolve(__dirname) |
||||
|
||||
module.exports = defineConfig({ |
||||
outputDir: path.resolve(__dirname, 'dist/renderer'), |
||||
outputDir: path.join(appRoot, 'dist/renderer'), |
||||
publicPath: './', |
||||
|
||||
// 关键修改:配置 Electron 构建目标和排除原生模块
|
||||
|
||||
configureWebpack: { |
||||
target: 'electron-renderer', // 指定为 Electron 渲染进程
|
||||
externals: { |
||||
electron: 'require("electron")', // 防止 Webpack 处理 electron 模块
|
||||
fs: 'require("fs")', // 排除 Node.js 原生模块
|
||||
path: 'require("path")', |
||||
target: 'electron-renderer', |
||||
node: { |
||||
global: false, // 禁用全局 polyfill
|
||||
__dirname: true |
||||
}, |
||||
resolve: { |
||||
alias: { |
||||
'@': path.resolve(__dirname, 'src/renderer'), |
||||
// 确保 Vue 单文件组件引用时自动补全扩展名
|
||||
'views': path.resolve(__dirname, 'src/renderer/views') |
||||
}, |
||||
// 添加扩展名自动解析
|
||||
extensions: ['.js', '.vue', '.json'] |
||||
fallback: { |
||||
global: false // 禁用 fallback
|
||||
}, |
||||
alias: { |
||||
'@': path.join(appRoot, 'src/renderer'), |
||||
'views': path.join(appRoot, 'src/renderer/views') |
||||
}, |
||||
extensions: ['.js', '.vue', '.json'] |
||||
}, |
||||
externals: { |
||||
electron: 'require("electron")', |
||||
fs: 'require("fs")', |
||||
path: 'require("path")' |
||||
} |
||||
}, |
||||
|
||||
// 保留原有页面配置
|
||||
pages: { |
||||
index: { |
||||
entry: 'src/renderer/main.js', |
||||
template: 'public/index.html', |
||||
entry: path.join(appRoot, 'src/renderer/main.js'), |
||||
template: path.join(appRoot, 'public/index.html'), |
||||
filename: 'index.html' |
||||
} |
||||
}, |
||||
|
||||
// 保留 Electron Builder 配置
|
||||
pluginOptions: { |
||||
electronBuilder: { |
||||
preload: 'src/preload.js', |
||||
nodeIntegration: false, |
||||
contextIsolation: true, |
||||
// 可选:明确指定主进程文件路径
|
||||
mainProcessFile: 'src/main/index.js' |
||||
preload: path.join(appRoot, 'src/preload.js'), |
||||
mainProcessFile: path.join(appRoot, 'src/main/index.js'), |
||||
builderOptions: { |
||||
extraResources: [{ |
||||
from: path.join(appRoot, 'dist/renderer'), |
||||
to: 'app', |
||||
filter: ["**/*"] |
||||
}] |
||||
} |
||||
} |
||||
}, |
||||
|
||||
// 开发服务器配置(与 Electron 主进程配合)
|
||||
devServer: { |
||||
port: 8080, // 确保与 wait-on 端口一致
|
||||
hot: true, |
||||
headers: { |
||||
'Access-Control-Allow-Origin': '*' |
||||
} |
||||
hot: false, |
||||
liveReload: false, |
||||
allowedHosts: "all", |
||||
static: { |
||||
directory: path.join(__dirname, 'dist/renderer'), |
||||
watch: false |
||||
}, |
||||
compress: false, |
||||
proxy: null |
||||
}, |
||||
|
||||
chainWebpack: config => { |
||||
// 开发环境 sourcemap
|
||||
config.devtool(process.env.NODE_ENV === 'development'
|
||||
? 'source-map'
|
||||
: false) |
||||
|
||||
// 静态资源处理
|
||||
config.module |
||||
.rule('images') |
||||
.set('generator', { |
||||
filename: 'img/[name].[hash:8][ext]' |
||||
}) |
||||
|
||||
// 全局变量定义
|
||||
config.plugin('define').tap(args => { |
||||
args[0]['global.GLOBAL'] = JSON.stringify(false) |
||||
return args |
||||
}) |
||||
} |
||||
}) |
Loading…
Reference in new issue