Skip to content

feat: add console hook to static template #943

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions sandpack-client/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: [
Expand Down
2 changes: 1 addition & 1 deletion sandpack-client/src/clients/node/inject-scripts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
9 changes: 7 additions & 2 deletions sandpack-client/src/clients/node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type {
SandpackLogLevel,
} from "../..";

type SandpackStandartMessages =
type SandpackStandardMessages =
| {
type: "start";
firstLoad?: boolean;
Expand Down Expand Up @@ -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
Expand All @@ -72,6 +76,7 @@ export type SandpackNodeMessage = BaseSandpackMessage &
payload: SandpackShellStdoutData;
}
| SandpackFSMessages
| SandpackConsoleMessages
);

export interface SandpackShellStdoutData {
Expand Down
57 changes: 57 additions & 0 deletions sandpack-client/src/clients/static/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string, string | Uint8Array> = new Map();
private registeredConsoleCount = 0;

public iframe!: HTMLIFrameElement;
public selector!: string;
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -137,6 +153,21 @@ export class SandpackStatic extends SandpackClient {
return this.injectContentIntoHead(content, tagsToInsert);
}

private injectScriptIntoHead(
content: FileContent,
opts: { script: string; scope?: Record<string, any> }
): FileContent {
const { script, scope = {} } = opts;
const scriptToInsert = `
<script>
const scope = ${JSON.stringify(scope)};
${script}
</script>
`.trim();

return this.injectContentIntoHead(content, scriptToInsert);
}

public updateSandbox(
setup = this.sandboxSetup,
_isInitializationCompile?: boolean
Expand Down Expand Up @@ -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
*/
Expand All @@ -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);
Expand All @@ -190,5 +244,8 @@ export class SandpackStatic extends SandpackClient {

public destroy(): void {
this.emitter.cleanup();
if (typeof window !== "undefined") {
window.removeEventListener("message", this.eventListener);
}
}
}
28 changes: 28 additions & 0 deletions sandpack-react/src/components/Console/Console.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,31 @@ export const MaxMessageCount = () => {
</>
);
};

export const StaticTemplateConsole = () => {
const indexHtml = `
<!DOCTYPE html>
<html>

<head>
<script>function logMsg() { console.log('Hello Sandpack!'); }</script>
</head>

<body>
<h1>Hello Sandpack!</h1>
<button onclick="logMsg()">Log Message</button>
</body>

</html>
`.trim();

return (
<SandpackProvider template="static" files={{ "/index.html": indexHtml }}>
<SandpackLayout>
<SandpackCodeEditor />
<SandpackPreview />
<SandpackConsole />
</SandpackLayout>
</SandpackProvider>
);
};
9 changes: 8 additions & 1 deletion sandpack-react/src/components/Console/useSandpackConsole.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,14 @@ export const useSandpackConsole = ({
resetOnPreviewRestart: boolean;
}): { logs: SandpackConsoleData; reset: () => void } => {
const [logs, setLogs] = React.useState<SandpackConsoleData>([]);
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) => {
Expand Down