npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

electron-deck

v1.0.0

Published

Host-shell framework for Electron: multi-window orchestration, native WebContentsViews that follow the DOM, overlays, popouts and cross-process IPC behind one `electronDeck(config)` entry — plus a browser-only dock layout engine.

Readme

Host-shell framework for Electron: multi-window orchestration, native WebContentsViews that follow the DOM, overlays, popouts and cross-process IPC behind one electronDeck(config) entry — plus a browser-only dock layout engine.

npm version npm downloads License Node

English · 简体中文

A framework for building a host shell on Electron out of a small set of orthogonal primitives: multi-window management, native WebContentsView stacking and geometry following, overlays and popouts, and cross-process IPC. Hosts write an injected RuntimeBackend; the framework owns Electron setup, transport wiring, and trust boundaries.

Features

  • One entry point — electronDeck(config) takes a RuntimeBackend and takes over app assembly: whenReady() gating, transport wiring, trust boundary.
  • DOM-following native views — WebContentsViews track DOM element geometry across the process boundary, built on top of view-anchor.
  • Dockable layouts — a pure-TypeScript layout-as-data engine (/layout) and its React renderer <DockView> (/dock-react), both usable in plain-browser projects.
  • Browser-pure subpaths — /layout and /dock-react (plus their transitive dependencies) never import electron or node; both boundaries are pinned by tests.
  • Subpath exports — dedicated entry points for main, preload, host, client, layout and dock-react.
  • Graduated APIs — a stable integration path via electronDeck(), plus an explicitly marked experimental declarative surface.

Performance

Every claim here has a command that reproduces it:

  • Native views track the DOM within about 1 ms — the placement publisher coalesces every set/remove of a render step into one IPC publish, scheduled as a post-render task instead of the next animation frame. DECK_DEMO_LAG=1 pnpm run examples:dockable drives a real pointer drag of a split handle and reports the lag of the native view behind its DOM slot (median 0.9 ms over 152 samples here, p95 2.2 ms; forcing the same drag back onto requestAnimationFrame moves the median to 16.9 ms — one full frame).
  • Tree-shaking is verified — pnpm run check:tree-shaking verifies that importing only createInitialState from electron-deck/layout shakes out its layout siblings, yielding a bundle of about 100 B gzip instead of the whole 5 KB entry; its root-entry case separately checks that dock-react stays outside the root dependency graph. This check runs in prepack.
  • Window cleanup is regression-tested — pnpm exec vitest run src/internal/deck-app.memory-regression.test.ts cycles windows and views in a fake Electron runtime, forces GC, and checks that the closed objects are collectible and heap growth stays below 1 MB. This tests DeckApp retention, not native Electron memory.
  • The main-process frame path is cheap — pnpm bench measures authorizeSnapshot → reconcile → applyReconciledPlacements per frame; expect a few microseconds per frame for a dozen views, and treat single runs as noisy.

Installation

pnpm add electron-deck
# or
npm install electron-deck

electron (>=30.5.1, the first line with WebContentsView; CI runs the e2e on both that floor and the version in devDependencies) is an optional peer dependency — browser-only consumers of /layout and /dock-react don't need it. React ≥ 18 is required for /dock-react.

Quick start

Take over app assembly

Implement a RuntimeBackend (build windows and wire your own IPC in assemble(runtime)) and hand it to electronDeck():

// main.ts
import { electronDeck } from 'electron-deck'
import { myBackend } from './my-backend.js'

electronDeck({ backend: myBackend }).catch((err) => {
	console.error(err)
	process.exit(1)
})

The framework waits for app.whenReady(), wires the transport, and enforces the trust boundary; you only assemble your domain (real context, main window content, views, IPC modules). Set ownsWindows: true when the backend owns the main window completely.

Don't await electronDeck() at the top level of your main module. Electron only fires whenReady after the main module finishes evaluating, so a top-level await deadlocks. Use .catch(...) instead. startElectronDeck() returns its handle synchronously, so the call itself never blocks module evaluation — but await handle.ready at the top level deadlocks identically to await electronDeck(); defer that await into an event handler or other post-ready code.

Window-internal docking only

electron-deck/layout is a pure-TypeScript layout-as-data engine; electron-deck/dock-react is its <DockView> React renderer. Both work in plain-browser web projects.

  • The layout is a serializable tree of SplitNode / TabGroupNode nodes. movePanel, splitPanel, closePanel, insertPanel, setActive, setSizes and setConstraint are its mutations; serializeLayout / parseLayout / collectTreeProblems handle persistence; createLayoutModel is the observable single-writer model.
  • Split children can carry a SizeConstraint: fixedPx pins a size, minPx sets a floor the user can still drag upward.
  • Panel descriptors can carry PanelCapabilities (draggable / acceptsDrops / dropPolicy / closable / hideTab) that constrain dragging and closing; computeReorderIndex is the accompanying pure geometry function.

Runnable examples live in examples/layout-demo and examples/dockable-demo.

Entry points

| What you need | Import from | | ----------------------------------------------------------- | ------------------------------------------------------ | | electronDeck entry, DeckConfig / RuntimeBackend types | electron-deck | | Main-process assembly utilities | electron-deck/main | | Host-side control-bus / capability / trust primitives | electron-deck/host | | Preload bridge exposeDeckBridge() | electron-deck/preload | | Renderer client createDeckClient<HS, EV>() | electron-deck/client (/client/browser is an alias) | | Layout-as-data engine + panel registry | electron-deck/layout | | <DockView> + computeReorderIndex | electron-deck/dock-react |

Experimental: declarative assembly

A higher-level declarative surface exists via startElectronDeck() with top-level config (hostServices / events) and high-level runtime APIs (runtime.windows / runtime.view / runtime.scopes):

import { startElectronDeck, defineEvent } from 'electron-deck'

const authChanged = defineEvent<{ user: { id: string } | null }>('authChanged')

startElectronDeck({
	app: { name: 'My Host' },
	hostServices: { getUser: async () => ({ user: null }) },
	events: [authChanged],
})

It currently has no production consumers outside this repo's examples — treat it as @experimental: signatures may change and it has not been validated under non-demo workloads. Its one concrete advantage over electronDeck() is that the call itself returns synchronously, so it never blocks module evaluation — but awaiting handle.ready still has to happen after top-level evaluation finishes, same as electronDeck().

Documentation

Contributing

Issues and pull requests are welcome. Before submitting, run pnpm lint, pnpm check-types, pnpm test, then pnpm build. After the build, run pnpm check:tree-shaking and pnpm check:e2e. The Electron interaction check needs a graphical session; on headless Linux, run it with xvfb-run --auto-servernum pnpm check:e2e.

License

MIT © lbb00