refactor: 迁移至 electron-vite 官方推荐目录结构

- electron/* -> src/main/* (主进程)
- electron/preload.ts -> src/preload/index.ts (预加载)
- src/electron-api.d.ts -> src/preload/index.d.ts (类型声明)
- src/* -> src/renderer/src/* (渲染进程)
- src/index.html -> src/renderer/index.html
- electron.vite.config.ts 简化为自动入口检测 (零配置)
- tsconfig.app.json -> tsconfig.web.json, 更新 includes/paths
- 构建产物 dist-electron/ -> out/ (修复 main/preload 输出覆盖 bug)
- 更新 package.json main 字段 + electron-builder files
- 更新 .gitignore + eslint ignores
- 更新 AGENTS.md 架构文档
This commit is contained in:
2026-07-10 23:46:34 +08:00
parent 157af4399f
commit eda30250c6
71 changed files with 112 additions and 127 deletions
+2 -2
View File
@@ -1,5 +1,5 @@
node_modules/ node_modules/
dist-electron/ out/
release/ release/
dist/ dist/
*.log *.log
@@ -15,7 +15,7 @@ yarn-error.log*
*.njsproj *.njsproj
*.sln *.sln
# Legacy codebase archived Vue 2 version, not part of v2 build # Legacy codebase - archived Vue 2 version, not part of v2 build
legacy/ legacy/
# Brainstorming artifacts # Brainstorming artifacts
+88 -83
View File
@@ -6,10 +6,10 @@ Fork of [AnotherRedisDesktopManager](https://github.com/qishibo/AnotherRedisDesk
## Stack ## Stack
- **Shell:** Electron 43 (`electron/main.ts`) - **Shell:** Electron 43 (`src/main/index.ts`)
- **Preload:** `electron/preload.ts` (contextBridge, typed API) - **Preload:** `src/preload/index.ts` (contextBridge, typed API)
- **Renderer:** Vue 3 + Pinia + Element Plus + Vue Router (`src/`) - **Renderer:** Vue 3 + Pinia + Element Plus + Vue Router (`src/renderer/src/`)
- **IPC types:** `src/electron-api.d.ts` (ElectronAPI interface, global Window augmentation) - **IPC types:** `src/preload/index.d.ts` (ElectronAPI interface, global Window augmentation)
- **Build:** electron-vite + Vite 6 + TypeScript 5 - **Build:** electron-vite + Vite 6 + TypeScript 5
- **Redis client:** ioredis 5 (main process only) - **Redis client:** ioredis 5 (main process only)
- **Persistence:** electron-store + safeStorage (credentials) - **Persistence:** electron-store + safeStorage (credentials)
@@ -18,7 +18,7 @@ Fork of [AnotherRedisDesktopManager](https://github.com/qishibo/AnotherRedisDesk
```bash ```bash
npm run dev # electron-vite dev (HMR, renderer on :5173) npm run dev # electron-vite dev (HMR, renderer on :5173)
npm run build # production build -> dist-electron/ npm run build # production build -> out/
npm start # preview built app npm start # preview built app
npm run build:unpack # build + electron-builder --dir npm run build:unpack # build + electron-builder --dir
npm run build:win # build + electron-builder --win npm run build:win # build + electron-builder --win
@@ -30,80 +30,84 @@ npm run lint # eslint --fix
## Architecture ## Architecture
``` ```
Electron main (electron/) Electron main (src/main/)
├── main.ts # Window creation, app lifecycle ├── index.ts # Window creation, app lifecycle
├── preload.ts # contextBridge.exposeInMainWorld ├── ipc-handlers.ts # all IPC channel handlers
├── ipc-handlers.ts # all IPC channel handlers ├── store.ts # electron-store (connections, settings)
├── store.ts # electron-store (connections, settings) ├── credential.ts # safeStorage encrypt/decrypt
├── credential.ts # safeStorage encrypt/decrypt ├── win-state.ts # window position persistence
├── win-state.ts # window position persistence ├── updater.ts # electron-updater (check/download/install)
── updater.ts # electron-updater (check/download/install) ── redis/ # Redis service modules
└── redis/ # Redis service modules ├── index.ts # Unified export
├── index.ts # Unified export ├── connection.ts # connect, disconnect, isClientConnected
├── connection.ts # connect, disconnect, isClientConnected ├── keys.ts # scan, delete, rename, ttl, batchDelete
├── keys.ts # scan, delete, rename, ttl, batchDelete ├── string.ts # get, set
├── string.ts # get, set ├── hash.ts # hscan, hset, hdel
├── hash.ts # hscan, hset, hdel ├── list.ts # range, push, set, remove
├── list.ts # range, push, set, remove ├── set.ts # members, add, remove
├── set.ts # members, add, remove ├── zset.ts # range, add, remove
├── zset.ts # range, add, remove ├── stream.ts # info, range, add, trim
├── stream.ts # info, range, add, trim ├── server.ts # info, select, ping, slowlog
├── server.ts # info, select, ping, slowlog ├── pubsub.ts # SUBSCRIBE/UNSUBSCRIBE
├── pubsub.ts # SUBSCRIBE/UNSUBSCRIBE
├── commandLogger.ts # command execution log ├── commandLogger.ts # command execution log
└── format.ts # value decode/format detection └── format.ts # value decode/format detection
Renderer (src/) Preload (src/preload/)
├── main.ts # Vue 3 bootstrap (Pinia, Element Plus) ├── index.ts # contextBridge.exposeInMainWorld
── App.vue # Shell layout (TitleBar + Sidebar + MainArea + StatusBar) ── index.d.ts # ElectronAPI type declarations
├── env.d.ts # Vite client + *.vue / *.css module declarations
├── electron-api.d.ts # ElectronAPI interface + global Window augmentation Renderer (src/renderer/)
├── stores/ ├── index.html # Vite entry HTML
│ ├── app.ts # theme, fontSize, scanCount └── src/
├── connection.ts # connections CRUD, connect/disconnect, health check ├── main.ts # Vue 3 bootstrap (Pinia, Element Plus)
── key.ts # key list, scan, tree view, selected key data ── App.vue # Shell layout (TitleBar + Sidebar + MainArea + StatusBar)
├── components/ ├── env.d.ts # Vite client + *.vue / *.css module declarations
├── TitleBar.vue # window controls ├── stores/
│ ├── StatusBar.vue # connection status, DB selector │ ├── app.ts # theme, fontSize, scanCount
│ ├── Sidebar.vue # keyboard shortcuts, dialog host │ ├── connection.ts # connections CRUD, connect/disconnect, health check
── ConnectionList.vue # search, import/export, new button ── key.ts # key list, scan, tree view, selected key data
├── ConnectionCard.vue # single connection card ├── components/
│ ├── NewConnectionDialog.vue # create/edit/test connection │ ├── TitleBar.vue # window controls
│ ├── DbSelector.vue # database 0-15 dropdown │ ├── StatusBar.vue # connection status, DB selector
│ ├── MainArea.vue # tab host (Status/Keys/CLI/SlowLog/Settings) │ ├── Sidebar.vue # keyboard shortcuts, dialog host
│ ├── StatusView.vue # INFO dashboard with stat cards │ ├── ConnectionList.vue # search, import/export, new button
│ ├── KeyBrowser.vue # split pane (KeyList + KeyDetail) │ ├── ConnectionCard.vue # single connection card
│ ├── KeyList.vue # pattern search, filter, SCAN, multi-select │ ├── NewConnectionDialog.vue # create/edit/test connection
│ ├── KeyDetail.vue # type dispatch, TTL, rename, copy │ ├── DbSelector.vue # database 0-15 dropdown
│ ├── StringEditor.vue # view/edit with JSON format │ ├── MainArea.vue # tab host (Status/Keys/CLI/SlowLog/Settings)
│ ├── HashEditor.vue # field table CRUD │ ├── StatusView.vue # INFO dashboard with stat cards
│ ├── ListEditor.vue # paginated elements │ ├── KeyBrowser.vue # split pane (KeyList + KeyDetail)
│ ├── SetEditor.vue # member list │ ├── KeyList.vue # pattern search, filter, SCAN, multi-select
│ ├── ZsetEditor.vue # sorted set with scores │ ├── KeyDetail.vue # type dispatch, TTL, rename, copy
│ ├── StreamEditor.vue # stream entries │ ├── StringEditor.vue # view/edit with JSON format
│ ├── CliView.vue # interactive terminal │ ├── HashEditor.vue # field table CRUD
│ ├── SlowLogView.vue # slow log table │ ├── ListEditor.vue # paginated elements
│ ├── SettingsView.vue # theme, language, scan count │ ├── SetEditor.vue # member list
│ ├── MemoryAnalysis.vue # MEMORY USAGE scan & sort │ ├── ZsetEditor.vue # sorted set with scores
│ ├── CommandLog.vue # command execution history │ ├── StreamEditor.vue # stream entries
── ReJsonEditor.vue # JSON.GET / JSON.SET editing ── CliView.vue # interactive terminal
├── i18n/ │ ├── SlowLogView.vue # slow log table
│ ├── index.ts # useI18n composable │ ├── SettingsView.vue # theme, language, scan count
── locales/ ── MemoryAnalysis.vue # MEMORY USAGE scan & sort
├── en.ts # English ├── CommandLog.vue # command execution history
── zh-CN.ts # 中文 ── ReJsonEditor.vue # JSON.GET / JSON.SET editing
├── ja.ts # 日本語 ├── i18n/
├── ko.ts # 한국어 ├── index.ts # useI18n composable
└── de.ts # Deutsch └── locales/
├── composables/ │ ├── en.ts # English
└── useKeyboard.ts # keyboard shortcut handler ├── zh-CN.ts # 中文
├── styles/ │ ├── ja.ts # 日本語
│ ├── variables.css # CSS custom properties ├── ko.ts # 한국어
│ └── global.css # global overrides │ └── de.ts # Deutsch
├── data/ ├── composables/
│ └── commands.ts # Redis command definitions │ └── useKeyboard.ts # keyboard shortcut handler
└── utils/ ├── styles/
└── binary.ts # hex ↔ buffer conversion │ ├── variables.css # CSS custom properties
│ └── global.css # global overrides
├── data/
│ └── commands.ts # Redis command definitions
└── utils/
└── binary.ts # hex ↔ buffer conversion
``` ```
## IPC Channels ## IPC Channels
@@ -203,19 +207,20 @@ Renderer (src/)
## Build config ## Build config
- `electron.vite.config.ts` defines three build targets: main, preload, renderer - `electron.vite.config.ts` defines three build targets: main, preload, renderer
- Main + preload output to `dist-electron/`; renderer to `dist-electron/renderer/` - Entry points auto-detected: `src/main/index.ts`, `src/preload/index.ts`, `src/renderer/index.html`
- Build output: `out/main/`, `out/preload/`, `out/renderer/`
- electron-builder packages into `release/` - electron-builder packages into `release/`
- Renderer dev server runs on port 5173 - Renderer dev server runs on port 5173
- Main/preload use `externalizeDepsPlugin()` to keep node_modules external - Main/preload use `externalizeDepsPlugin()` to keep node_modules external
- `@renderer` alias resolves to `src` - `@renderer` alias resolves to `src/renderer/src`
## TypeScript ## TypeScript
- Root `tsconfig.json` references `tsconfig.node.json` (main + preload) and `tsconfig.app.json` (renderer) - Root `tsconfig.json` references `tsconfig.node.json` (main + preload) and `tsconfig.web.json` (renderer)
- Node target (`tsconfig.node.json`) includes `electron/**/*` + `electron.vite.config.ts` - Node target (`tsconfig.node.json`) includes `src/main/**/*`, `src/preload/**/*.ts`, `electron.vite.config.ts`
- App target (`tsconfig.app.json`) includes `src/**/*` - Web target (`tsconfig.web.json`) includes `src/renderer/src/**/*`, `src/preload/**/*.d.ts`
- Both use `verbatimModuleSyntax` (type-only imports required) and `moduleResolution: "bundler"` - Both use `verbatimModuleSyntax` (type-only imports required) and `moduleResolution: "bundler"`
- `src/electron-api.d.ts` declares the `ElectronAPI` interface and augments global `Window` - `src/preload/index.d.ts` declares the `ElectronAPI` interface and augments global `Window`
## Security ## Security
+5 -30
View File
@@ -5,44 +5,19 @@ import { resolve } from 'path'
export default defineConfig({ export default defineConfig({
main: { main: {
plugins: [externalizeDepsPlugin()], plugins: [externalizeDepsPlugin()],
build: {
outDir: 'dist-electron',
rollupOptions: {
input: {
index: resolve(__dirname, 'electron/main.ts')
}
}
}
}, },
preload: { preload: {
plugins: [externalizeDepsPlugin()], plugins: [externalizeDepsPlugin()],
build: {
outDir: 'dist-electron',
rollupOptions: {
input: {
index: resolve(__dirname, 'electron/preload.ts')
}
}
}
}, },
renderer: { renderer: {
root: 'src',
build: {
outDir: resolve(__dirname, 'dist-electron/renderer'),
rollupOptions: {
input: {
index: resolve(__dirname, 'src/index.html')
}
}
},
resolve: { resolve: {
alias: { alias: {
'@renderer': resolve(__dirname, 'src') '@renderer': resolve(__dirname, 'src/renderer/src'),
} },
}, },
plugins: [vue()], plugins: [vue()],
server: { server: {
port: 5173 port: 5173,
} },
} },
}) })
+1 -1
View File
@@ -13,7 +13,7 @@ const commonLanguageOptions = {
} }
export default tseslint.config( export default tseslint.config(
{ ignores: ['dist', 'dist-electron', 'release', 'coverage', 'node_modules'] }, { ignores: ['dist', 'out', 'release', 'coverage', 'node_modules'] },
{ {
extends: [js.configs.recommended, ...tseslint.configs.recommended], extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.ts'], files: ['**/*.ts'],
+3 -4
View File
@@ -9,7 +9,7 @@
}, },
"homepage": "http://git.jokul.space/Jokul/JRedisDesktop", "homepage": "http://git.jokul.space/Jokul/JRedisDesktop",
"type": "module", "type": "module",
"main": "./dist-electron/main.js", "main": "./out/main/index.js",
"allowScripts": { "allowScripts": {
"electron": true, "electron": true,
"esbuild": true, "esbuild": true,
@@ -60,10 +60,9 @@
"output": "release" "output": "release"
}, },
"files": [ "files": [
"dist/**/*", "out/**/*",
"dist-electron/**/*",
"!**/*.map", "!**/*.map",
"!dist-electron/**/*.map", "!out/**/*.map",
"package.json" "package.json"
], ],
"publish": { "publish": {
+1 -1
View File
@@ -22,7 +22,7 @@ function createWindow(): void {
icon: nativeImage.createFromPath(iconPath), icon: nativeImage.createFromPath(iconPath),
backgroundColor: nativeTheme.shouldUseDarkColors ? '#0f0f1a' : '#f8fafc', backgroundColor: nativeTheme.shouldUseDarkColors ? '#0f0f1a' : '#f8fafc',
webPreferences: { webPreferences: {
preload: join(__dirname, '../preload.js'), preload: join(__dirname, '../preload/index.mjs'),
contextIsolation: true, contextIsolation: true,
nodeIntegration: false, nodeIntegration: false,
sandbox: false, sandbox: false,
View File
+1 -1
View File
@@ -7,6 +7,6 @@
</head> </head>
<body> <body>
<div id="app"></div> <div id="app"></div>
<script type="module" src="./main.ts"></script> <script type="module" src="./src/main.ts"></script>
</body> </body>
</html> </html>
View File
+2 -2
View File
@@ -1,7 +1,7 @@
{ {
"files": [], "files": [],
"references": [ "references": [
{ "path": "./tsconfig.app.json" }, { "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.node.json" } { "path": "./tsconfig.web.json" }
] ]
} }
+1 -1
View File
@@ -19,5 +19,5 @@
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true "noFallthroughCasesInSwitch": true
}, },
"include": ["electron.vite.config.ts", "electron"] "include": ["electron.vite.config.ts", "src/main/**/*", "src/preload/**/*.ts"]
} }
+8 -2
View File
@@ -1,6 +1,6 @@
{ {
"compilerOptions": { "compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.web.tsbuildinfo",
"target": "es2023", "target": "es2023",
"lib": ["ESNext", "DOM"], "lib": ["ESNext", "DOM"],
"module": "ESNext", "module": "ESNext",
@@ -14,10 +14,16 @@
"moduleDetection": "force", "moduleDetection": "force",
"noEmit": true, "noEmit": true,
/* Path alias */
"baseUrl": ".",
"paths": {
"@renderer/*": ["src/renderer/src/*"]
},
/* Linting */ /* Linting */
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"noFallthroughCasesInSwitch": true "noFallthroughCasesInSwitch": true
}, },
"include": ["src"] "include": ["src/renderer/src/**/*", "src/preload/**/*.d.ts"]
} }