-
-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathWebContainer.astro
More file actions
103 lines (96 loc) · 3.12 KB
/
WebContainer.astro
File metadata and controls
103 lines (96 loc) · 3.12 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
---
import Terminal from "./Terminal.astro";
interface Props {
file: string;
}
const { file } = Astro.props;
---
<web-container name={file}>
<pre data-content><code><slot /></code></pre>
<Terminal />
</web-container>
<script>
import type { Terminal } from "@xterm/xterm";
import { WebContainer } from "@webcontainer/api";
let host: WebContainer;
host = await WebContainer.boot({ workdirName: 'demo' });
const snapshotResponse = await fetch(`/docs/snapshot`);
const snapshot = await snapshotResponse.arrayBuffer();
await host.mount(snapshot, { mountPoint: "/" });
customElements.define(
"web-container",
class extends HTMLElement {
get dir() {
return `${this.name}/`
}
get file() {
return `${this.dir}index.js`;
}
get fileContent() {
const text = this.querySelector("[data-content]")!.textContent;
return `import { intro, outro } from "@clack/prompts";console.clear();intro("\\x1b[46m\\x1b[30m ${this.name} \\x1b[0m");\n${text};process.on('exit', () => console.log('EOF'));`;
}
get name() {
return this.getAttribute("name")!;
}
get terminal(): Terminal | undefined {
return (this.querySelector("docs-terminal") as any)?.instance;
}
async connectedCallback() {
await host.fs.mkdir(this.dir, { recursive: true });
await host.fs.writeFile(
this.file,
this.fileContent,
{ encoding: "utf-8" }
);
await this.render();
}
async render() {
const { terminal, name, render } = this;
terminal?.reset();
const main = async () => {
// we set an infinite loop so that when the user runs the `exit` command, we restart
while (true) {
const jsh = Promise.withResolvers();
let isJSHReady = false;
const process = await host.spawn("jsh", {
cwd: name,
terminal: { rows: terminal?.rows!, cols: terminal?.cols! },
});
process.output.pipeTo(
new WritableStream({
write(data) {
if (data.includes("❯") && !isJSHReady) {
isJSHReady = true;
jsh.resolve(undefined);
}
if (data.includes("❯") || data.includes('~/demo')) {
return;
}
if (data.includes("EOF")) {
process.kill();
render();
return;
}
terminal?.write(data);
}
})
);
const shell = process.input.getWriter();
await jsh.promise;
await shell.write(`node index.js\n`);
// write the terminal input to the process
const terminalWriter = terminal?.onData((data) => {
shell.write(data);
});
// wait for the process to finish
await process.exit;
terminal?.clear();
terminalWriter?.dispose();
}
}
main();
}
}
);
</script>