mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-03-12 17:37:24 +00:00
docs(plugins): update README for ES module frontend
Replace iframe-based plugin documentation with ES module approach. Update architecture diagram, file structure, and manifest.json examples to reflect the switch from index.html/iframe to index.js/module with mount/unmount exports and api.rpc() helper.
This commit is contained in:
@@ -38,7 +38,6 @@ export default function PluginTabContent({
|
||||
selectedSession,
|
||||
}: PluginTabContentProps) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||
const { isDarkMode } = useTheme();
|
||||
const { plugins } = usePlugins();
|
||||
|
||||
@@ -49,8 +48,6 @@ export default function PluginTabContent({
|
||||
const moduleRef = useRef<any>(null);
|
||||
|
||||
const plugin = plugins.find(p => p.name === pluginName);
|
||||
// 'iframe' is the explicit legacy type; everything else (including 'module' and unset) uses module loading
|
||||
const isIframe = plugin?.type === 'iframe';
|
||||
|
||||
// Keep contextRef current and notify the mounted plugin on every context change
|
||||
useEffect(() => {
|
||||
@@ -60,16 +57,10 @@ export default function PluginTabContent({
|
||||
for (const cb of contextCallbacksRef.current) {
|
||||
try { cb(ctx); } catch { /* plugin error — ignore */ }
|
||||
}
|
||||
}, [isDarkMode, selectedProject, selectedSession]);
|
||||
|
||||
// Also push to legacy iframe plugin
|
||||
if (isIframe && iframeRef.current?.contentWindow) {
|
||||
iframeRef.current.contentWindow.postMessage({ type: 'ccui:context', ...ctx }, '*');
|
||||
}
|
||||
}, [isDarkMode, selectedProject, selectedSession, isIframe]);
|
||||
|
||||
// ── Module plugin (default) ──────────────────────────────────────
|
||||
useEffect(() => {
|
||||
if (isIframe || !containerRef.current) return;
|
||||
if (!containerRef.current) return;
|
||||
|
||||
let active = true;
|
||||
const container = containerRef.current;
|
||||
@@ -121,68 +112,7 @@ export default function PluginTabContent({
|
||||
contextCallbacksRef.current.clear();
|
||||
moduleRef.current = null;
|
||||
};
|
||||
}, [pluginName, isIframe, plugin?.entry]); // re-mount only when the plugin itself changes
|
||||
|
||||
// ── Legacy iframe plugin ─────────────────────────────────────────
|
||||
useEffect(() => {
|
||||
if (!isIframe) return;
|
||||
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
if (event.source !== iframeRef.current?.contentWindow) return;
|
||||
if (!event.data || typeof event.data !== 'object') return;
|
||||
|
||||
const { type } = event.data;
|
||||
|
||||
switch (type) {
|
||||
case 'ccui:request-context':
|
||||
iframeRef.current?.contentWindow?.postMessage(
|
||||
{ type: 'ccui:context', ...contextRef.current },
|
||||
'*',
|
||||
);
|
||||
break;
|
||||
|
||||
case 'ccui:rpc': {
|
||||
const { requestId, method, path: rpcPath, body } = event.data;
|
||||
if (!requestId || !rpcPath) break;
|
||||
const cleanPath = String(rpcPath).replace(/^\//, '');
|
||||
authenticatedFetch(`/api/plugins/${encodeURIComponent(pluginName)}/rpc/${cleanPath}`, {
|
||||
method: method || 'GET',
|
||||
...(body ? { body: JSON.stringify(body) } : {}),
|
||||
})
|
||||
.then(async (res) => {
|
||||
const data = await res.json().catch(() => null);
|
||||
iframeRef.current?.contentWindow?.postMessage(
|
||||
{ type: 'ccui:rpc-response', requestId, status: res.status, data }, '*',
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
iframeRef.current?.contentWindow?.postMessage(
|
||||
{ type: 'ccui:rpc-response', requestId, status: 500, error: (err as Error).message }, '*',
|
||||
);
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener('message', handleMessage);
|
||||
return () => window.removeEventListener('message', handleMessage);
|
||||
}, [isIframe, pluginName]);
|
||||
|
||||
if (isIframe) {
|
||||
const src = `/api/plugins/${encodeURIComponent(pluginName)}/assets/${plugin?.entry ?? 'index.html'}`;
|
||||
return (
|
||||
<div className="h-full w-full overflow-hidden">
|
||||
<iframe
|
||||
ref={iframeRef}
|
||||
src={src}
|
||||
title={`Plugin: ${pluginName}`}
|
||||
className="w-full h-full border-0"
|
||||
sandbox="allow-scripts allow-forms allow-popups"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}, [pluginName, plugin?.entry]); // re-mount only when the plugin itself changes
|
||||
|
||||
return <div ref={containerRef} className="h-full w-full overflow-auto" />;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user