I'm currently making an app with vite & WebContainers and have no prior experience with the API or xterm. I followed this tutotial and everything worked well until I decided to add tabs to switch from the terminal, to the editor to the preview box. Then the terminal stopped accepting any input. There weren't any error messages. I didn't change anything to do with the Xterm configuration either. My main.js:
import "./style.css";
import { files } from "./files";
import "xterm/css/xterm.css";
import { Terminal } from "xterm";
import { WebContainer } from "@webcontainer/api";
let WebContainerInstance;
window.addEventListener("load", async () => {
textareaEl.style.height = `${window.innerHeight}px`;
textareaEl.value = files["index.js"].file.contents;
textareaEl.addEventListener("input", () => {
writeIndexJS(textareaEl.currentTarget.value);
});
const terminal = new Terminal({
convertEol: true,
});
terminal.open(terminalEl);
WebContainerInstance = await WebContainer.boot();
await WebContainerInstance.mount(files);
WebContainerInstance.on("server-ready", (port, url) => {
iframeEl.src = url;
});
startShell(terminal);
});
async function startShell(terminal) {
const shellProcess = await WebContainerInstance.spawn("jsh");
shellProcess.output.pipeTo(
new WritableStream({
write(data) {
terminal.write(data);
},
})
);
const input = shellProcess.input.getWriter();
terminal.onData((data) => {
input.write(data);
});
return shellProcess;
}
async function writeIndexJS(content) {
await WebContainerInstance.fs.writeFile("./index.js", content);
}
document.querySelector("#app").innerHTML = `
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0"/>
<div class="header">
<ul>
<li id="term"><span class="material-symbols-outlined">terminal</span></li>
<li id="code"><span class="material-symbols-outlined">code</span></li>
<li id="prev"><span class="material-symbols-outlined">preview</span></li>
</ul>
</div>
<div class="terminal">
</div>
<div class="editor">
<textarea spellcheck="false"></textarea>
</div>
<div class="output">
<iframe src="/load.html">
</div>
`;
const iframeEl = document.querySelector("iframe");
const textareaEl = document.querySelector("textarea");
const terminalEl = document.querySelector(".terminal");
document.getElementById("term").addEventListener("click", () => {
textareaEl.style.display = "none";
iframeEl.style.display = "none";
terminalEl.style.display = "block";
});
document.getElementById("code").addEventListener("click", () => {
terminalEl.style.display = "none";
iframeEl.style.display = "none";
textareaEl.style.display = "block";
});
document.getElementById("prev").addEventListener("click", () => {
textareaEl.style.display = "none";
terminalEl.style.display = "none";
iframeEl.style.display = "block";
});
Style.css:
@import url("https://fonts.googleapis.com/css2?family=Poppins:wght@900&display=swap");
* {
margin: 0px;
padding: 0px;
}
#app {
height: 100%;
width: 100%;
}
body {
background-color: #000000;
}
.header {
background-color: #191919;
display: flex;
width: 100%;
height: 64px;
}
ul {
display: flex;
flex-direction: row;
align-items: center;
}
li {
width: 45px;
height: 45px;
border-radius: 50%;
background-color: #000000;
color: #ffffff;
display: flex;
text-decoration: none;
align-items: center;
justify-content: center;
margin: 2px;
}
#app h1 {
font-family: "Poppins", sans-serif;
color: #ffffff;
font-size: clamp(3em, 3.25em, 3.5em);
}
#app h3 {
font-family: "Poppins", sans-serif;
color: #ffffff;
}
#app textarea {
width: 100%;
color: white;
background: black;
display: none;
}
#app iframe {
height: 100%;
width: 100%;
display: none;
}
Thanks!