Skip to content

Transport Types

RemObj supports various transport mechanisms for different environments and use cases.

Web Transports

Web Workers

The most common use case for offloading CPU-intensive tasks:

typescript
import { provide, consume } from '@remobj/core'
import { createWebWorkerEndpoint } from '@remobj/web'

// In worker.js
const endpoint = createWebWorkerEndpoint(self)
provide(api, endpoint)

// In main thread
const worker = new Worker('./worker.js', { type: 'module' })
const endpoint = createWebWorkerEndpoint(worker)
const remote = consume(endpoint)

Service Workers

For background processing and caching:

typescript
import { createServiceWorkerEndpoint } from '@remobj/web'

// In service worker
const endpoint = createServiceWorkerEndpoint(self)
provide(cacheAPI, endpoint)

// In main app
const registration = await navigator.serviceWorker.register('./sw.js')
const endpoint = createServiceWorkerEndpoint(registration)
const cache = consume(endpoint)

iFrames

For sandboxed execution:

typescript
import { createWindowEndpoint } from '@remobj/web'

// In iframe
const endpoint = createWindowEndpoint(window.parent, '*')
provide(sandboxAPI, endpoint)

// In parent
const iframe = document.querySelector('iframe')
const endpoint = createWindowEndpoint(iframe.contentWindow, '*')
const sandbox = consume(endpoint)

WebSockets

For client-server communication:

typescript
import { createWebsocketEndpoint } from '@remobj/core'

// Client
const ws = new WebSocket('ws://localhost:8080')
const endpoint = createWebsocketEndpoint(ws)
const api = consume(endpoint)

// Server (Node.js)
import { WebSocketServer } from 'ws'

const wss = new WebSocketServer({ port: 8080 })
wss.on('connection', (ws) => {
  const endpoint = createWebsocketEndpoint(ws)
  provide(serverAPI, endpoint)
})

Node.js Transports

Child Processes

For CPU isolation and fault tolerance:

typescript
import { fork } from 'child_process'
import { createChildProcessEndpoint } from '@remobj/node'

// Parent process
const child = fork('./child.js')
const endpoint = createChildProcessEndpoint(child)
const remote = consume(endpoint)

// Child process
const endpoint = createChildProcessEndpoint(process)
provide(childAPI, endpoint)

Worker Threads

For true parallelism in Node.js:

typescript
import { Worker } from 'worker_threads'
import { createWorkerThreadEndpoint } from '@remobj/node'

// Main thread
const worker = new Worker('./worker.js')
const endpoint = createWorkerThreadEndpoint(worker)
const remote = consume(endpoint)

// Worker thread
import { parentPort } from 'worker_threads'
const endpoint = createWorkerThreadEndpoint(parentPort)
provide(workerAPI, endpoint)

Custom Endpoints

You can create custom endpoints for any message-passing interface:

typescript
import { PostMessageEndpoint } from '@remobj/core'

class CustomEndpoint implements PostMessageEndpoint {
  addEventListener(event: 'message', listener: (event: MessageEvent) => void): void {
    // Implement message listening
  }
  
  removeEventListener(event: 'message', listener: (event: MessageEvent) => void): void {
    // Implement listener removal
  }
  
  postMessage(message: any): void {
    // Implement message sending
  }
}

const endpoint = new CustomEndpoint()
provide(api, endpoint)

Connection Patterns

One-to-One

Standard pattern where one provider serves one consumer:

typescript
// Provider
provide(api, endpoint)

// Consumer
const remote = consume(endpoint)

One-to-Many (Broadcast)

One provider serving multiple consumers:

typescript
// Provider
provide(api, broadcastEndpoint)

// Multiple consumers
const remote1 = consume(endpoint1)
const remote2 = consume(endpoint2)

Many-to-One (Load Balancing)

Multiple providers behind a single consumer interface:

typescript
// Multiple workers
workers.forEach(worker => {
  const endpoint = createWebWorkerEndpoint(worker)
  provide(api, endpoint)
})

// Consumer with load balancer
const remote = consume(loadBalancerEndpoint)

Choosing the Right Transport

TransportUse CaseProsCons
Web WorkerCPU-intensive tasksTrue parallelism, no UI blockingLimited API access
Service WorkerBackground tasks, cachingRuns in background, intercepts requestsComplex lifecycle
iframeSandboxing, third-party codeSecurity isolationPerformance overhead
WebSocketReal-time, bidirectionalServer communicationNetwork dependency
Child ProcessSystem tasks, isolationFull Node.js API, fault isolationMemory overhead
Worker ThreadParallel processingShared memory possibleNode.js only

Performance Considerations

Serialization

RemObj automatically handles serialization, but be aware of limitations:

typescript
// ✅ These work fine
const api = {
  processData: (data: number[]) => data.map(x => x * 2),
  getUserInfo: () => ({ name: 'John', age: 30 })
}

// ❌ These won't work (non-serializable)
const api = {
  returnFunction: () => () => 'Hello',  // Functions can't be serialized
  returnMap: () => new Map(),           // Maps need special handling
  returnSymbol: () => Symbol('test')    // Symbols can't be serialized
}

Message Size

Large messages can impact performance:

typescript
// Consider chunking for large data
const api = {
  processLargeData: async function* (data: ArrayBuffer) {
    const chunkSize = 1024 * 1024 // 1MB chunks
    for (let i = 0; i < data.byteLength; i += chunkSize) {
      const chunk = data.slice(i, i + chunkSize)
      yield await processChunk(chunk)
    }
  }
}

Next Steps

  • Learn about multiplexing for multiple channels
  • Explore error handling strategies
  • Set up DevTools for debugging

Note: Additional guides for multiplexing, error handling, and DevTools are coming soon.

Released under the MIT License.