xtermjs / xterm.js

A terminal for the web
https://xtermjs.org/
MIT License
17.52k stars 1.62k forks source link

Unexpected issue regarding `addon-fit` when used in React #5016

Closed brandonmcconnell closed 6 months ago

brandonmcconnell commented 6 months ago

I have a minimal reproduction here, where you can see some issues in the console and client that appear, apparently related to the usage of addon-fit. https://stackblitz.com/edit/stackblitz-starters-6ssv2a?file=app%2Fcomponents%2FXTerm.tsx

Do you have any idea what I could be doing wrong in my wrapper component? It's a very thin wrapper, so I feel the issue is probably related to my usage of XTerm and not React-specific.

The component source and errors are below:

Component source

app/components/XTerm.tsx

'use client';

import React, { useEffect, useRef } from 'react';
import '@xterm/xterm/css/xterm.css';

// Import addons

// https://github.com/xtermjs/xterm.js
import { Terminal } from '@xterm/xterm';
// https://github.com/xtermjs/xterm.js/tree/master/addons/addon-fit
import { FitAddon } from '@xterm/addon-fit';
// https://github.com/xtermjs/xterm.js/tree/master/addons/addon-web-links
import { SearchAddon } from '@xterm/addon-search';
// https://github.com/xtermjs/xterm.js/tree/master/addons/addon-image
import { WebLinksAddon } from '@xterm/addon-web-links';
// https://github.com/xtermjs/xterm.js/tree/master/addons/addon-search
import { ImageAddon } from '@xterm/addon-image';

const XTerm = () => {
  const terminalRef = useRef(null);
  const terminal = useRef(new Terminal());

  useEffect(() => {
    // ComponentDidMount
    if (terminalRef.current) {
      const fitAddon = new FitAddon();
      const searchAddon = new SearchAddon();
      const webLinksAddon = new WebLinksAddon();
      const imageAddon = new ImageAddon({ pixelLimit: 16777216 });

      // Set up addons
      terminal.current.loadAddon(fitAddon);
      terminal.current.loadAddon(searchAddon);
      terminal.current.loadAddon(webLinksAddon);
      terminal.current.loadAddon(imageAddon);

      // Attach the terminal to the div
      terminal.current.open(terminalRef.current);
      fitAddon.fit();
      // Example output
      terminal.current.writeln('Hello world');
    }

    // ComponentWillUnmount
    return () => terminal.current.dispose(); // Cleanup

    // Empty dependency array, to only run on mount and cleanup on unmount
  }, []);

  return <div ref={terminalRef} style={{ height: '300px', width: '600px' }} />;
};

export default XTerm;

app/page.tsx

import XTerm from './components/XTerm';

export default function Home() {
  return (
    <main className="flex min-h-screen flex-col items-center justify-between p-24">
      <XTerm />
    </main>
  );
}

Errors

In the terminal:

 X node_modules/@xterm/addon-fit/lib/addon-fit.js (1:196) @ eval
 X ReferenceError: self is not defined
    at __webpack_require__ (/home/projects/stackblitz-starters-6ssv2a/.next/server/webpack-runtime.js:33:42)
    at eval (./app/components/XTerm.tsx:12:74)
    at (ssr)/./app/components/XTerm.tsx (/home/projects/stackblitz-starters-6ssv2a/.next/server/app/page.js:151:1)
    at __webpack_require__ (/home/projects/stackblitz-starters-6ssv2a/.next/server/webpack-runtime.js:33:42)

In the client:

Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'dimensions')

Call Stack
get dimensions
node_modules/@xterm/xterm/lib/xterm.js (1:108798)
t.Viewport.syncScrollArea
node_modules/@xterm/xterm/lib/xterm.js (1:50747)
eval
node_modules/@xterm/xterm/lib/xterm.js (1:48246)