Skip to content

v13.0.0

Latest

Choose a tag to compare

@guasam guasam released this 02 Sep 20:06

v13.0.0 - Electron React App

A major release. The IPC layer is rebuilt on electron-conveyor, and main is now a minimal starting shell with the interactive playground moved to the demo branch.

Type-safe IPC - Electron Conveyor

  • Define once, typed everywhere. Write a feature in the main process and the renderer gets a fully typed client for free. No channel strings, no client to write, no types to keep in sync.
  • Five primitives. query for reads, command for actions, stream for live output, event for main-to-renderer pushes, defineStore for shared state.
  • React hooks built in. conveyor.window.init.useQuery(), conveyor.web.openUrl.useMutation(), conveyor.window.onFocusChange.useEvent(cb), all powered by TanStack Query, with query keys derived from the call path instead of written by hand.
  • State shared across windows. Main owns the state, every window stays in sync, and persistence to disk is opt-in.
  • Handlers know their window. Each call carries the calling window as context, so titlebar and menu commands act on the right window without passing IDs around.
  • Multi-window ready. A built-in window manager tracks open windows and lets any handler open a new one.
  • Validated at the boundary. Zod schemas check every payload crossing the bridge, so bad input fails in main rather than deeper in your code.
  • Middleware. Attach it to reusable bases and narrow the context for everything below it.
  • Errors with codes. Failures cross the bridge with a stable code, so the renderer branches on err.code instead of parsing messages.
  • Per-call timings in dev. devLogger logs every IPC call while developing and is a no-op in packaged builds.
  • A preload that never changes. Two lines to expose the bridge, and it stays that way as your API grows.

App shell and UI

  • Minimal by default. A window, titlebar, menu, theming, and the IPC bridge. Nothing to delete before you start.
  • Playground on the demo branch. Every primitive shown live, built on main so it stays current.
  • Welcome screen you can remove. One folder (app/components/welcome), nothing else imports it, and it registers no IPC of its own.
  • Custom window frame and titlebar. App icon, window controls, and a menu system with keyboard shortcuts on Windows, macOS, and Linux.
  • Full titlebar menu, wired up. Undo, redo, cut, copy, paste, select all, zoom, fullscreen, reload, and devtools, all through typed commands.
  • Smooth theme switching. The window cross-fades between light and dark instead of snapping colour by colour.
  • A real error screen. The message first, React's component stack next to the error stack, dependency frames dimmed, and copy, retry, and reload buttons.
  • Fonts and components refreshed. Geist and JetBrains Mono bundled, shadcn components updated onto the single radix-ui package, framer-motion dropped.

Platform and security

  • Sandboxed renderer. sandbox: true out of the box, with the conveyor bundled into the preload so it works in a sandbox.
  • Working safeStorage on Linux. The keychain backend is named explicitly, so secrets are encrypted on desktops Chromium does not recognise instead of silently falling back to plain text.
  • Hardened external links. openExternal accepts http(s) URLs only.

Tooling

  • Checks. npm run typecheck, npm run lint:check, and npm run format:check.
  • CI on every push. Verified on main, then built and packaged on Linux, macOS, and Windows.
  • ESLint config in TypeScript. eslint.config.ts, with the flat config format.
  • Consistent filenames. Every component file is kebab-case.

Also included

  • res:// protocol for loading local resources.
  • Import path aliases: @/app/, @/lib/, @/conveyor/, @/resources/.
  • Vite HMR for near-instant reloads in development.
  • VS Code debugging preconfigured for both the main and renderer processes.
  • electron-builder set up for Windows, macOS, and Linux packaging.

Breaking changes

  • useConveyor() is gone. Calls go through the typed client instead: conveyor.window.minimize(), conveyor.window.init.useQuery().
  • The IPC surface moved to conveyor/: init.ts, modules/, router.ts, client.ts. Feature modules are main-process only, and the renderer imports just type AppRouter.