Skip to content

Commit

Permalink
Separate out JS-execution code into a 'Kernel'
Browse files Browse the repository at this point in the history
  • Loading branch information
rameshvarun committed Sep 2, 2023
1 parent 3af920c commit 03f7738
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 34 deletions.
47 changes: 14 additions & 33 deletions src/blog-cells.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
// @ts-ignore
import WORKER_SRC from "!raw-loader!ts-loader!./blog-cells-worker.ts";

import { history, defaultKeymap, historyKeymap } from "@codemirror/commands";
import { EditorView, lineNumbers, keymap } from "@codemirror/view";
import { javascript } from "@codemirror/lang-javascript";
import { oneDark } from "@codemirror/theme-one-dark";

import * as React from "react";
Expand All @@ -13,18 +9,12 @@ import * as ReactDOM from "react-dom/client";
const SCRIPT_URL = import.meta.url;
const SCRIPT_DIR = SCRIPT_URL.substring(0, SCRIPT_URL.lastIndexOf("/"));

// Create webworker.
const blob = new Blob([WORKER_SRC], { type: "application/javascript" });
const worker: Worker = new Worker(URL.createObjectURL(blob));

let requestID = 0;
function getRequestID() {
return requestID++;
}

const editors: any[] = [];
const events = new EventTarget();

import { JavaScriptKernel } from "./javascript-kernel";
const kernel = new JavaScriptKernel();

class Cell extends React.Component<
{
code: string;
Expand Down Expand Up @@ -139,7 +129,7 @@ class Cell extends React.Component<
extensions: [
history(),
lineNumbers(),
javascript(),
kernel.getSyntaxHighlighter(),
oneDark,
keymap.of([...defaultKeymap, ...historyKeymap]),
],
Expand All @@ -166,21 +156,19 @@ class Cell extends React.Component<
this.state.output = [];
}

const requestID = getRequestID();

worker.postMessage({
kind: "run-code",
code: code,
requestID: requestID,
});

const minimumWait = new Promise<void>((resolve, reject) => {
setTimeout(() => resolve(), 500);
});

const messageHandler = async (e) => {
if (e.data.requestID != requestID) return;
if (e.data.kind === "run-code-done") {
kernel.run(
code,
(line) => {
this.setState((state) => {
state.output.push(line);
return state;
});
},
async () => {
// Wait the minimum amount of run-time.
await minimumWait;

Expand All @@ -191,15 +179,8 @@ class Cell extends React.Component<
state.output.push({ type: "log", line: "Done." });
return state;
});
worker.removeEventListener("message", messageHandler);
} else if (e.data.kind === "run-code-output") {
this.setState((state) => {
state.output.push(e.data.output);
return state;
});
}
};
worker.addEventListener("message", messageHandler);
);
}
}

Expand Down
45 changes: 45 additions & 0 deletions src/javascript-kernel/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// @ts-ignore - Load worker source code.
import WORKER_SRC from "!raw-loader!ts-loader!./worker.ts";
const blob = new Blob([WORKER_SRC], { type: "application/javascript" });

import { javascript } from "@codemirror/lang-javascript";
import { Kernel, OutputLine } from "../kernel";
import { ExecutionRequest, ExecutionResponse } from "./types";

export class JavaScriptKernel implements Kernel {
worker: Worker = new Worker(URL.createObjectURL(blob));

requestID: number = 0;
getRequestID() {
return this.requestID++;
}

run(code: string, onOutput: (line: OutputLine) => void, onDone: () => void) {
// Generate a unique ID to track this execution request.
const requestID = this.getRequestID();

const messageHandler = (e: MessageEvent<ExecutionResponse>) => {
if (e.data.requestID != requestID) return;

if (e.data.kind === "run-code-output") {
onOutput(e.data.output);
} else if (e.data.kind === "run-code-done") {
this.worker.removeEventListener("message", messageHandler);
onDone();
}
};

this.worker.addEventListener("message", messageHandler);

// Post the code to the worker.
this.worker.postMessage({
kind: "run-code",
code: code,
requestID: requestID,
} as ExecutionRequest);
}

getSyntaxHighlighter() {
return javascript();
}
}
19 changes: 19 additions & 0 deletions src/javascript-kernel/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { OutputLine } from "../kernel";

export type ExecutionRequest = {
kind: "run-code";
code: string;
requestID: number;
}

export type ExecutionResponse = {
kind: "run-code-output";
output: OutputLine;
requestID: number;
} | {
kind: "run-code-done";
requestID: number;
} | {
kind: "run-code-waiting";
requestID: number;
};
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ ${transform(code, Object.keys(this.module))}`;

const executor = new Executor();

self.onmessage = async (e) => {
self.onmessage = async (e: MessageEvent) => {
console.log("Worker received message: %o", e);
const requestID = e.data.requestID;
if (e.data.kind === "run-code") {
Expand Down
11 changes: 11 additions & 0 deletions src/kernel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { LanguageSupport } from "@codemirror/language";

export type OutputLine = {
type: string;
line: string;
};

export interface Kernel {
run(code: string, onOutput: (line: OutputLine) => void, onDone: () => void);
getSyntaxHighlighter(): LanguageSupport;
}

0 comments on commit 03f7738

Please sign in to comment.