• logo

      SeolMyeongTang

  • xterm.js과 node-pty로 웹 터미널을 만들어보겠습니다. 근데 이제 rollup을 곁들인 - 프론트엔드편

    2022년 10월 17일

    이전 글에 이어서 이번 시간에는 xterm.js, node-pty를 활용하여 웹 터미널을 만들어 보도록 하겠습니다. 웹 터미널을 구현하기 위해 크게 프론트엔드, 백엔드, 서버 이렇게 3개의 파트가 준비되어야합니다. 프론트엔드는 React, 백엔드는 NodeJS를 활용하고 언어는 TypeScript로 작성하였습니다. 먼저, 프론트엔드 파트부터 천천히 살펴보겠습니다.

    웹 터미널 구현을 위해 첫 번째로 할 일은 React 프레임워크를 가지고 xterm.js 모듈로 웹 터미널의 껍데기를 만들겁니다. 웹 터미널 라이브러리화도 고려할 것이므로 초기에 이것저것 설정해야할 것이 있습니다. 기본적인 prettier, eslint, tsconfig 설정을 더불어 라이브러리 개발 환경을 위해 rollup 모듈을 사용합니다. rollup 모듈에 대해서 알고 싶다면 이 글을 추천드립니다. React 개발 환경에서 lib 디렉터리를 만들어 이 곳에서는 웹 터미널 라이브러리를 코드를 작성하도록 합니다. 그리고 npm link로 웹 터미널 라이브러리 링크를 만들어 쉽게 라이브러리 개발을 할 수 있도록 설정합니다.

    BASH
    ├── frontend # 최상단 디렉터리
    │   ├── lib # 웹 터미널 라이브러리 코드
    │   │   ├── dist
    │   │   ├── package.json
    │   │   ├── rollup.config.js
    │   │   ├── src
    │   │   ├── tsconfig.json
    │   ├── node_modules # lib 디렉터리 npm link로 연결
    │   ├── package.json
    │   ├── public
    │   ├── src # 웹 터미널 모듈을 가져다 쓸 React 코드
    │   └── tsconfig.json
    
    BASH
    cd frontend/lib
    npm link
    
    cd ..
    npm link webterminal
    
    • 모듈 링크 성공 예시
    모듈 링크 성공 예시

    위 그림과 같이 frontend/node_modules 디렉터리 안에 이러한 모듈이 있으면 링크 생성이 된 겁니다.

    React 코드를 수정하면 hot reload가 되어 브라우저에 바로 반영이 되고, 웹 터미널 라이브러리 코드를 수정하면 라이브러리가 자동 빌드가 되도록 package.json에 다음과 같이 스크립트를 작성하고 실행하면 더욱 빠르게 개발을 진행 할 수 있습니다.

    JSON
    ...
    "scripts": {
        "dev": "yarn dev:lib & yarn start",
        "dev:lib": "cd lib && yarn watch",
        "start": "react-scripts start"
    },
    ...
    

    개발 환경 설정을 하였으니 간단하게 코드를 작성해봅시다. lib 디렉터리로 이동하여 xterm.js 모듈로 웹 터미널 껍데기를 만듭시다.

    TYPESCRIPT
    // lib/src/WebTerminal/WebTerminal.tsx
    
    import React, { useEffect } from "react";
    import { Terminal } from "xterm";
    
    import "xterm/css/xterm.css";
    
    const WebTerminal = () => {
      useEffect(() => {
        const terminal = new Terminal();
    
        terminal.open(document.getElementById("terminal") as HTMLElement);
        terminal.write("Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ");
      }, []);
    
      return <div id="terminal" />;
    };
    
    export default WebTerminal;
    

    React 쪽 코드는 다음과 같이 작성하고 yarn start으로 실행하면 브라우저에 웹 터미널을 볼 수 있습니다.

    TYPESCRIPT
    // src/App.tsx
    
    import React from "react";
    import WebTerminal from "WebTerminal";
    
    import "../lib/node_modules/xterm/css/xterm.css";
    
    const App = () => {
      return (
        <div className="App">
          <WebTerminal />
        </div>
      );
    };
    
    export default App;
    

    축하드립니다. 웹 터미널을 만들었습니다. 👏👏👏

    나의 소중한 웹 터미널
    나의 소중한 웹 터미널

    하지만 이 웹 터미널은 그저 ‘껍데기’로, 이 상태로는 키보드 입력조차 받을 수 없는 무능한 터미널입니다. 키보드 입력을 받기 위해 웹 터미널 라이브러리 코드를 수정해봅시다.

    TYPESCRIPT
    // lib/src/WebTerminal/WebTerminal.tsx
    
    import React, { useEffect } from 'react';
    import { Terminal } from 'xterm';
    
    import 'xterm/css/xterm.css';
    
    const WebTerminal = () => {
        useEffect(() => {
            const terminal = new Terminal();
    
            terminal.open(document.getElementById('terminal') as HTMLElement);
    
            ***terminal.onData((e) => {
                terminal.write(e);
            });***
    
            terminal.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ');
        }, []);
    
        return <div id="terminal" />;
    };
    
    export default WebTerminal;
    

    이런 식으로 기능을 하나씩 추가시켜 기본적인 웹 터미널을 만들겠습니다. 기본적인 웹 터미널 기능을 위해 다음과 같은 작업을 수행했습니다. xterm.jsdocument를 참고하면 자신의 입맛에 맞게 커스텀을 할 수 있으니 한 번 문서를 둘러보는것도 좋을 것 같습니다. 🤗 😆

    • 웹 터미널 클래스화 작업
    • 키보드 처리 추가(위, 오른쪽, 아래, 왼쪽, enter, backspace)
    • 웹 터미널 해상도를 맞추기 위한 fit addon 추가

    이로써 기본적인 틀을 갖춘 웹 터미널이 완성되었습니다. 하지만 앞서 말했듯이 터미널의 ‘껍데기’로 bashcmd와 같이 명령어를 해석할 수 있는 것이 아닌 그저 텍스트를 띄워서 보여주기만 할 뿐입니다. 진정한 웹 터미널을 만들기 위해 저희는 백엔드 부분 또한 만질 겁니다. 다음 편에는 node-pty 모듈을 이용하여 pty를 생성하고 진정한 의미의 웹 터미널을 만들어 볼 예정입니다.

    웹 터미널 프론트엔드 코드는 아래의 GitHub에서 확인할 수 있습니다.

    WebTerminal Github

    참고 사이트들