Skip to content

Commit

Permalink
feat: add console hook to static template (#909)
Browse files Browse the repository at this point in the history
Co-authored-by: Danilo Woznica <danilowoz@gmail.com>
  • Loading branch information
SSHari and danilowoz committed Sep 11, 2023
1 parent 349c68d commit 1a473e3
Show file tree
Hide file tree
Showing 10 changed files with 208 additions and 7 deletions.
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
3 changes: 2 additions & 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,8 @@ 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
4 changes: 2 additions & 2 deletions sandpack-client/src/clients/node/taskManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,14 @@ type Token =
| { type: TokenType.OR | TokenType.AND | TokenType.PIPE }
| {
type: TokenType.Command | TokenType.Argument | TokenType.String;
value: string;
value?: string;
}
| {
type: TokenType.EnvVar;
value: Record<string, string>;
};

const operators = new Map<string, { type: TokenType }>([
const operators = new Map<string, Token>([
["&&", { type: TokenType.AND }],
["||", { type: TokenType.OR }],
["|", { type: TokenType.PIPE }],
Expand Down
52 changes: 51 additions & 1 deletion sandpack-client/src/clients/static/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
import type { FilesMap } from "@codesandbox/nodebox";
import type { FileContent } from "static-browser-server";
import { PreviewController } from "static-browser-server";
Expand All @@ -8,9 +9,12 @@ import type {
SandboxSetup,
UnsubscribeFunction,
} from "../..";
// get the bundled file, which contains all dependencies
// @ts-ignore
import consoleHook from "../../inject-scripts/dist/consoleHook.js";
import { SandpackClient } from "../base";
import { EventEmitter } from "../event-emitter";
import { fromBundlerFilesToFS } from "../node/client.utils";
import { fromBundlerFilesToFS, generateRandomId } from "../node/client.utils";
import type { SandpackNodeMessage } from "../node/types";

import { insertHtmlAfterRegex, readBuffer, validateHtml } from "./utils";
Expand Down Expand Up @@ -52,6 +56,10 @@ export class SandpackStatic extends SandpackClient {
content,
options.externalResources
);
content = this.injectScriptIntoHead(content, {
script: consoleHook,
scope: { channelId: generateRandomId() },
});
} catch (err) {
console.error("Runtime injection failed", err);
}
Expand Down Expand Up @@ -82,6 +90,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 @@ -139,6 +152,25 @@ export class SandpackStatic extends SandpackClient {
return this.injectContentIntoHead(content, tagsToInsert);
}

private injectScriptIntoHead(
content: FileContent,
opts: {
script: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
scope?: { channelId: string } & 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 @@ -172,6 +204,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 @@ -193,5 +240,8 @@ export class SandpackStatic extends SandpackClient {

public destroy(): void {
this.emitter.cleanup();
if (typeof window !== "undefined") {
window.removeEventListener("message", this.eventListener);
}
}
}
54 changes: 54 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,57 @@ export const MaxMessageCount = () => {
</>
);
};

export const StaticTemplate: React.FC = () => {
return (
<Sandpack
files={{
"index.html": `<!DOCTYPE html>
<html>
<head>
<title>Parcel Sandbox</title>
<meta charset="UTF-8" />
<link rel="stylesheet" href="/styles.css" />
<script>
console.log("fooo")
</script>
</head>
<body>
<h1>Hello world</h1>
<button onclick="console.log(document.querySelectorAll('button'))">Log</button>
<button onclick="console.log(document.querySelectorAll('button'))">Log</button>
</body>
</html>`,
}}
options={{ showConsole: true }}
template="static"
/>
);
};

export const NodeTemplate: React.FC = () => {
return <Sandpack options={{ showConsole: true }} template="node" />;
};

export const ReactTemplate: React.FC = () => {
return (
<Sandpack
options={{ showConsole: true }}
files={{
"App.js": `import { useState } from "react"
export default function App() {
const foo = useState("")
console.log(foo)
return (
<>
</>
)
}`,
}}
template="react"
/>
);
};
1 change: 0 additions & 1 deletion sandpack-react/src/components/Console/ConsoleList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const ConsoleList: React.FC<{ data: SandpackConsoleData }> = ({
data,
}) => {
const classNames = useClassNames();

return (
<>
{data.map(({ data, id, method }, logIndex, references) => {
Expand Down
1 change: 1 addition & 0 deletions sandpack-react/src/components/Console/utils/constraints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const CLEAR_LOG = {
};

export const TRANSFORMED_TYPE_KEY = "@t";
export const TRANSFORMED_TYPE_KEY_ALTERNATE = "#@t";
export const CIRCULAR_REF_KEY = "@r";

export const MAX_LENGTH_STRING = 10000;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,73 @@ const cases: Array<[Message, string]> = [
{ constructor: { name: "CustomThing" } },
'CustomThing { constructor: { name: "CustomThing" } }',
],
[
{
"0": {
"#@t": "HTMLElement",
data: {
tagName: "button",
attributes: {},
innerHTML: "Test",
},
},
"1": {
"#@t": "HTMLElement",
data: {
tagName: "button",
attributes: {
onclick: "console.log(document.querySelectorAll('button'))",
},
innerHTML: "Log",
},
},
entries: {
"#@t": "Function",
data: {
name: "entries",
body: "",
proto: "Function",
},
},
keys: {
"#@t": "Function",
data: {
name: "keys",
body: "",
proto: "Function",
},
},
values: {
"#@t": "Function",
data: {
name: "values",
body: "",
proto: "Function",
},
},
forEach: {
"#@t": "Function",
data: {
name: "forEach",
body: "",
proto: "Function",
},
},
length: 2,
item: {
"#@t": "Function",
data: {
name: "item",
body: "",
proto: "Function",
},
},
constructor: {
name: "NodeList",
},
},
`NodeList(2)[<button>Test</button>,<button onclick="console.log(document.querySelectorAll('button'))">Log</button>]`,
],

/**
* Function
Expand Down
29 changes: 29 additions & 0 deletions sandpack-react/src/components/Console/utils/fromConsoleToString.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import {
TRANSFORMED_TYPE_KEY,
TRANSFORMED_TYPE_KEY_ALTERNATE,
MAX_NEST_LEVEL,
MAX_KEYS,
MAX_LENGTH_STRING,
Expand Down Expand Up @@ -48,6 +49,25 @@ const formatSymbols = (message: Message): any => {
const transform = transformers[type];

return transform(message.data);
} else if (
typeof message == "object" &&
TRANSFORMED_TYPE_KEY_ALTERNATE in message
) {
const type = message[TRANSFORMED_TYPE_KEY_ALTERNATE] as TransformsTypes;
const transform = transformers[type];

return transform(message.data);
} else if (
typeof message == "object" &&
message.constructor?.name === "NodeList"
) {
const NodeList = {};
Object.entries(message).forEach(([key, value]) => {
// @ts-ignore
NodeList[key] = formatSymbols(value);
});

return NodeList;
}

return message;
Expand Down Expand Up @@ -163,6 +183,15 @@ export const fromConsoleToString = (
return fromConsoleToString(newMessage, references, level + 1);
}

if (output.constructor?.name === "NodeList") {
const length = output.length;
const nodes = new Array(length).fill(null).map((_, index) => {
return fromConsoleToString(output[index], references);
});

return `NodeList(${output.length})[${nodes}]`;
}

return objectToString(output, references, level + 1);
}
} catch {
Expand Down

1 comment on commit 1a473e3

@vercel
Copy link

@vercel vercel bot commented on 1a473e3 Sep 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.