forked from trent_larson/crowd-funder-for-time-pwa
Add single-instance enforcement to Electron app
- Implement app.requestSingleInstanceLock() to prevent multiple instances - Add user-friendly dialog when second instance is attempted - Focus and restore existing window instead of creating new instance - Prevent database corruption and resource conflicts - Update documentation with single-instance behavior details
This commit is contained in:
18
BUILDING.md
18
BUILDING.md
@@ -246,6 +246,24 @@ npm run build:electron:deb:prod
|
||||
npm run build:electron:dmg:prod
|
||||
```
|
||||
|
||||
### Single Instance Enforcement
|
||||
|
||||
The Electron app enforces single-instance operation to prevent:
|
||||
- Database corruption from multiple instances
|
||||
- Resource conflicts and performance issues
|
||||
- User confusion from multiple windows
|
||||
|
||||
**Behavior:**
|
||||
- Only one instance can run at a time
|
||||
- Attempting to launch a second instance shows a user-friendly dialog
|
||||
- The existing window is focused and restored if minimized
|
||||
- Second instance exits gracefully
|
||||
|
||||
**Implementation:**
|
||||
- Uses Electron's `requestSingleInstanceLock()` API
|
||||
- Handles `second-instance` events to focus existing window
|
||||
- Shows informative dialog explaining why only one instance is allowed
|
||||
|
||||
#### Direct Script Usage
|
||||
|
||||
```bash
|
||||
|
||||
@@ -117,6 +117,25 @@ dist/
|
||||
└── linux-unpacked/ # Unpacked directory
|
||||
```
|
||||
|
||||
## Features
|
||||
|
||||
### Single Instance Enforcement
|
||||
TimeSafari Electron enforces single-instance operation to prevent:
|
||||
- Database corruption from multiple instances
|
||||
- Resource conflicts and performance issues
|
||||
- User confusion from multiple windows
|
||||
|
||||
**Behavior:**
|
||||
- Only one instance can run at a time
|
||||
- Attempting to launch a second instance shows a user-friendly dialog
|
||||
- The existing window is focused and restored if minimized
|
||||
- Second instance exits gracefully
|
||||
|
||||
**Implementation:**
|
||||
- Uses Electron's `requestSingleInstanceLock()` API
|
||||
- Handles `second-instance` events to focus existing window
|
||||
- Shows informative dialog explaining why only one instance is allowed
|
||||
|
||||
## Configuration
|
||||
|
||||
### App Metadata
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CapacitorElectronConfig } from '@capacitor-community/electron';
|
||||
import { getCapacitorElectronConfig, setupElectronDeepLinking } from '@capacitor-community/electron';
|
||||
import type { MenuItemConstructorOptions } from 'electron';
|
||||
import { app, MenuItem, ipcMain } from 'electron';
|
||||
import { app, MenuItem, ipcMain, dialog } from 'electron';
|
||||
import electronIsDev from 'electron-is-dev';
|
||||
import unhandled from 'electron-unhandled';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
@@ -10,6 +10,27 @@ import { join } from 'path';
|
||||
|
||||
import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup';
|
||||
|
||||
// Single instance enforcement
|
||||
const gotTheLock = app.requestSingleInstanceLock();
|
||||
|
||||
if (!gotTheLock) {
|
||||
console.log('[Electron] Another instance is already running. Exiting...');
|
||||
|
||||
// Show user-friendly dialog before quitting
|
||||
dialog.showMessageBox({
|
||||
type: 'info',
|
||||
title: 'TimeSafari Already Running',
|
||||
message: 'TimeSafari is already running in another window.',
|
||||
detail: 'Please use the existing TimeSafari window instead of opening a new one.',
|
||||
buttons: ['OK']
|
||||
}).then(() => {
|
||||
app.quit();
|
||||
});
|
||||
|
||||
// Exit immediately
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Graceful handling of unhandled errors.
|
||||
unhandled({
|
||||
logger: (error) => {
|
||||
@@ -79,6 +100,20 @@ autoUpdater.on('error', (error) => {
|
||||
// Initialize our app, build windows, and load content.
|
||||
await myCapacitorApp.init();
|
||||
|
||||
// Handle second instance launch (focus existing window)
|
||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||
console.log('[Electron] Second instance attempted to launch');
|
||||
|
||||
// Someone tried to run a second instance, we should focus our window instead
|
||||
const mainWindow = myCapacitorApp.getMainWindow();
|
||||
if (mainWindow) {
|
||||
if (mainWindow.isMinimized()) {
|
||||
mainWindow.restore();
|
||||
}
|
||||
mainWindow.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Only check for updates in production builds, not in development or AppImage
|
||||
if (!electronIsDev && !process.env.APPIMAGE) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user