Mastering the Node.js REPL (part 2)
In the first part of this series we have covered the basics of the Node.js REPL. Now is time to learn how to use the programmatic API to transform it into a powerful tool for development.
Building our own custom REPL
Hello, world
We are going to begin by building a REPL version of a hello world. We can start our greeter loop with just a few lines of code:
That is pretty much self explanatory. We import the repl
node library, we print a message and we start the loop. We use the USER
environment variable and the current working directory to print a nice message:
Adding some colors
We can highlight some parts of the welcome message to make things easier to read:
We colorized the username and the current working directory to make it look a bit better:
Customizing the prompt
The REPL prompt is just a string which can be passed to the start()
function:
Now we have a nice prompt that shows the node version that we are running:
The exit
event
The start
function returns the loop server. Using the loop server instance we can listen to server events like the exit
event:
Understanding the REPL context
The basics
Let’s say we run our last example in the terminal using the CLI:
As you can see, the variables we defined in our code are not available in our REPL. This happens because when we invoke the start
method, a new execution context is created for the REPL. This context is different from the context where the rest of our code is executed, so we won’t have access to the variables we define in it.
We can define properties in the context by using the reference to the loop server instance that the start
method returns.
By defining properties in the server’s context object we expose them to be used within the REPL:
Read-only context
The context properties are not read-only by default, so they can be overwritten if we mess up:
We can define them as read-only using Object.defineProperty()
:
We could also write a nice utility function to extend our context easily, It would be something like this:
After doing this, our context properties cannot be overwritten any more:
Handling context reloads
The context can be anything we want (for instance, it could hold state). For this reason it sometimes makes sense to reset the context to its default value.
The REPL command .clear
can be used to reset the context. Let’s try it out:
The context is not being reloaded properly because we need to listen for the reset
event and re-initialize it when the event is fired:
The reset
listener should be a function context => { ... }
that receives the context and does whatever it wants with it.
Now our context is being properly reloaded:
Using the global
context
There is a way to force the REPL to use the global context instead of a separate context. This is the setting that the default node REPL uses.
Setting the REPL to use the global context can be useful if you need to define the context before the loop server is actually instantiated. You’ll lose, however, the ability to reload it:
Custom node commands
Another cool trick you can do with it is defining new commands. You can define dot commands using the loop server method defineCommand
.
The defineCommand
method takes a command name and a { help, action }
object:
It’s worth noting that the action
function will be bound to the loop server, so we should invoke the server’s functions using the this
keyword. Avoid using an arrow function here, since they have lexical scope.
Now that we have defined our command, it will be available for us within the REPL and it will be shown when we invoke .help
:
Using the await keyword
Just like we covered in our previous post, we can also run our custom REPL with the experimental await
support using the flag --experimental-repl-await
:
Wrapping it up once again
In this post we have covered the basics of the REPL’s programmatic API. Our complete code looks like this:
If you made it this far you may want to play a bit with what you’ve learned today. You can find all the code we used in this repository.
In the next part of the series we’ll make a custom REPL for a real project. Stay tuned!