A tool for people curious about the React Server Components protocol
at main 2.1 kB view raw
1/** 2 * RSC Explorer Embed API 3 * 4 * Usage: 5 * ```html 6 * <div id="demo" style="height: 500px;"></div> 7 * <script type="module"> 8 * import { mount } from 'https://rscexplorer.dev/embed.js'; 9 * 10 * mount('#demo', { 11 * server: ` 12 * export default function App() { 13 * return <h1>Hello RSC</h1>; 14 * } 15 * `, 16 * client: ` 17 * 'use client' 18 * export function Button() { 19 * return <button>Click</button>; 20 * } 21 * ` 22 * }); 23 * </script> 24 * ``` 25 */ 26 27// Get the embed URL relative to this script's location 28const getEmbedUrl = () => { 29 return new URL('embed.html', import.meta.url).href; 30}; 31 32/** 33 * Mount an RSC Explorer embed into a container element 34 * @param {string|HTMLElement} container - CSS selector or DOM element 35 * @param {Object} options - Configuration options 36 * @param {string} options.server - Server component code 37 * @param {string} options.client - Client component code 38 * @returns {Object} - Control object with methods to interact with the embed 39 */ 40export function mount(container, { server, client }) { 41 const el = 42 typeof container === "string" 43 ? document.querySelector(container) 44 : container; 45 46 if (!el) { 47 throw new Error(`RSC Explorer: Container not found: ${container}`); 48 } 49 50 // Create iframe 51 const iframe = document.createElement("iframe"); 52 iframe.src = getEmbedUrl(); 53 iframe.style.cssText = 54 "width: 100%; height: 100%; border: 1px solid #e0e0e0; border-radius: 8px;"; 55 56 // Wait for iframe to be ready, then send code 57 const handleMessage = (event) => { 58 if (event.source !== iframe.contentWindow) return; 59 60 if (event.data?.type === "rsc-embed:ready") { 61 iframe.contentWindow.postMessage( 62 { 63 type: "rsc-embed:init", 64 code: { server: server.trim(), client: client.trim() }, 65 }, 66 "*", 67 ); 68 } 69 }; 70 71 window.addEventListener("message", handleMessage); 72 73 // Clear container and add iframe 74 el.innerHTML = ""; 75 el.appendChild(iframe); 76 77 // Return control object 78 return { 79 iframe, 80 destroy: () => { 81 window.removeEventListener("message", handleMessage); 82 el.innerHTML = ""; 83 }, 84 }; 85}