Node.js
REPL

Node.js の REPL で、変数のバインドとHistoryの両立で快適になった

More than 1 year has passed since last update.

動機

Node.jsには node とターミナルで打ち込めばREPLを開始できる。

が、そこそこの規模のプロジェクトで、 rails c 感覚で使おうとすると、毎回モジュールの読み込みをするのが面倒。

Railsなら

$ rails c
pry > User.first.email
=> "hoge@example.com"

みたいになるのに、これを node でやろうとすると

$ node
> const User = require('./models').User
> User.findOne.then(user => console.log(user.get().email))
"hoge@example.com"

という具合になる。 require... を省きたい。

問題

Node.js にはREPLという機能があり、これを使えば実現できる。

bin/console
const replServer = require('repl').start('>>> ')
replServer.context.User = User

このようなファイルを作っておけば

$ bin/console
>>> User.findOne().then...

とできる。

https://nodejs.org/api/repl.html

ただ、ここで一つ問題がある。

REPLの履歴を呼び出せない。

普段、履歴に頼る生活をしているので、これは困る。

Node.jsのIssueにもなっているが、解決されていない。理由はちゃんと読んでいないので不明。

https://github.com/nodejs/node/issues/5730

解決策

下記のファイルを置いてあげれば、 rails c とほぼ同様の挙動ができる。

bin/console
#!/usr/bin/env node
const fs = require('fs')
const path = require('path')

const models = require('../api/models')
const User = models.User

const replServer = require('repl').start('>>> ')

replServer.context.User = User

const replHistoryPath = process.env.HOME + '/.node_repl_history'

fs.readFile(replHistoryPath, 'utf8', (err, data) =>
  data.split('\n').forEach(command =>
    replServer.history.push(command)
  )
)

replServer.on('exit', () => {
  fs.writeFile(replHistoryPath, replServer.history.join('\n'), err => {
    console.log(err)
    process.exit();
  })
});

// vim:set ft=js

肝心なのは replHistoryPath 以降で、起動時に読み出しと、終了時に書き出しを行っている。

これで開発が捗りそう。