Posted at

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 以降で、起動時に読み出しと、終了時に書き出しを行っている。

これで開発が捗りそう。