webTerminal.js 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. export default async function initWebTerminal() {
  2. const container = document.querySelector('.js-web-terminal');
  3. if (!container) {
  4. return;
  5. }
  6. const Terminal = await loadXterm();
  7. const terminal = new Terminal();
  8. let Addon = null;
  9. if (typeof WebGL2RenderingContext !== 'undefined') {
  10. Addon = await loadWebGLAddon();
  11. } else {
  12. Addon = await loadCanvasAddon();
  13. }
  14. terminal.loadAddon(new Addon());
  15. terminal.open(container);
  16. const socket = new WebSocket(`wss://${window.location.host}/_shell/`);
  17. socket.addEventListener('open', (_) => {
  18. terminal.onData((data) => socket.send(data));
  19. socket.addEventListener('message', (evt) => terminal.write(evt.data));
  20. });
  21. socket.addEventListener('error', (_) => {
  22. terminal.reset();
  23. terminal.writeln('Connection error.');
  24. });
  25. socket.addEventListener('close', (evt) => {
  26. if (evt.wasClean) {
  27. terminal.reset();
  28. terminal.writeln(evt.reason ?? 'Connection closed.');
  29. }
  30. });
  31. }
  32. /** @returns {Promise<typeof import("xterm").Terminal>} */
  33. async function loadXterm() {
  34. // NOTE: String expression used to prevent ESBuild from resolving
  35. // the import on build (xterm is a separate bundle)
  36. const xtermBundlePath = '/js/dist/xterm.min.js';
  37. const xtermModule = await import(`${xtermBundlePath}`);
  38. return xtermModule.default.Terminal;
  39. }
  40. /** @returns {Promise<typeof import("xterm-addon-webgl").WebglAddon>} */
  41. async function loadWebGLAddon() {
  42. // NOTE: String expression used to prevent ESBuild from resolving
  43. // the import on build (xterm-addon-webgl is a separate bundle)
  44. const xtermBundlePath = '/js/dist/xterm-addon-webgl.min.js';
  45. const xtermModule = await import(`${xtermBundlePath}`);
  46. return xtermModule.default.WebglAddon;
  47. }
  48. /** @returns {Promise<typeof import("xterm-addon-canvas").CanvasAddon>} */
  49. async function loadCanvasAddon() {
  50. // NOTE: String expression used to prevent ESBuild from resolving
  51. // the import on build (xterm-addon-canvas is a separate bundle)
  52. const xtermBundlePath = '/js/dist/xterm-addon-canvas.min.js';
  53. const xtermModule = await import(`${xtermBundlePath}`);
  54. return xtermModule.default.CanvasAddon;
  55. }