ハイパーマッスルエンジニアになりたい

Vim、ShellScriptについてよく書く

ブラウザからTemrinalに接続するxterm.jsをNext.jsとNestJSで構築する

f:id:rasukarusan:20210501125947p:plain

xterm.jsが楽しそう

ブラウザにTerminalを設置できるxterm.jsというライブラリがある。VSCodeのTerminalやHyperなどに使われている。
xterm.jsが提供するのはざっくり言ってしまえばTerminalの形をしたテキストフィールドのみ。実際にTerminalに接続したりキーボードの入力を送信したりする処理は自分で書く必要がある。

github.com

xterm.jsを触ってみた

xterm.jsを組み込むフロントエンドにNext.js、xtermとやりとりするためのサーバーサイドをNestJSを使って書いてみた。

ブラウザから自分のTemrinalに接続

github.com

vimとtmuxの挙動が若干怪しいが、いちおう接続するところまではいけたので満足。

以下メモ

xterm.jsの流れ

f:id:rasukarusan:20210501124756p:plain
 

ReferenceError: self is not definedが出る

nextjsのSSRを用いているから出るエラーだった。試しにcreate-react-appでやったらエラーは出なかった。 - reactjs - (Webpack) Why am I getting ReferenceError: self is not defined in Next.js when I try to import a client-side library? - Stack Overflow 完璧な回答がここにあった。 - Xterm.Js not work in with NextJs | React app work fine · Discussion #22409 · vercel/next.js

dynamic importで解決。ReactHooksコンポーネントの場合、then(mod)が必要。

const Terminal = dynamic(
  () => import('@/components/terminal').then((mod) => mod.TerminalComponent),
  {
    ssr: false,
  }
)
const Index: React.FC = () => {
  const classes = useStyles()
  return (
    <Layout>
      <div className={classes.container}>
        <Terminal />
      </div>
    </Layout>
  )
}

document.getElementByIdをReactHooksでする

デモだとindex.htmlに

と書いてあって、tsファイル内でterm.open(document.getElementById('terminal'))をする形がだったが、 ReactHooksだとindex.htmlがないからどうしたらいいのかわからなかった。

import React, { useEffect } from 'react'
import { Terminal } from 'xterm'

export const TerminalComponent = () => {
  const term = new Terminal()
  useEffect(() => {
    term.open(document.getElementById('terminal'))
  })
  return <div id="terminal" />
}

useRefをつかってもできる

import React, { useEffect } from 'react'
import { Terminal } from 'xterm'

export const TerminalComponent = () => {
  const ref = React.useRef<HTMLDivElement>()
  const term = new Terminal()
  useEffect(() => {
    term.open(ref.current)
  })
  return <div ref={ref}></div>
}

複数のTerminalを置くとき、cssが効かない

Propsでidを渡すようにしたら解決した。document.getElementById("terminal")でやっていたため、2つ目のTerminalが1つ目に奪われてしまっている状態であった。なのでPropsでidを渡すようにして、document.getElementById(id)としたらいけた。

nestjsでサーバーを構築

$ yarn global add @nestjs/cli
$ yarn global add @nestjs/schematics
$ nest new server

Error: Collection "@nestjs/schematics" cannot be resolved.が出る。yarn global add @nestjs/schematicsが必要。 - node.js - NestJS cli error: Collection "@nestjs/schematics" cannot be resolved - Stack Overflow

node-configでTypeError: Cannot read property 'get' of undefinedがでる

importの仕方を変えたら解決した。 - javascript - node-config Config is undefined in typescript jest context? - Stack Overflow