- Electron 版本 43 -> 33 - 补充 ESM 模块系统说明 (main .js / preload .mjs) - 补充构建产物文件名和 package.json main 字段 - 新增运行时 __dirname 路径表 (preload/renderer/icon) - 新增 Electron 二进制安装问题及修复方法
12 KiB
AGENTS.md - JRedisDesktop v2
Project identity
Fork of AnotherRedisDesktopManager. The legacy Vue 2 codebase lives in legacy/ and is gitignored. Work only in the root project.
Stack
- Shell: Electron 33 (
src/main/index.ts) - Preload:
src/preload/index.ts(contextBridge, typed API) - Renderer: Vue 3 + Pinia + Element Plus + Vue Router (
src/renderer/src/) - IPC types:
src/preload/index.d.ts(ElectronAPI interface, global Window augmentation) - Build: electron-vite + Vite 6 + TypeScript 5
- Module system:
"type": "module"(ESM) — main outputs.js, preload outputs.mjs - Redis client: ioredis 5 (main process only)
- Persistence: electron-store + safeStorage (credentials)
Commands
npm run dev # electron-vite dev (HMR, renderer on :5173)
npm run build # production build -> out/
npm start # preview built app
npm run build:unpack # build + electron-builder --dir
npm run build:win # build + electron-builder --win
npm run build:mac # build + electron-builder --mac
npm run build:linux # build + electron-builder --linux
npm run lint # eslint --fix
Architecture
Electron main (src/main/)
├── index.ts # Window creation, app lifecycle
├── ipc-handlers.ts # all IPC channel handlers
├── store.ts # electron-store (connections, settings)
├── credential.ts # safeStorage encrypt/decrypt
├── win-state.ts # window position persistence
├── updater.ts # electron-updater (check/download/install)
└── redis/ # Redis service modules
├── index.ts # Unified export
├── connection.ts # connect, disconnect, isClientConnected
├── keys.ts # scan, delete, rename, ttl, batchDelete
├── string.ts # get, set
├── hash.ts # hscan, hset, hdel
├── list.ts # range, push, set, remove
├── set.ts # members, add, remove
├── zset.ts # range, add, remove
├── stream.ts # info, range, add, trim
├── server.ts # info, select, ping, slowlog
├── pubsub.ts # SUBSCRIBE/UNSUBSCRIBE
├── commandLogger.ts # command execution log
└── format.ts # value decode/format detection
Preload (src/preload/)
├── index.ts # contextBridge.exposeInMainWorld
└── index.d.ts # ElectronAPI type declarations
Renderer (src/renderer/)
├── index.html # Vite entry HTML
└── src/
├── main.ts # Vue 3 bootstrap (Pinia, Element Plus)
├── App.vue # Shell layout (TitleBar + Sidebar + MainArea + StatusBar)
├── env.d.ts # Vite client + *.vue / *.css module declarations
├── stores/
│ ├── app.ts # theme, fontSize, scanCount
│ ├── connection.ts # connections CRUD, connect/disconnect, health check
│ └── key.ts # key list, scan, tree view, selected key data
├── components/
│ ├── TitleBar.vue # window controls
│ ├── StatusBar.vue # connection status, DB selector
│ ├── Sidebar.vue # keyboard shortcuts, dialog host
│ ├── ConnectionList.vue # search, import/export, new button
│ ├── ConnectionCard.vue # single connection card
│ ├── NewConnectionDialog.vue # create/edit/test connection
│ ├── DbSelector.vue # database 0-15 dropdown
│ ├── MainArea.vue # tab host (Status/Keys/CLI/SlowLog/Settings)
│ ├── StatusView.vue # INFO dashboard with stat cards
│ ├── KeyBrowser.vue # split pane (KeyList + KeyDetail)
│ ├── KeyList.vue # pattern search, filter, SCAN, multi-select
│ ├── KeyDetail.vue # type dispatch, TTL, rename, copy
│ ├── StringEditor.vue # view/edit with JSON format
│ ├── HashEditor.vue # field table CRUD
│ ├── ListEditor.vue # paginated elements
│ ├── SetEditor.vue # member list
│ ├── ZsetEditor.vue # sorted set with scores
│ ├── StreamEditor.vue # stream entries
│ ├── CliView.vue # interactive terminal
│ ├── SlowLogView.vue # slow log table
│ ├── SettingsView.vue # theme, language, scan count
│ ├── MemoryAnalysis.vue # MEMORY USAGE scan & sort
│ ├── CommandLog.vue # command execution history
│ └── ReJsonEditor.vue # JSON.GET / JSON.SET editing
├── i18n/
│ ├── index.ts # useI18n composable
│ └── locales/
│ ├── en.ts # English
│ ├── zh-CN.ts # 中文
│ ├── ja.ts # 日本語
│ ├── ko.ts # 한국어
│ └── de.ts # Deutsch
├── composables/
│ └── useKeyboard.ts # keyboard shortcut handler
├── styles/
│ ├── variables.css # CSS custom properties
│ └── global.css # global overrides
├── data/
│ └── commands.ts # Redis command definitions
└── utils/
└── binary.ts # hex ↔ buffer conversion
IPC Channels
| Channel | Type | Purpose |
|---|---|---|
redis:connect |
invoke | Create Redis connection |
redis:disconnect |
invoke | Close connection |
redis:execute |
invoke | Execute arbitrary command |
redis:getInfo |
invoke | INFO server info |
redis:ping |
invoke | Health check ping |
redis:isConnected |
invoke | Check connection status |
redis:scanKeys |
invoke | SCAN with pattern |
redis:getKeyType |
invoke | TYPE of a key |
redis:getKeyTTL |
invoke | TTL of a key |
redis:deleteKey |
invoke | DEL a single key |
redis:existsKey |
invoke | EXISTS check |
redis:getString |
invoke | GET string value |
redis:setString |
invoke | SET string value |
redis:hashScan |
invoke | HSCAN fields |
redis:hashSet |
invoke | HSET field |
redis:hashDel |
invoke | HDEL field |
redis:listRange |
invoke | LRANGE elements |
redis:listLength |
invoke | LLEN |
redis:listPush |
invoke | RPUSH elements |
redis:listSet |
invoke | LSET element |
redis:listRemove |
invoke | LREM elements |
redis:setMembers |
invoke | SMEMBERS |
redis:setSize |
invoke | SCARD |
redis:setAdd |
invoke | SADD members |
redis:setRemove |
invoke | SREM members |
redis:zsetRange |
invoke | ZRANGE with scores |
redis:zsetSize |
invoke | ZCARD |
redis:zsetAdd |
invoke | ZADD member |
redis:zsetRemove |
invoke | ZREM members |
redis:streamInfo |
invoke | XINFO STREAM |
redis:streamRange |
invoke | XRANGE entries |
redis:streamAdd |
invoke | XADD entry |
redis:streamTrim |
invoke | XTRIM |
redis:streamDel |
invoke | XDEL entries |
redis:streamGroups |
invoke | XINFO GROUPS |
redis:streamConsumers |
invoke | XINFO CONSUMERS |
redis:streamGroupCreate |
invoke | XGROUP CREATE |
redis:streamGroupDestroy |
invoke | XGROUP DESTROY |
redis:streamAck |
invoke | XACK messages |
redis:batchDelete |
invoke | Pipeline DEL multiple keys |
redis:renameKey |
invoke | RENAME key |
redis:setTTL |
invoke | EXPIRE/PERSIST |
redis:selectDb |
invoke | SELECT database |
redis:dbSize |
invoke | DBSIZE |
redis:slowLogGet |
invoke | SLOWLOG GET |
redis:slowLogLen |
invoke | SLOWLOG LEN |
redis:memoryUsage |
invoke | MEMORY USAGE |
redis:subscribe |
invoke | SUBSCRIBE to channels |
redis:unsubscribe |
invoke | UNSUBSCRIBE from channels |
redis:subscribeMessage |
send | Push subscribed message to renderer |
redis:monitor |
invoke | Start MONITOR stream |
redis:monitorStop |
invoke | Stop MONITOR stream |
redis:monitorMessage |
send | Push monitored command to renderer |
redis:getCommandLog |
invoke | Get command execution log |
redis:clearCommandLog |
invoke | Clear command log |
redis:decodeValue |
invoke | Decode value by format |
redis:detectFormat |
invoke | Auto-detect value format |
redis:customFormat |
invoke | Custom external formatter |
redis:rejsonGet |
invoke | JSON.GET value |
redis:rejsonSet |
invoke | JSON.SET value |
storage:getConnections |
invoke | Read connections |
storage:saveConnection |
invoke | Save connection |
storage:deleteConnection |
invoke | Delete connection |
storage:reorderConnections |
invoke | Reorder connections |
storage:getSettings |
invoke | Read settings |
storage:saveSettings |
invoke | Save settings |
credential:encrypt |
invoke | safeStorage encrypt |
credential:decrypt |
invoke | safeStorage decrypt |
dialog:openFile |
invoke | Open file picker |
theme:get |
invoke | Get OS dark mode |
theme:set |
send | Set theme source |
theme:os-updated |
send | Push OS theme change to renderer |
window:minimize |
send | Minimize window |
window:maximize |
send | Toggle maximize |
window:close |
send | Close window |
updater:check |
invoke | Check for updates |
updater:download |
invoke | Download update |
updater:install |
invoke | Quit and install update |
updater:status |
send | Push updater status to renderer |
Keyboard Shortcuts
| Shortcut | Action | Scope |
|---|---|---|
Ctrl+N |
New connection | Global |
Ctrl+R |
Refresh keys | Global |
F5 |
Refresh keys | Global |
Delete |
Delete selected key | Global |
Escape |
Deselect key | Global |
Build config
electron.vite.config.tsdefines three build targets: main, preload, renderer- Entry points auto-detected (zero-config):
src/main/index.ts,src/preload/index.ts,src/renderer/index.html - Build output:
out/main/index.js,out/preload/index.mjs,out/renderer/(index.html + assets/) package.json"main"points to./out/main/index.js- electron-builder packages into
release/ - Renderer dev server runs on port 5173
- Main/preload use
externalizeDepsPlugin()to keep node_modules external @rendereralias resolves tosrc/renderer/src
Runtime paths in main process
src/main/index.ts uses __dirname (resolved to out/main/ at runtime) to locate siblings:
| Target | Expression |
|---|---|
| Preload script | join(__dirname, '../preload/index.mjs') |
| Renderer HTML | join(__dirname, '../renderer/index.html') |
| App icon | join(__dirname, '../../build/icons/icon_256.png') |
If output directory or file extensions change, update these paths accordingly.
TypeScript
- Root
tsconfig.jsonreferencestsconfig.node.json(main + preload) andtsconfig.web.json(renderer) - Node target (
tsconfig.node.json) includessrc/main/**/*,src/preload/**/*.ts,electron.vite.config.ts - Web target (
tsconfig.web.json) includessrc/renderer/src/**/*,src/preload/**/*.d.ts - Both use
verbatimModuleSyntax(type-only imports required) andmoduleResolution: "bundler" src/preload/index.d.tsdeclares theElectronAPIinterface and augments globalWindow
Security
contextIsolation: true- renderer has zero Node.js accessnodeIntegration: false- no Node globals in renderersafeStorage- OS-level encryption for credentials- All Redis operations go through typed IPC to main process
Legacy
The legacy/ directory contains the old Vue 2 + Webpack 4 codebase. It is gitignored and not part of the v2 build. See legacy/AGENTS.md for its documentation.
Known issues
Electron binary not installed after npm install
The allowScripts field in package.json blocks electron's postinstall script (node install.js), so npm install only fetches the npm package without downloading the ~100 MB binary. npm run dev then fails with Error: Electron failed to install correctly or spawn ... ENOENT.
Fix: Run the install script manually after npm install:
node node_modules/electron/install.js
If the download is slow (GitHub releases), use a mirror:
ELECTRON_MIRROR="https://npmmirror.com/mirrors/electron/" node node_modules/electron/install.js
package.jsonreferencesscripts/fix-electron.sh(npm run fix:electron) but the script does not exist yet.