Skip to content

Bug: Tauri events never reach frontend — require() fails in ESM/Vite context, falls back to DOM listeners #462

@neteraf0

Description

@neteraf0

Summary

Claude runs perfectly (backend works), but the frontend never receives any Tauri events — resulting in infinite loading spinner, no response shown, cancel button broken (claudeSessionId stays null).

Root Cause

ClaudeCodeSession.tsx loads the Tauri event listener via require() inside a try/catch:

// src/components/ClaudeCodeSession.tsx
let tauriListen: any;
try {
  if (typeof window !== 'undefined' && window.__TAURI__) {
    tauriListen = require("@tauri-apps/api/event").listen; // ← BUG
  }
} catch (e) {
  console.log('[ClaudeCodeSession] Tauri APIs not available, using web mode');
}

const listen = tauriListen || domEventFallback;

Vite bundles as ESMrequire is not defined at runtime → ReferenceError is thrown → silently caught → tauriListen stays undefinedlisten = DOM event fallback.

The DOM fallback listens via window.addEventListener(eventName, ...) and expects window.dispatchEvent(new CustomEvent(...)). But the Rust backend emits events through Tauri's IPC bridge, not the DOM — so the frontend receives zero events.

Symptoms

  • Infinite loading animation after sending a message
  • No response rendered (though Claude responds correctly — verified via RUST_LOG=debug)
  • Cancel button does nothing (requires claudeSessionId which is set from the init event — never received)
  • Debug overlay shows: loading:true | sid:null | msgs:1 | listening:true

Affected

All macOS (and likely Linux) users building from source with Vite. The require() anti-pattern in ESM is the culprit.

Fix

Replace the require() pattern with a proper static ESM import:

- let tauriListen: any;
- try {
-   if (typeof window !== 'undefined' && window.__TAURI__) {
-     tauriListen = require("@tauri-apps/api/event").listen;
-   }
- } catch (e) {
-   console.log('[ClaudeCodeSession] Tauri APIs not available, using web mode');
- }
- 
- const listen = tauriListen || ((eventName, callback) => {
-   window.addEventListener(eventName, ...);
-   return Promise.resolve(...);
- });
+ import { listen } from "@tauri-apps/api/event";

One line. Fixes all event delivery.

Verification

After the fix, the debug overlay shows correct progression:

  • Before send: loading:false | sid:null | msgs:0 | listening:false
  • After response: loading:false | sid:d49637f9 | msgs:3 | listening:false

Claude responses render correctly and loading state clears.

Notes

The same require() pattern exists in useClaudeMessages.ts (for claude-stream events) — worth fixing there too for consistency, though that code path may not be active by default.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions