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
BASHcd 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.js
의 document를 참고하면 자신의 입맛에 맞게 커스텀을 할 수 있으니 한 번 문서를 둘러보는것도 좋을 것 같습니다. 🤗 😆
- 웹 터미널 클래스화 작업
- 키보드 처리 추가(위, 오른쪽, 아래, 왼쪽, enter, backspace)
- 웹 터미널 해상도를 맞추기 위한 fit addon 추가
이로써 기본적인 틀을 갖춘 웹 터미널이 완성되었습니다. 하지만 앞서 말했듯이 터미널의 ‘껍데기’로 bash
나 cmd
와 같이 명령어를 해석할 수 있는 것이 아닌 그저 텍스트를 띄워서 보여주기만 할 뿐입니다. 진정한 웹 터미널을 만들기 위해 저희는 백엔드 부분 또한 만질 겁니다. 다음 편에는 node-pty
모듈을 이용하여 pty
를 생성하고 진정한 의미의 웹 터미널을 만들어 볼 예정입니다.
웹 터미널 프론트엔드 코드는 아래의 GitHub에서 확인할 수 있습니다.
참고 사이트들