웹 기반 터미널을 만드는 방법
33134 단어 tutorialjavascriptwebdev
이 문서에서는 웹 기술을 사용하여 터미널을 구축하고 브라우저에서 사용하는 방법에 대한 기본적인 세부 정보를 제공합니다. 동일한 기술이 VSCode 내장 터미널 및 Hyper과 같은 터미널 앱을 만드는 데 사용됩니다.
우리는 서버와 클라이언트를 모두 만들어야 합니다. 그리고 Socket.IO을 사용하여 데이터를 주고 받을 예정입니다. 전자에 이것이 필요하면 socket.io 필요하지 않습니다. 글 말미에 전자 관련 정보를 확인해주세요.
우리가 사용할 주요 라이브러리:
고객 입장에서
Socket.io 클라이언트
xterm.js - 터미널용 UI
서버 측
Socket.io 서버
node-pty - 유사 터미널을 생성합니다. 이에 대한 입력을 보내야 합니다. pseudoterminals에 대한 자세한 정보가 필요하면 this을 확인하십시오.
클라이언트와 서버 모두에 대해 실행 중인 앱은 다음 코드 및 상자 링크에서 사용할 수 있습니다. 작동하지 않는 경우 링크를 열고 앱이 Codesandbox에 의해 최대 절전 모드인 경우 깨우기 위해 빠르게 새로 고침하십시오.
사용 가능한 코드는 Github에서 사용할 수 있습니다.
서버 생성
먼저 기본적인 설정을 해봅시다. NodeJS
http
모듈에서 서버를 생성하여 socket.io 서버에 전달합니다.//index.js
const http = require("http");
const SocketService = require("./SocketService");
/*
Create Server from http module.
If you use other packages like express, use something like,
const app = require("express")();
const server = require("http").Server(app);
*/
const server = http.createServer((req, res) => {
res.write("Terminal Server Running.");
res.end();
});
const port = 8080;
server.listen(port, function() {
console.log("Server listening on : ", port);
const socketService = new SocketService();
// We are going to pass server to socket.io in SocketService.js
socketService.attachServer(server);
});
다음으로 socket.io 이벤트에 대한 이벤트 리스너를 추가할 래퍼 클래스를 만들어야 합니다.
//SocketService.js
const socketIO = require("socket.io");
const PTYService = require("./PTYService");
class SocketService {
constructor() {
this.socket = null;
this.pty = null;
}
attachServer(server) {
if (!server) {
throw new Error("Server not found...");
}
const io = socketIO(server);
console.log("Created socket server. Waiting for client connection.");
// "connection" event happens when any client connects to this io instance.
io.on("connection", socket => {
console.log("Client connect to socket.", socket.id);
this.socket = socket;
this.socket.on("disconnect", () => {
console.log("Disconnected Socket: ", socket.id);
});
// Create a new pty service when client connects.
this.pty = new PTYService(this.socket);
// Attach event listener for socket.io
this.socket.on("input", input => {
// Runs this listener when socket receives "input" events from socket.io client.
// input event is emitted on client side when user types in terminal UI
this.pty.write(input);
});
});
}
}
module.exports = SocketService;
마지막으로 서버 측에서
node-pty
를 사용하여 의사 터미널 프로세스를 생성해 보겠습니다. 입력한 입력은 node-pty
의 인스턴스로 전달되고 출력은 연결된 socket.io 클라이언트로 전송됩니다. 나중에 socket.io 클라이언트를 추가할 예정입니다.// PTYService.js
const os = require("os");
const pty = require("node-pty");
class PTY {
constructor(socket) {
// Setting default terminals based on user os
this.shell = os.platform() === "win32" ? "powershell.exe" : "bash";
this.ptyProcess = null;
this.socket = socket;
// Initialize PTY process.
this.startPtyProcess();
}
/**
* Spawn an instance of pty with a selected shell.
*/
startPtyProcess() {
this.ptyProcess = pty.spawn(this.shell, [], {
name: "xterm-color",
cwd: process.env.HOME, // Which path should terminal start
env: process.env // Pass environment variables
});
// Add a "data" event listener.
this.ptyProcess.on("data", data => {
// Whenever terminal generates any data, send that output to socket.io client
this.sendToClient(data);
});
}
/**
* Use this function to send in the input to Pseudo Terminal process.
* @param {*} data Input from user like a command sent from terminal UI
*/
write(data) {
this.ptyProcess.write(data);
}
sendToClient(data) {
// Emit data to socket.io client in an event "output"
this.socket.emit("output", data);
}
}
module.exports = PTY;
클라이언트 생성
이제 UI가 나옵니다. 매우 간단합니다. 지금 해야 할 일은
xterm
로 터미널을 만들고 이를 dom의 컨테이너에 연결하는 것입니다. 그런 다음 터미널의 입력을 연결된 socket.io의 서버로 전달합니다. 또한 socket.io 서버에서 xtermjs 터미널로 응답을 작성하는 이벤트 리스너를 socket.io-client에 추가할 예정입니다.html 페이지에서 xtermjs가 터미널을 연결할 위치
div
를 만듭니다.<!DOCTYPE html>
<html>
<head>
<title>Terminal in Browser</title>
<meta charset="UTF-8" />
</head>
<body>
<div id="terminal-container"></div>
<script src="src/index.js"></script>
</body>
</html>
socket.io 클라이언트를 시작하기 전에 xtermjs 관련 함수와 socket.io-client에 필요한 이벤트 리스너를 포함하는 래퍼 클래스를 생성해 보겠습니다.
// TerminalUI.js
// You will need a bundler like webpack or parcel to use these imports.
// The example in codesandboxes and github uses parcel.
import { Terminal } from "xterm";
import "xterm/css/xterm.css"; // DO NOT forget importing xterm.css
export class TerminalUI {
constructor(socket) {
this.terminal = new Terminal();
/* You can make your terminals colorful :) */
this.terminal.setOption("theme", {
background: "#202B33",
foreground: "#F5F8FA"
});
this.socket = socket;
}
/**
* Attach event listeners for terminal UI and socket.io client
*/
startListening() {
this.terminal.onData(data => this.sendInput(data));
this.socket.on("output", data => {
// When there is data from PTY on server, print that on Terminal.
this.write(data);
});
}
/**
* Print something to terminal UI.
*/
write(text) {
this.terminal.write(text);
}
/**
* Utility function to print new line on terminal.
*/
prompt() {
this.terminal.write(`\\r\\n$ `);
}
/**
* Send whatever you type in Terminal UI to PTY process in server.
* @param {*} input Input to send to server
*/
sendInput(input) {
this.socket.emit("input", input);
}
/**
*
* container is a HTMLElement where xterm can attach terminal ui instance.
* div#terminal-container in this example.
*/
attachTo(container) {
this.terminal.open(container);
// Default text to display on terminal.
this.terminal.write("Terminal Connected");
this.terminal.write("");
this.prompt();
}
clear() {
this.terminal.clear();
}
}
xtermjs는 모든 종류의 멋진 기능을 지원합니다. 터미널용 테마를 만들 수 있고 다른 기능에 애드온을 사용할 수 있습니다. 자세한 내용은 xtermjs github repo을 확인하십시오. 이 예에서 더 많은 사용자 지정 권한을 원하는 경우 위의
TerminalUI.js
파일을 업데이트하고 this.terminal
개체를 사용자 지정할 수 있습니다. 예를 들어 기본 어두운 테마 옵션이 여기에 추가되었습니다.마지막으로 서버에서 node-pty 프로세스의 이벤트를 송수신하도록 클라이언트socket.io를 초기화해야 합니다.
// index.js
import { TerminalUI } from "./TerminalUI";
import io from "socket.io-client";
// IMPORTANT: Make sure you replace this address with your server address.
const serverAddress = "http://localhost:8080";
function connectToSocket(serverAddress) {
return new Promise(res => {
const socket = io(serverAddress);
res(socket);
});
}
function startTerminal(container, socket) {
// Create an xterm.js instance.
const terminal = new TerminalUI(socket);
// Attach created terminal to a DOM element.
terminal.attachTo(container);
// When terminal attached to DOM, start listening for input, output events.
// Check TerminalUI startListening() function for details.
terminal.startListening();
}
function start() {
const container = document.getElementById("terminal-container");
// Connect to socket and when it is available, start terminal.
connectToSocket(serverAddress).then(socket => {
startTerminal(container, socket);
});
}
// Better to start on DOMContentLoaded. So, we know terminal-container is loaded
start();
서버와 클라이언트가 모두 실행 중이면 브라우저에 터미널이 표시됩니다. 높이, 너비와 같은 다른 스타일 사용자 정의에 대해서는 xtermjs 문서를 확인하십시오.
전자 사용자의 경우
Electron에서는 xtermjs와 node-pty를 사용하는 것이 훨씬 더 간단합니다. 렌더러 프로세스는 노드 모듈을 실행할 수 있으므로 소켓 라이브러리를 사용하지 않고 xtermjs와 node-pty 간에 직접 데이터를 생성하고 전달할 수 있습니다. 간단한 예는 다음과 같습니다.
// In electronjs renderer process
// Make sure nodeIntegration is enabled in your BrowserWindow.
// Check github repo for full example (link given at the beginning of this article).
// Choose shell based on os
const shell = os.platform() === "win32" ? "powershell.exe" : "bash";
// Start PTY process
const ptyProcess = pty.spawn(shell, [], {
name: "xterm-color",
cwd: process.env.HOME, // Which path should terminal start
env: process.env // Pass environment variables
});
// Create and attach xtermjs terminal on DOM
const terminal = new Terminal();
terminal.open(document.getElementById("terminal-container"));
// Add event listeners for pty process and terminal
// we don't need to use any socket to communicate between xterm/node-pty
ptyProcess.on("data", function(data) {
terminal.write(data);
});
terminal.onData(data => ptyProcess.write(data));
작동하는 전자 예제가 Github 저장소에 추가되었습니다.
기타 정보
NodeJS의 출력만 인쇄하는 터미널 UI만 필요한 경우
child_process
node-pty가 필요하지 않습니다. child_process
stdout을 xtermjs UI로 직접 보낼 수 있습니다.내 오픈 소스 프로젝트https://github.com/saisandeepvaddi/ten-hands 중 하나가 이 방식으로 작동합니다. Ten Hands을 확인하여
xtermjs
, socket.io
및 ReactJS
를 함께 사용하여 터미널 기반 앱을 빌드하는 방법을 자세히 알아보세요.감사합니다 🙏
Reference
이 문제에 관하여(웹 기반 터미널을 만드는 방법), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/saisandeepvaddi/how-to-create-web-based-terminals-38d텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)