isomorphic-ws

A drop-in isomorphic WebSocket client that exposes one identical API in Node.js and browsers.

Library
npm
v5.0.0
417stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
40/100Fair
Development Activity0
Maintenance20
Community60
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
50/100Fair
Architecture60
Code Quality30
Innovation65
Learning Curve45

isomorphic-ws solves a small but common problem: Node.js has no built-in WebSocket implementation, while browsers ship a native WebSocket global with a different surface than the popular ws package. isomorphic-ws wraps both behind a single import so the same client code runs unmodified on the server and in the browser.

On Node it re-exports the ws package (installed as a peer dependency) directly. In a browser bundle it resolves to whichever global WebSocket (or MozWebSocket) implementation the environment provides. Bundlers pick the right file automatically via the browser field in package.json, so consumers just require('isomorphic-ws') or import WebSocket from 'isomorphic-ws' and get a working client either way.

What You Get

  • A single require('isomorphic-ws')/import that resolves to ws on Node and the native WebSocket global in browsers
  • Automatic environment resolution via package.json’s browser field, so bundlers like Webpack and Rollup pick the right file with zero config
  • TypeScript definitions (index.d.ts) that type the module as the ws package’s WebSocket class
  • Fallback checks for MozWebSocket alongside standard WebSocket for older Firefox builds
  • Zero runtime dependencies of its own beyond the ws peer dependency

Common Use Cases

  • Writing a WebSocket client library that must work identically whether it’s imported in a Node.js backend or bundled into a browser frontend
  • Building isomorphic/universal JavaScript apps (SSR frameworks, shared client SDKs) that establish WebSocket connections from either environment
  • SDKs for realtime services (chat, live data feeds, blockchain nodes) that ship one client package instead of separate Node and browser builds
  • Test suites that need to exercise WebSocket-dependent code under Node without swapping implementations manually

Under The Hood

Architecture The entire package is two tiny entry files selected by package.json’s main/browser fields: node.js simply does module.exports = require('ws'), and browser.js probes WebSocket, MozWebSocket, global, window, and self in turn and exports whichever global constructor it finds. There is no shared internal module, no runtime configuration, and no abstraction layer beyond this environment dispatch — the design intentionally does as little as possible, delegating all actual WebSocket behavior to ws or the browser’s native implementation.

Tech Stack The package has no dependencies of its own; it declares ws as a peerDependency ("ws": "*") that the consumer must install alongside it. It ships plain, unbundled JavaScript (CommonJS for Node, an ES module default export for the browser file) with a hand-written index.d.ts for TypeScript consumers, and the example/ directory shows both a Webpack and a Rollup build integrating the browser entry point. CI (CircleCI, .circleci/config.yml) only installs dependencies — it does not run a build or test step.

Code Quality There are no test files anywhere in the repository, and the CI configuration confirms this — it caches node_modules but never invokes a test runner. Error handling is not applicable given the module’s scope (it either finds a WebSocket implementation or exports undefined/null). There are no linter or formatter configs, and the codebase is small enough (a few dozen lines total) that conventions are simple and consistent, but nothing here is verified by automated tests.

What Makes It Unique The package’s value isn’t novel WebSocket behavior — it deliberately adds none — but a narrow, widely-adopted convention: the browser field swap that lets one import path silently become environment-appropriate code at bundle time. That pattern, combined with matching its API surface to ws so it’s compatible with existing Node WebSocket code, is why it’s become the de facto choice for libraries that need one WebSocket client for both server and browser bundles.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search