Integración con iframe
Si buscas una visión general independiente del transporte, empieza por Resumen.
Cuándo conviene usar iframe
Enlace al encabezadoEl transporte con iframe es la opción base en navegador para ejecutar extensiones remotas aisladas:
- host y remoto corren en contextos de navegador distintos;
- la comunicación usa
postMessagepor medio de@remote-ui/rpc; - la aplicación host mantiene el control del render a través de
provideryreceiver.
Ejemplo del lado host
Enlace al encabezadoimport type { Channel } from '@omnicajs/vue-remote/host'import type { Endpoint } from '@remote-ui/rpc'
import { createApp, defineComponent, h, onBeforeUnmount, onMounted, ref } from 'vue'import { HostedTree, createProvider, createReceiver } from '@omnicajs/vue-remote/host'import { createEndpoint, fromIframe } from '@remote-ui/rpc'
import VButton from './components/VButton.vue'import VInput from './components/VInput.vue'
type HostBridge = { track(event: { type: string; payload: Record<string, unknown> }): void;}
type RemoteApi = { run(channel: Channel, bridge: HostBridge): Promise<void>; release(): void;}
const provider = createProvider({ VButton, VInput })
export function mountIframeRemote(remoteUrl: string, bridge: HostBridge) { return createApp(defineComponent({ setup() { const iframe = ref<HTMLIFrameElement | null>(null) const receiver = createReceiver() let endpoint: Endpoint<RemoteApi> | null = null
onMounted(() => { endpoint = createEndpoint<RemoteApi>(fromIframe(iframe.value as HTMLIFrameElement, { terminate: false, })) })
onBeforeUnmount(() => endpoint?.call.release())
return () => [ h(HostedTree, { provider, receiver }), h('iframe', { ref: iframe, src: remoteUrl, style: { display: 'none' }, onLoad: () => endpoint?.call.run(receiver.receive, bridge), }), ] }, }))}Ejemplo del lado remoto
Enlace al encabezadoimport { createEndpoint, fromInsideIframe, release, retain } from '@remote-ui/rpc'import { createRemoteRenderer, createRemoteRoot, defineRemoteComponent } from '@omnicajs/vue-remote/remote'import { defineComponent, h, ref } from 'vue'
type HostBridge = { track(event: { type: string; payload: Record<string, unknown> }): void;}
const VButton = defineRemoteComponent('VButton')const VInput = defineRemoteComponent('VInput', [ 'update:value',] as unknown as { 'update:value': (value: string) => true;})
const endpoint = createEndpoint(fromInsideIframe())let onRelease = () => {}
endpoint.expose({ async run(channel, bridge: HostBridge) { retain(channel) retain(bridge)
const root = createRemoteRoot(channel, { components: ['VButton', 'VInput'], }) await root.mount()
const app = createRemoteRenderer(root).createApp(defineComponent({ setup() { const text = ref('') return () => [ h(VInput, { value: text.value, 'onUpdate:value': (value: string) => text.value = value, }), h(VButton, { onClick: () => bridge.track({ type: 'remote.clear', payload: { value: text.value }, }), }, 'Clear'), ] }, }))
app.mount(root)
onRelease = () => { release(channel) release(bridge) app.unmount() } },
release() { onRelease() },})Secuencia de arranque con iframe
Enlace al encabezado- El host renderiza
HostedTreey creareceiver. - El host carga la URL remota en un iframe oculto.
- El iframe remoto expone
run/release. - Cuando se dispara
load, el host llama arun(receiver.receive, hostBridge). - El remoto monta la interfaz y sincroniza las actualizaciones del árbol por el canal.
- El host llama a
release()al cerrar la sesión.
Recomendaciones de seguridad para iframe
Enlace al encabezado- Restringe los orígenes: usa orígenes permitidos explícitos en lugar de comodines demasiado abiertos.
- Valida las URLs remotas: usa una allowlist para las fuentes del entorno de extensiones.
- Ajusta correctamente los atributos del iframe:
configura
sandboxde acuerdo con tu modelo de confianza. - Alinea la política de CSP y de frame:
asegúrate de que
frame-srcychild-srcsolo permitan los orígenes aprobados.
Errores comunes
Enlace al encabezado- Llamar a
run(...)antes de que termine de cargar el iframe. - Olvidar registrar los componentes host en el provider.
- Pasar payloads no serializables a través de la frontera.
- Olvidar
release()y dejar referencias retenidas.