Skip to content

fix(desktop): npm run dev stuck on preload skeleton — protocol barrel pulls node:crypto into the renderer #4706

Description

@me2seeks

Summary

npm run dev launches, the Electron window appears, but the renderer stays on the index.html preload skeleton (.maka-preload) forever. No error reaches the terminal. Reproduced on Windows and Linux at current main (b39e8d3). Packaged builds are unaffected.

Root cause

The renderer startup graph pulls a Node-only module into the browser through the protocol barrel:

src/renderer/main.tsx → app.tsx → app-shell.tsx
  → use-app-shell-session-workspace.ts → session-workspace-actions.ts
    → import { MESSAGE_QUEUE_MAX_ENTRIES } from '@maka/runtime-host/protocol'
      → packages/runtime-host/src/protocol/index.ts: export * from './client-capability.js'
        → client-capability.ts: import { createHash } from 'node:crypto'

Vite dev does no tree-shaking, so export * eagerly loads client-capability.js in the browser. Vite externalizes node:crypto for browser compatibility, and the served module begins with a top-level destructure:

const createHash = __vite__cjsImport0_node_crypto["createHash"];

That getter throws at module evaluation, which kills the whole renderer import graph before React mounts. The window is still revealed by the 4s SHOW_FALLBACK_TIMEOUT_MS fallback in main-window.ts, so the failure presents as "window opens, skeleton forever, silence in the terminal" — renderer console errors never reach the terminal unless ELECTRON_ENABLE_LOGGING=1.

clientCapabilityEntityId is the only createHash consumer, and it is used exclusively by main-process code (runtime-host-boot.ts, runtime-host-native-capabilities.ts); the renderer never calls it.

Reproduction

npm run dev
# window opens, skeleton stays forever
# with ELECTRON_ENABLE_LOGGING=1 the terminal shows the node:crypto error

Confirmed via CDP attach (--remote-debugging-port): Runtime.exceptionThrown stack ends at packages/runtime-host/dist/protocol/client-capability.js triggered from __vite-browser-external:node:crypto.

Timeline

Together they break vite dev mode on every platform.

Why CI did not catch it

  • windows-baseline.yml's Electron smoke is continue-on-error: true and exercises the dist build (smoke:windows:dist); vite build tree-shakes the unused client-capability.js out, so only vite dev mode breaks.
  • check-renderer-architecture.mjs forbids Node builtins in renderer sources but only scans the renderer's own imports — it does not walk the transitive graph through workspace package barrels.

Proposed fix

Move clientCapabilityEntityId (and the node:crypto import) out of protocol/client-capability.ts into a Node-only module that the protocol barrel does not re-export, and point the two main-process call sites at it. The renderer keeps importing browser-safe values from the barrel.

Follow-up worth considering: extend check-renderer-architecture.mjs (or add a vite-level guard) to reject Node builtins anywhere in the renderer's transitive dependency graph, so the next barrel re-export cannot silently reintroduce this.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

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