tmytのらくがき

個人の日記レベルです

ブラウザでTerminal実装してみたら簡単だった

新年あけましておめでとうございます。本年もどうぞよろしくお願いいたします。

というわけで、Webブラウザで動くターミナルを実装してみたんです。NodeJSで。そしたらすごく簡単だった。って話です。

使うもの

  • express
  • pty.js
  • socket.io
  • xterm.js
  • pug-static

インストール

npmでてきとうにインストールします。

npm init
npm install --save express pty.js pug-static socket.io xterm

サーバ実装

適当にかきます。xterm.jsの中身をexpress.staticで公開しつつ、viewはpugで書きます。

ブラウザとの通信はSocket.IOを使って、ブラウザとターミナルの間をそれぞれ中継してあげます。

'use strict';

const express = require('express')
    , app = express()
    , server = require('http').createServer(app)
    , pugStatic = require('pug-static')
    , Io = require('socket.io')
    , pty = require('pty.js')

app.use('/xterm.js', express.static('node_modules/xterm'))
app.use('/', pugStatic('views'))

let io = new Io(server);
io.on('connect', socket => {
  let term = pty.spawn('bash', [], {
    name: 'xterm-256color',
    cols: 80,
    rows: 24
  });
  term.on('data', d => socket.emit('data', d));
  socket.on('data', d => term.write(d));
  socket.on('disconnect', () => term.destroy());
});

server.listen(3000);

クライアント実装

こっちもてきとうに。これは、index.pugという名前でviewsディレクトリの中に保存して使います。

サーバ実装と同様に、Socket.IOでブラウザへの入出力を中継してあげます。

doctype html
html
  head
    link(rel='stylesheet', href='/xterm.js/dist/xterm.css')
  body
    #terminal
    script(src='/xterm.js/dist/xterm.js')
    script(src='/socket.io/socket.io.js')
    script.
      var term = new Terminal();
      var socket = io();
      term.open(document.getElementById('terminal'));
      term.on('data', d => socket.emit('data', d));
      socket.on('data', d => term.write(d));

おわり

あとはアクセスすると、bashが見れて、そのまま使えます。xterm.jsすごくって、vimとかtmuxとかちゃんと使えます。

ただ、この実装にユーザ認証が含まれていないので必ずユーザ認証して使ってください。