Skip to content

Commit a3a25a6

Browse files
gnoviawanclaude
andauthored
fix: resolve CommonJS import error causing startup crash in v0.1.5 (#11)
* fix: resolve CommonJS import error causing startup crash in v0.1.5 - Changed autoUpdater import to lazy-load with error handling - Added getAutoUpdater() function that loads electron-updater on-demand - Wrapped require in try-catch to prevent app crash on load failure - Added esModuleInterop to tsconfig.node.json for proper ESM/CJS interop - Aliased UpdateInfo type as ElectronUpdateInfo to avoid naming conflicts - Updated version to 0.1.6 - Added eslint-disable for necessary any type This fixes the critical TypeError/SyntaxError that prevented the application from starting in production builds. The electron-updater package uses CommonJS exports which don't work with ES6 named imports when using externalizeDepsPlugin. The lazy loading approach ensures the app starts even if electron-updater fails to load. Co-Authored-By: Claude <noreply@anthropic.com> * chore: ignore tmpclaude files in gitignore --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent d586acf commit a3a25a6

File tree

4 files changed

+63
-19
lines changed

4 files changed

+63
-19
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ nul
4242

4343
# Claude Code temp directories
4444
tmpclaude-*/
45+
tmpclaude-*
4546

4647
# ADR documentation
4748
docs/adr/

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "termul-manager",
3-
"version": "0.1.0",
3+
"version": "0.1.6",
44
"description": "Project-aware terminal that treats workspaces as first-class citizens",
55
"main": "./out/main/index.js",
66
"author": {

src/main/services/updater-service.ts

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
11
import { BrowserWindow, app } from 'electron'
2-
import { autoUpdater, UpdateInfo } from 'electron-updater'
3-
import type { ProgressInfo } from 'electron-updater'
2+
import { createRequire } from 'node:module'
3+
import type { ProgressInfo, UpdateInfo as ElectronUpdateInfo } from 'electron-updater'
44
import type { IpcResult } from '../../shared/types/ipc.types'
55
import { read, write } from './persistence-service'
66

7+
// Lazy load electron-updater with error handling
8+
// This prevents app crash if electron-updater fails to load
9+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
10+
let autoUpdater: any = null
11+
let electronUpdaterLoaded = false
12+
13+
function getAutoUpdater() {
14+
if (!electronUpdaterLoaded) {
15+
try {
16+
const require = createRequire(import.meta.url)
17+
const electronUpdater = require('electron-updater')
18+
autoUpdater = electronUpdater.autoUpdater
19+
electronUpdaterLoaded = true
20+
console.log('electron-updater loaded successfully')
21+
} catch (error) {
22+
console.error('Failed to load electron-updater:', error)
23+
autoUpdater = null
24+
electronUpdaterLoaded = true
25+
}
26+
}
27+
return autoUpdater
28+
}
29+
730
// Updater error codes
831
export const UpdaterErrorCodes = {
932
NOT_INITIALIZED: 'NOT_INITIALIZED',
@@ -42,7 +65,7 @@ export interface DownloadProgress {
4265
// Full updater state
4366
export interface UpdaterState {
4467
state: UpdateState
45-
updateInfo: UpdateInfo | null
68+
updateInfo: ElectronUpdateInfo | null
4669
downloadProgress: DownloadProgress | null
4770
error: string | null
4871
skippedVersion: string | null
@@ -76,7 +99,7 @@ let updaterServiceInstance: UpdaterService | null = null
7699
export class UpdaterService {
77100
private mainWindow: BrowserWindow | null = null
78101
private currentState: UpdateState = 'idle'
79-
private currentUpdateInfo: UpdateInfo | null = null
102+
private currentUpdateInfo: ElectronUpdateInfo | null = null
80103
private currentDownloadProgress: DownloadProgress | null = null
81104
private currentError: string | null = null
82105
private skippedVersion: string | null = null
@@ -128,7 +151,7 @@ export class UpdaterService {
128151
/**
129152
* Check for updates manually
130153
*/
131-
async checkForUpdates(): Promise<IpcResult<UpdateInfo>> {
154+
async checkForUpdates(): Promise<IpcResult<ElectronUpdateInfo>> {
132155
if (!this.isInitialized) {
133156
return {
134157
success: false,
@@ -195,7 +218,11 @@ export class UpdaterService {
195218

196219
try {
197220
// Actually trigger the download with electron-updater
198-
await autoUpdater.downloadUpdate()
221+
const updater = getAutoUpdater()
222+
if (!updater) {
223+
throw new Error('electron-updater not available')
224+
}
225+
await updater.downloadUpdate()
199226
return { success: true, data: undefined }
200227
} catch (error) {
201228
this.isDownloading = false
@@ -236,7 +263,11 @@ export class UpdaterService {
236263
await this.performBackup()
237264

238265
// Set autoInstallOnAppQuit to trigger install on restart
239-
autoUpdater.autoInstallOnAppQuit = true
266+
const updater = getAutoUpdater()
267+
if (!updater) {
268+
throw new Error('electron-updater not available')
269+
}
270+
updater.autoInstallOnAppQuit = true
240271

241272
// Restart the app to apply update
242273
app.relaunch()
@@ -300,21 +331,27 @@ export class UpdaterService {
300331
* Setup electron-updater configuration and event handlers
301332
*/
302333
private setupAutoUpdater(): void {
334+
const updater = getAutoUpdater()
335+
if (!updater) {
336+
console.warn('electron-updater not available, auto-update will not work')
337+
return
338+
}
339+
303340
// Configure for GitHub Releases
304-
autoUpdater.setFeedURL({
341+
updater.setFeedURL({
305342
provider: 'github',
306343
owner: 'PecutAPP',
307344
repo: 'termul'
308345
})
309346

310347
// Disable auto-download (we'll handle it manually)
311-
autoUpdater.autoDownload = false
348+
updater.autoDownload = false
312349

313350
// Disable auto-install on quit (we'll control when to install)
314-
autoUpdater.autoInstallOnAppQuit = false
351+
updater.autoInstallOnAppQuit = false
315352

316353
// Event handlers
317-
autoUpdater.on('update-available', (info: UpdateInfo) => {
354+
updater.on('update-available', (info: ElectronUpdateInfo) => {
318355
console.log('Update available:', info.version)
319356
this.currentUpdateInfo = info
320357

@@ -336,12 +373,12 @@ export class UpdaterService {
336373
this.sendEvent('update-available', info)
337374
})
338375

339-
autoUpdater.on('update-not-available', (info: UpdateInfo) => {
376+
updater.on('update-not-available', (info: ElectronUpdateInfo) => {
340377
console.log('Update not available, current version:', info.version)
341378
this.setState('idle')
342379
})
343380

344-
autoUpdater.on('download-progress', (progress: ProgressInfo) => {
381+
updater.on('download-progress', (progress: ProgressInfo) => {
345382
this.currentDownloadProgress = {
346383
bytesPerSecond: progress.bytesPerSecond,
347384
percent: progress.percent,
@@ -351,15 +388,15 @@ export class UpdaterService {
351388
this.sendEvent('download-progress', this.currentDownloadProgress)
352389
})
353390

354-
autoUpdater.on('update-downloaded', (info: UpdateInfo) => {
391+
updater.on('update-downloaded', (info: ElectronUpdateInfo) => {
355392
console.log('Update downloaded:', info.version)
356393
this.isDownloading = false
357394
this.currentUpdateInfo = info
358395
this.setState('downloaded')
359396
this.sendEvent('update-downloaded', info)
360397
})
361398

362-
autoUpdater.on('error', (error: Error) => {
399+
updater.on('error', (error: Error) => {
363400
console.error('Updater error:', error)
364401
this.isDownloading = false
365402

@@ -380,11 +417,16 @@ export class UpdaterService {
380417
/**
381418
* Check for updates with retry logic
382419
*/
383-
private async checkWithRetry(): Promise<UpdateInfo> {
420+
private async checkWithRetry(): Promise<ElectronUpdateInfo> {
421+
const updater = getAutoUpdater()
422+
if (!updater) {
423+
throw new Error('electron-updater not available')
424+
}
425+
384426
for (let attempt = 0; attempt < MAX_RETRY_ATTEMPTS; attempt++) {
385427
try {
386428
this.retryCount = attempt
387-
const result = await autoUpdater.checkForUpdates()
429+
const result = await updater.checkForUpdates()
388430

389431
if (!result) {
390432
throw new Error('No update information available')
@@ -459,7 +501,7 @@ export class UpdaterService {
459501
/**
460502
* Check if version is compatible with current version
461503
*/
462-
private isVersionCompatible(updateInfo: UpdateInfo): boolean {
504+
private isVersionCompatible(updateInfo: ElectronUpdateInfo): boolean {
463505
// Basic compatibility check - can be enhanced
464506
// For now, just check if version is present
465507
return Boolean(updateInfo.version)

tsconfig.node.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"module": "ESNext",
66
"moduleResolution": "node",
77
"allowSyntheticDefaultImports": true,
8+
"esModuleInterop": true,
89
"resolveJsonModule": true,
910
"strict": true,
1011
"noImplicitAny": true,

0 commit comments

Comments
 (0)