L4 remote WebView
L4 is the highest isolation level for plugin Rendering (Render): the plugin page runs in its own Tauri WebviewWindow (a separate renderer process), isolated from the main interface at the process level. Even if a plugin gets stuck in a busy loop, only its own window freezes; the main UI is unaffected (it can still respond, render, and close). This suits heavy-UI, unrestrained plugins (a complex editor, a game UI enhancement, a long-running background page). Inside an iframe (L2) such plugins still share the same WebView with the main interface, so one infinite loop freezes the whole Launcher.Manifest declaration
L4 Rendering turns on when either condition holds:"render": "webview", or- the
layersarray contains"l4"
plugin-loader.tsx useWebview): render === 'webview' || layers.includes('l4'). A plugin that declares l4 must still provide entry.frontend, or it never activates and renders.
How the cross-window Bridge (bridge)works
An l4 window is not an ordinary child window opened withwindow.open; it is a separate WebView window created through Tauri IPC WebviewWindow (opener is null), so you cannot rely on window.opener.postMessage. Cross-window communication uses the Tauri event system (emitTo / listen; core:event is allowed by default):
- Activation (Activate): when the plugin is enabled,
createRemoteWebviewopens the windowplugin-webview-{id}(1200×800 by default) at the plugin page URL with apluginWebview=1marker. - Lightweight startup: once
App.tsxsees the marker, it skips the main Layout / routes / automatic plugin Activation and renders onlyPluginWebviewPage. - Rendering:
PluginWebviewPagepulls the plugin frontend assets, injects theme variables and the Bridge script throughbuildPluginDoc, and renders the result into an iframe withsandbox="allow-scripts". - API forwarding: an
__PLUGIN_API__call inside the iframe emits an__plugin_api_callmessage → the page forwards it as the Tauri eventemitTo('main', 'plugin-l4-api-call', {pluginId, id, method, args}). - Main window execution:
initL4Bridgein the main window receives the event → it calls the samehandleApiCallused for iframes (METHOD_PERMISSIONSPermission (permissions)check +executePluginMethod) → the response goes back throughemitTo(l4label, 'plugin-l4-api-response')→PluginWebviewPagelistens andpostMessages it back to the iframe unchanged. - Stream abort:
__plugin_api_abort→ theplugin-l4-api-abortevent →abortStreamin the main window.
{type,id,method,args} / {type,id,result,error}); only the transport changes to cross-window events, so plugins see no difference.
Non-Tauri fallback
l4 depends on the Tauri WebViewWindow, so it automatically falls back to an iframe (l2) outside Tauri:- Plain browser / Vite dev (no
window.__TAURI_INTERNALS__):createRemoteWebviewgoes straight tocreateSandbox(iframe Sandbox). - Window creation failure (
tauri://error): the log reports a fallback to an iframe, and it falls back tocreateSandbox.
plugin-webview-{id} label (an existing one is focused, not rebuilt); when you close a window manually, the instance table is cleaned up so deduplication does not misfire.
Trade-offs vs. iframe (l2) / WASM (l3)
- Regular UI plugins → keep the default iframe (l2); do not declare l4 casually.
- Plugins with heavy computation or Rendering that may block the UI → move the heavy work into WASM (l3) first; use l4 only when “the entire page must be isolated in its own process”.
- Need access to the main interface DOM → iframes cannot do it, so use
"render": "inline"(same window as the main interface, weakest isolation; use with care).
Known boundaries (the code is authoritative)
- Cross-plugin calls through
registerMethod/callPlugin: l4 windows are relayed throughplugin-registry.tsin the main window; directly using the registry from the l4 side is marked TODO (see ADR-054), so prefer the main-window registry for plugin-to-plugin calls. - Theme push: l4 windows have no full theme pipeline; the current theme variables (
__qomicex_theme) are pushed once when the iframe firesonload, and new values after a theme switch are not synced automatically (the code is authoritative).