REPL stands for read-eval-print-loop, or just an interactive session (usually in your terminal), where you can enter some expression and immediately evaluate it, seeing the result. After evaluating, the whole flow repeats, and it works until you exit the process. So, R
stands for reading your command, E
stands for evaluating it, P
stands for printing the result of the execution, and L
means to run the whole process again, “in the loop”.
In order to run Node.js REPL, you need to run the node
command without any arguments:
1
> node
REPL session is similar to the console window in the browser – you can create and store variables, declare functions, require modules and installed dependencies (check module object). However, one important difference between executing a file and working in a REPL session is that a REPL session is not wrapped into the function, so you don’t have __dirname and __filename variables. So, you can require any files as you would do in any existing commonjs file. To illustrate, let’s create a new file where we export some string, and require it from the REPL:
1
2
3
4
5
6
7
> touch example.js
> echo "exports.some = 'some text';" >> example.js
> node
> require('./example');
{ some: 'some text' }
> _.some
'some text'
I did not assign the result of the require
expression, but I was able to access it anyway! I got the last expression’s result by using underscore variable – Node.js REPL automatically assigns the last expression’s result to _
variable. It is interesting, that despite being a popular choice for lodash, you can’t assign to this variable. It will save the value, but after the next expression it will be different:
1
2
3
4
5
6
7
8
9
10
> node
> _ = 'something'
Expression assignment to _ now disabled.
'something'
> _
'something'
> _ = 'something else'
'something else'
> _
'something else'
Node.js REPL has special commands, even though I feel they are not so widely known. First, let’s look at the multiline command. By default, every line is evaluated after you type it and hit “Enter”: there is no way in JavaScript to tell when we need to continue or can evaluate our code (like it is done in Python REPL, for example). Because of that it is challenging to write functions, since it is very unreadable and very error-prone to type all in one line. However, there is an .editor command, which allows you to type as many lines as you need:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> node
> .editor
// Entering editor mode (^D to finish, ^C to cancel)
function sum(a, b) {
return a + b;
}
sum(5, 4);
// I type ^D at this point
9
> sum(10, 6)
16
Other special commands (from the official docs):
.break
- When in the process of inputting a multi-line expression, entering the .break command (or pressing the <ctrl>-C
key combination) will abort further input or processing of that expression..clear
- Resets the REPL context to an empty object and clears any multi-line expression currently being input..exit
- Close the I/O stream, causing the REPL to exit..help
- Show this list of special commands..save
- Save the current REPL session to a file: > .save ./file/to/save.js
.load
- Load a file into the current REPL session. > .load ./file/to/load.js
.editor
- Enter editor mode (<ctrl>-D
to finish, <ctrl>-C
to cancel).If you hit the TAB key twice, it will give you all possible autocompletions (also, if you already typed something, and there is only one option, it will do it automatically). We can use it to check what is available globally (keep in mind that everything you declare in your session, is also available there).
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
> node
// I tap TAB twice
Array Boolean Date Error EvalError Function Infinity
JSON Math NaN Number Object RangeError ReferenceError
RegExp String SyntaxError TypeError URIError decodeURI decodeURIComponent
encodeURI encodeURIComponent eval isFinite isNaN parseFloat parseInt
undefined
ArrayBuffer Atomics Buffer DTRACE_HTTP_CLIENT_REQUEST DTRACE_HTTP_CLIENT_RESPONSE DTRACE_HTTP_SERVER_REQUEST DTRACE_HTTP_SERVER_RESPONSE
DTRACE_NET_SERVER_CONNECTION DTRACE_NET_STREAM_END DataView Float32Array Float64Array GLOBAL Int16Array
Int32Array Int8Array Intl Map Promise Proxy Reflect
Set SharedArrayBuffer Symbol Uint16Array Uint32Array Uint8Array Uint8ClampedArray
WeakMap WeakSet WebAssembly _ assert async_hooks buffer
child_process clearImmediate clearInterval clearTimeout cluster console crypto
dgram dns domain escape events fs global
http http2 https module net os path
perf_hooks process punycode querystring readline repl require
root setImmediate setInterval setTimeout stream string_decoder tls
tty unescape url util v8 vm zlib
__defineGetter__ __defineSetter__ __lookupGetter__ __lookupSetter__ __proto__ constructor hasOwnProperty
isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf
What is important here, aside from the expected global objects and methods, is that you automatically have access to core Node.js modules, like fs, http, os, path and so on. While it is not a big deal, it might be a very convienent thing, especially when you are trying out some ideas in your REPL.
You can use these imported modules in a special way of running Node.js: if you provide a -e
argument with a following string, containing JS code, it will be evaluated immediately:
1
2
> node -e "console.log(os.platform())"
darwin
Keep in mind, that in this mode node does not print anything in the console by default, and you would have to wrap your code in console.log
if you want to see some result. This execution might be helpful, if you don’t want to enter REPL, and don’t want to create a separate file for it.
You can import the repl module directly and use it within your Node.js application. All Node.js does by default can be done using the repl.start method. It will use all the usual defaults, standard input and output streams. To run an interactive shell with our own prompt symbol, we have to create a small javascript file:
1
2
3
4
const repl = require('repl');
// Our own prompt
repl.start('Code:: ');
Now we can run this file, and it will work as before, but with the custom prompt:
1
2
3
4
5
6
> node repl.js
Code:: const sum = (...args) => args.reduce((a, b) => a + b, 0)
undefined
Code:: sum(1, 2, 3)
6
Code:: .exit
As you can see, all commands work as expected. You can cusomize plently of things, so feel free to play around with your own REPL session! For example, you can add your own variables to the scope of REPL, so you don’t need to require them:
1
2
3
4
5
6
const repl = require('repl');
const r = repl.start('Code:: ');
r.context.enrich = (obj) => {
return Object.assign(obj, { prop: 'something' });
}
Now we will have this function in our scope available immediately:
1
2
3
> node repl.js
Code:: enrich({ num: 123 })
{ num: 123, prop: 'something' }