Skip to content

Introduction

@omnicajs/vue-remote is a render synchronization library for Vue 3 extension ecosystems.

It lets a host product render UI that is described by an isolated remote runtime. The remote side declares component trees, and the host side controls which components are actually allowed and how they are rendered.

Use this library when you want to turn an application into an extension platform:

  • your product owns the host runtime and UI boundaries;
  • third-party teams build extensions independently;
  • extension UI should run in isolation (for example iframe or worker runtime);
  • rendering must still be integrated into host-controlled UI contracts.

At the minimum, host and remote exchange one render channel:

// host
const provider = createProvider({ VButton, VInput })
const receiver = createReceiver()
// render <HostedTree provider={provider} receiver={receiver} />
// then call remote.run(receiver.receive, hostBridge)
// remote
const root = createRemoteRoot(channel, { components: ['VButton', 'VInput'] })
await root.mount()
createRemoteRenderer(root).createApp(RemoteApp).mount(root)

From here, remote components emit intent through props/events, while host stays in control of allowed rendering capabilities.

This model gives host products platform control without forcing extension authors into host internals:

  • Host teams define capability boundaries through provider component contracts.
  • Extension authors focus on product features and UI intent.
  • Runtime isolation reduces accidental coupling and makes upgrades safer.
  • Multiple remote extensions can coexist while sharing one host UX contract.

In a production product, an extension usually needs both render sync and business access:

  1. Render channel: remote renders host-approved components via @omnicajs/vue-remote.
  2. Business bridge: remote calls product APIs through a separate contract (hostBridge).
  3. Capability policy: host decides what each extension can render and call.

This separation is intentional: render lifecycle stays stable even when business contracts evolve.

Two runtimes collaborate:

  1. Host runtime: registers allowed components with createProvider(...), receives remote tree updates with createReceiver(), renders HostedTree.
  2. Remote runtime: creates synchronized root with createRemoteRoot(...), uses createRemoteRenderer(...), references host-exposed components through defineRemoteComponent(...).

Updates move through a channel transport (commonly @remote-ui/rpc).

In scope:

  • synchronized UI tree rendering between host and remote;
  • host-controlled component allowlist;
  • props/events/slots contract across runtime boundary;
  • native remote tags (html, svg, mathml) mirrored into host render tree.

Out of scope:

  • product business API protocol;
  • auth, permissions, billing, marketplace, extension discovery;
  • extension packaging, publishing, lifecycle policy;
  • product-specific governance and trust management.

These capabilities should live in surrounding platform tooling.

A production extension ecosystem usually has three separate layers:

  1. Render synchronization layer (@omnicajs/vue-remote).
  2. Product bridge layer (business methods/data contracts).
  3. Platform layer (permissions, discovery, monetization, governance).

Keeping these layers separate reduces coupling and makes independent versioning possible.

Compared to directly embedding third-party UI code into host runtime:

  • Vue Remote improves host-side control over allowed component surface.
  • It favors explicit contracts over implicit access to host internals.
  • It works better for isolated runtimes where remote does not own real DOM.

The tradeoff is that you must design boundary contracts and serialization rules carefully.

Think about the remote side as a declarative UI intent producer, not as direct DOM owner.

  • Remote code composes UI and emits intent.
  • Host code enforces capabilities, validates boundaries, and performs real rendering.
  • Cross-runtime payloads must stay serializable where data crosses the channel.

This separation keeps extension ecosystems safer and easier to evolve over time.

@omnicajs/vue-remote may be unnecessary if:

  • you own both sides and do not need runtime isolation;
  • you do not need host-controlled component boundaries;
  • a simple local component library solves your integration problem.

It may also be insufficient alone if you need a full plugin platform runtime today. In that case, keep this library as the render core and add platform services around it.

  1. Host product starts extension runtime shell and render receiver.
  2. Remote extension exposes run/release API.
  3. Host provides render channel (and optional business bridge contract).
  4. Remote mounts and renders through synchronized channel updates.
  5. Session ends with release().

See transport-agnostic wiring in Overview, and iframe-specific details in Iframe Integration.