Skip to content
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

Unable to tearDown and ReBoot webcontainer on page change #1178

Open
1 task done
pratham15541 opened this issue Sep 12, 2023 · 5 comments
Open
1 task done

Unable to tearDown and ReBoot webcontainer on page change #1178

pratham15541 opened this issue Sep 12, 2023 · 5 comments

Comments

@pratham15541
Copy link

pratham15541 commented Sep 12, 2023

Describe the bug

GITHUB LINK: https://github.com/pratham15541/webcontainer-trial-react

i am trying to teardown webcontainer and once again boot in react app
but it shows error:
/docs
Webcontainer.jsx:98 null
Webcontainer.jsx:59 Booting WebContainer...
Webcontainer.jsx:75 WebContainer booted successfully!
/docs
Webcontainer.jsx:98 {"_instance":{},"_runtimeInfo":{"path":"/bin:/usr/bin:/usr/local/bin","cwd":"/home/httplocalhost5173-b5wu"},"_iframe":{},"fs":{"_fs":{}}}
Webcontainer.jsx:101 Stopping WebContainer...
Webcontainer.jsx:104 WebContainer stopped
Webcontainer.jsx:59 Booting WebContainer...
Webcontainer.jsx:93

Error booting WebContainer: Error: WebContainer already booted
at WebContainer.boot (index.js:140:19)
at initializeComponents (Webcontainer.jsx:60:47)
at Webcontainer.jsx:150:7

Link to the blitz that caused the error

https://stackblitz.com/~/github.com/pratham15541/webcontainer-trial-react

Steps to reproduce

code:

import React, { useEffect } from "react";
import { WebContainer } from "@webcontainer/api";
import { expressFiles } from "../files/express";
import { Terminal } from "xterm";
import { FitAddon } from "xterm-addon-fit";
import "xterm/css/xterm.css";
import { useLocation } from "react-router-dom";

// Declare variables for DOM elements and WebContainer instance
let webcontainerInstance = null;
let terminalEl = null;
let iframeEl = null;
let editorEl = null;
let shellProcess = null;
let terminal = null;
let fitAddon = null;
let initialized = false;

// Function to check if DOM elements are ready
function areDOMElementsReady() {
  return iframeEl && editorEl && terminalEl;
}

async function createTerminal(terminalEl) {
  fitAddon = new FitAddon();
  const terminal = new Terminal({
    // cursorBlink: true,
    convertEol: true,
  });
  terminal.loadAddon(fitAddon);
  terminal.open(terminalEl);

  // Return a promise that resolves when the terminal is ready
  await new Promise((resolve) => {
    terminal.onRender(() => {
      fitAddon.fit(); // Call fitAddon.fit() when the terminal is ready
      resolve(terminal);
    });
  });

  return terminal;
}

// Function to initialize the components
async function initializeComponents() {
  try {
    // Get DOM elements
    iframeEl = document.getElementById("iframeEl");
    editorEl = document.getElementById("editor");
    terminalEl = document.getElementById("terminalEl");

    // Check if any of the elements are null
    if (!areDOMElementsReady()) {
      console.log("One or more elements are null. Retrying in 2 seconds...");
      setTimeout(initializeComponents, 2000); // Retry after 2 seconds
      return;
    }

    console.log("Booting WebContainer...");
    webcontainerInstance = await WebContainer.boot();
    await webcontainerInstance.mount(expressFiles);

    // When the server is ready, set the iframe's src
    webcontainerInstance.on("server-ready", (port, url) => {
      iframeEl.src = url;
      // console.log(url)
    });

    webcontainerInstance.on("port", async (port, type, url) => {
      if (type === "close") {
        iframeEl.src = "./serverOpenClose.html";
      }
    });

    console.log("WebContainer booted successfully!");

    // Create a terminal
    terminal = await createTerminal(terminalEl);

    await startShell(terminal);

    // Resize the terminal when the window is resized
    window.addEventListener("resize", () => {
      fitAddon.fit();
      shellProcess.resize({
        cols: terminal.cols,
        rows: terminal.rows,
      });
    });

    initialized = true;
  } catch (error) {
    console.error("Error booting WebContainer:", error);
  }
}

async function stopWebContainer() {
  console.log(JSON.stringify(webcontainerInstance)); // Log the instance before teardown
  if (webcontainerInstance !== null) {
    try {
      console.log("Stopping WebContainer...");

      await webcontainerInstance.teardown();
      console.log("WebContainer stopped"); // Log after teardown
      webcontainerInstance = null;
    } catch (error) {
      console.error("Error stopping WebContainer", error);
    }
  }
}

async function startShell(terminal) {
  try {
    shellProcess = await webcontainerInstance.spawn("jsh", {
      terminal: {
        cols: terminal.cols,
        rows: terminal.rows,
      },
    });

    shellProcess.output.pipeTo(
      new WritableStream({
        write(data) {
          terminal.write(data);
        },
      })
    );

    const input = shellProcess.input.getWriter();

    terminal.onData((data) => {
      input.write(data);
    });

    return shellProcess;
  } catch (error) {
    console.error("Error starting shell:", error);
    // return null; // Handle the error gracefully, you can return null or another value
  }
}

// Wait for the DOM to load and then initialize components

const Webcontainer = () => {
  const location = useLocation();

  useEffect(() => {
    if (location.pathname === "/playground") {
      // console.log(location.pathname);
      initializeComponents();
    } else {
      console.log(location.pathname);
      stopWebContainer();
    }
  }, [location]);

  return <></>;
};

export default Webcontainer;

Expected behavior

i think it should destroy and again start new webcontainer Instance..

Parity with Local

Screenshots

No response

Platform

  • OS: [ Windows]
  • Browser: [ Chrome]

Additional context

No response

@kirjavascript
Copy link
Member

hi 👋 thanks for reporting this issue!

I pulled the code and started the app, but wasn't sure exactly how the error should be trigger.

Can you list the steps you take to reproduce this issue?

@pratham15541
Copy link
Author

pratham15541 commented Sep 13, 2023

if you run it locally
and install app and start dev server

then it shows the four routes
like /docs , /playground, in navbar

when i switch to /playground it boots webcontainer successfully
and on change page to other url i am calling function for teardown webcontainer

and when user gets back again /playground then it shows error webcontainer already booted!

@pratham15541
Copy link
Author

pratham15541 commented Sep 15, 2023

@kirjavascript no reply since 2 days

@kirjavascript
Copy link
Member

Thanks for the reproduction notes, We've been trying to debug this issue but haven't got to the bottom of it yet.

Once the issue if figured out we will post an update here!

@pratham15541
Copy link
Author

pratham15541 commented Sep 28, 2023

any updates @kirjavascript ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants