From 9f181b4abc4fbc51ebebed6ae0c9208bec0897c1 Mon Sep 17 00:00:00 2001 From: SSHari Date: Sat, 20 May 2023 13:13:02 -0400 Subject: [PATCH] feat: add console hook to static template --- sandpack-client/rollup.config.js | 4 +- .../src/clients/node/inject-scripts/index.ts | 2 +- sandpack-client/src/clients/node/types.ts | 9 ++- sandpack-client/src/clients/static/index.ts | 57 +++++++++++++++++++ .../node => }/inject-scripts/consoleHook.ts | 0 .../components/Console/Console.stories.tsx | 28 +++++++++ .../components/Console/useSandpackConsole.ts | 9 ++- 7 files changed, 103 insertions(+), 6 deletions(-) rename sandpack-client/src/{clients/node => }/inject-scripts/consoleHook.ts (100%) diff --git a/sandpack-client/rollup.config.js b/sandpack-client/rollup.config.js index 2bcd4be51..6ac089098 100644 --- a/sandpack-client/rollup.config.js +++ b/sandpack-client/rollup.config.js @@ -9,9 +9,9 @@ import pkg from "./package.json"; const configs = [ { - input: "src/clients/node/inject-scripts/consoleHook.ts", + input: "src/inject-scripts/consoleHook.ts", output: { - file: "src/clients/node/inject-scripts/dist/consoleHook.js", + file: "src/inject-scripts/dist/consoleHook.js", format: "es", }, plugins: [ diff --git a/sandpack-client/src/clients/node/inject-scripts/index.ts b/sandpack-client/src/clients/node/inject-scripts/index.ts index b9facd7ff..d08a6e9b9 100644 --- a/sandpack-client/src/clients/node/inject-scripts/index.ts +++ b/sandpack-client/src/clients/node/inject-scripts/index.ts @@ -5,7 +5,7 @@ import { INJECT_MESSAGE_TYPE } from "@codesandbox/nodebox"; // get the bundled file, which contains all dependencies // @ts-ignore -import consoleHook from "./dist/consoleHook.js"; +import consoleHook from "../../../inject-scripts/dist/consoleHook.js"; import { setupHistoryListeners } from "./historyListener"; const scripts = [ diff --git a/sandpack-client/src/clients/node/types.ts b/sandpack-client/src/clients/node/types.ts index de519a0b0..1098a74da 100644 --- a/sandpack-client/src/clients/node/types.ts +++ b/sandpack-client/src/clients/node/types.ts @@ -6,7 +6,7 @@ import type { SandpackLogLevel, } from "../.."; -type SandpackStandartMessages = +type SandpackStandardMessages = | { type: "start"; firstLoad?: boolean; @@ -60,9 +60,13 @@ type SandpackShellMessages = | { type: "shell/openPreview" } | { type: "shell/progress"; data: WorkerStatusUpdate & { command?: string } }; +type SandpackConsoleMessages = + | { type: "console/register" } + | { type: "console/unregister" }; + export type SandpackNodeMessage = BaseSandpackMessage & ( - | SandpackStandartMessages + | SandpackStandardMessages | SandpackURLsMessages | SandpackBundlerMessages | SandpackShellMessages @@ -72,6 +76,7 @@ export type SandpackNodeMessage = BaseSandpackMessage & payload: SandpackShellStdoutData; } | SandpackFSMessages + | SandpackConsoleMessages ); export interface SandpackShellStdoutData { diff --git a/sandpack-client/src/clients/static/index.ts b/sandpack-client/src/clients/static/index.ts index 14b5c50d2..782d98daf 100644 --- a/sandpack-client/src/clients/static/index.ts +++ b/sandpack-client/src/clients/static/index.ts @@ -15,10 +15,15 @@ import type { SandpackNodeMessage } from "../node/types"; import { insertHtmlAfterRegex, readBuffer, validateHtml } from "./utils"; +// get the bundled file, which contains all dependencies +// @ts-ignore +import consoleHook from "../../inject-scripts/dist/consoleHook.js"; + export class SandpackStatic extends SandpackClient { private emitter: EventEmitter; private previewController: PreviewController; private files: Map = new Map(); + private registeredConsoleCount = 0; public iframe!: HTMLIFrameElement; public selector!: string; @@ -50,6 +55,12 @@ export class SandpackStatic extends SandpackClient { content, options.externalResources ); + + if (this.registeredConsoleCount > 0) { + content = this.injectScriptIntoHead(content, { + script: consoleHook, + }); + } } catch (err) { console.error("Runtime injection failed", err); } @@ -80,6 +91,11 @@ export class SandpackStatic extends SandpackClient { ); } + this.eventListener = this.eventListener.bind(this); + if (typeof window !== "undefined") { + window.addEventListener("message", this.eventListener); + } + // Dispatch very first compile action this.updateSandbox(); } @@ -137,6 +153,21 @@ export class SandpackStatic extends SandpackClient { return this.injectContentIntoHead(content, tagsToInsert); } + private injectScriptIntoHead( + content: FileContent, + opts: { script: string; scope?: Record } + ): FileContent { + const { script, scope = {} } = opts; + const scriptToInsert = ` + + `.trim(); + + return this.injectContentIntoHead(content, scriptToInsert); + } + public updateSandbox( setup = this.sandboxSetup, _isInitializationCompile?: boolean @@ -169,6 +200,21 @@ export class SandpackStatic extends SandpackClient { }); } + // Handles message windows coming from iframes + private eventListener(evt: MessageEvent): void { + // skip events originating from different iframes + if (evt.source !== this.iframe.contentWindow) { + return; + } + + const message = evt.data; + if (!message.codesandbox) { + return; + } + + this.dispatch(message); + } + /** * Bundler communication */ @@ -178,6 +224,14 @@ export class SandpackStatic extends SandpackClient { this.compile(message.modules); break; + case "console/register": + this.registeredConsoleCount += 1; + break; + + case "console/unregister": + this.registeredConsoleCount -= 1; + break; + default: this.iframe.contentWindow?.postMessage(message, "*"); this.emitter.dispatch(message); @@ -190,5 +244,8 @@ export class SandpackStatic extends SandpackClient { public destroy(): void { this.emitter.cleanup(); + if (typeof window !== "undefined") { + window.removeEventListener("message", this.eventListener); + } } } diff --git a/sandpack-client/src/clients/node/inject-scripts/consoleHook.ts b/sandpack-client/src/inject-scripts/consoleHook.ts similarity index 100% rename from sandpack-client/src/clients/node/inject-scripts/consoleHook.ts rename to sandpack-client/src/inject-scripts/consoleHook.ts diff --git a/sandpack-react/src/components/Console/Console.stories.tsx b/sandpack-react/src/components/Console/Console.stories.tsx index 0d7631ff0..e8cd4e23c 100644 --- a/sandpack-react/src/components/Console/Console.stories.tsx +++ b/sandpack-react/src/components/Console/Console.stories.tsx @@ -235,3 +235,31 @@ export const MaxMessageCount = () => { ); }; + +export const StaticTemplateConsole = () => { + const indexHtml = ` + + + + + + + + +

Hello Sandpack!

+ + + + +`.trim(); + + return ( + + + + + + + + ); +}; diff --git a/sandpack-react/src/components/Console/useSandpackConsole.ts b/sandpack-react/src/components/Console/useSandpackConsole.ts index 1080ba172..7ba525d49 100644 --- a/sandpack-react/src/components/Console/useSandpackConsole.ts +++ b/sandpack-react/src/components/Console/useSandpackConsole.ts @@ -26,7 +26,14 @@ export const useSandpackConsole = ({ resetOnPreviewRestart: boolean; }): { logs: SandpackConsoleData; reset: () => void } => { const [logs, setLogs] = React.useState([]); - const { listen } = useSandpack(); + const { listen, dispatch } = useSandpack(); + + React.useEffect(() => { + dispatch({ type: "console/register" }, clientId); + return () => { + dispatch({ type: "console/unregister" }, clientId); + }; + }, [dispatch, clientId]); React.useEffect(() => { const unsubscribe = listen((message) => {