Self is not defined (NextJS & Xterm)

배고픈 징징이 ㅣ 2024. 11. 6. 14:48

1. Error : Self is not defined

React에서 테스트할 때는 문제가 없었지만, NextJS에서는 에러가 발생하였다.
NextJS가 아직 그려지지 않은 페이지에 컴포넌트를 랜더링하려 하기에 발생한다.
하여 dynamic import 구문으로 Xterm에 지연 로드를 사용하면 해결할 수 있다.

 

2. Dynamic Import?

지연 로드.

모듈을 빌드타임이 아닌 런타임에 불러오도록 한다.

번들 파일을 분리하고 퍼포먼스 향상을 기대할 수 있다.

 

3. Solution Code

코드 수정을 한 파일은 총 두개이다.

page.tsx

import dynamic from "next/dynamic";

const WebTerminal = dynamic(
    async() => (await import("@/containers/terminal/WebTerminal")).WebTerminal,
    {ssr : false}
);

export default function TerminalSection() {
    return (
        <WebTerminal/>
    );
}

 

 

WebTerminal.tsx

"use client"

import { useEffect } from "react";

import SocketConfig from "@/containers/terminal/SocketConfig";
import "xterm/css/xterm.css";
import MyTerminal from "./MyTerminal";

export const WebTerminal = () => {
  ...

  return <div id="terminal" style={{height : "100vh", textAlign : "left"}} onContextMenu={clickRight} />;
};

 

xterm 구현에 관한 자세한 코드는 아래 포스팅에서 확인할 수 있다.

react에서 테스트로 작성한 코드이지만, 위 수정 사항과 같이 쓰면 금방 구현 할 수 있다.

 

WebTerminal

1. Web Terminal 이란?보통 Putty 혹은 MovaXTerm으로 SSH 연결을 할 것이다.특정 상황에서는 웹에서 SSH 연결이 된 것 처럼 보여줘야 할 때,웹상에서 터미널을 사용하게 해주는 것을 의미한다.라이브러리

pinokio5600.tistory.com

 

혹시 백엔드가 NestJS로 되어있다면, 아래 포스팅에서 NestJS로 Socket을 사용하는 법을 참고하여 개발하면 된다.

 

1. Screen Sharing - SocketIO Setting

1. 설명화면 공유 기술이 필요했다.처음에는 WebRTC를 사용하려 했지만, UDP를 사용하는 WebRTC의 특성상 TURN Server가 필요했다.이 프로젝트에서는 TURN Server를 제공할 여유가 없었다.그래서 TURN Server가

pinokio5600.tistory.com

 

설정을 다했으면, 아래 코드처럼 사용하면 된다.

import { MessageBody, OnGatewayConnection, OnGatewayDisconnect, OnGatewayInit, SubscribeMessage, WebSocketGateway, WebSocketServer } from "@nestjs/websockets";
import { Server } from "socket.io";
import { Client, ClientChannel } from "ssh2";

@WebSocketGateway()
export class TerminalGateway implements OnGatewayConnection, OnGatewayInit, OnGatewayDisconnect{
    @WebSocketServer() server : Server;
    stream : ClientChannel;

    afterInit(server : Server){
        console.log("afterInit", server , this.server);
    }

    handleConnection(client: any, ...args: any[]) {
        const ssh = new Client();

        ssh
            .on("ready", () => {
                ssh.shell((err, stream) => {
                    if(err) console.log("err : ", err);
                    this.stream = stream;
                    
                    stream
                        .on("data", (d : any) => {
                            this.server.emit('output', d.toString("binary"));
                        })
                        .on("close", () => {
                            ssh.end();
                        })
                    ;
                });
            })
            .connect({
                host : "비밀",
                port: 22,
                username: "비밀",
                password: "비밀"
            })
            .on("error", (e) => {
                console.log("error : ", e.message);
            })
        ;
    } 

    handleDisconnect(client: any) {
        console.log("disconnection");
    }

    @SubscribeMessage("input")
    handleMessage(@MessageBody() data){
        this.stream.write(data)
    }
}
반응형