DEV Community

Cover image for How to Make Coding Fun in JavaScript (Almost Like in Clojure)
Stanislav Somov
Stanislav Somov

Posted on

How to Make Coding Fun in JavaScript (Almost Like in Clojure)

A REPL?! What is it?

REPL stands for Read-Eval-Print Loop, and in Clojure it’s the way to work with
code. It’s interactive, fast, and honestly just fun. You write some code, run it
immediately, and boom - you’ve got the result right there.

The problem with the default NodeJS REPL is that it’s not very practical for
everyday coding. Running it in a terminal isn’t convenient: you don’t see the
full picture, your code isn’t linted/checked beforehand, and you’re constantly
switching between the editor and the terminal, losing focus and context.

So, in this post I’ll show you how to make JavaScript coding way more
interactive and enjoyable - kinda like how people code in Clojure.

For example, in JavaScript you might write:

function add(a, b) { return a + b; }
Enter fullscreen mode Exit fullscreen mode

To test it, you’d usually add some tests, or do something like:

console.log(add(36, 6));
Enter fullscreen mode Exit fullscreen mode

Then run it with:

node index.js
Enter fullscreen mode Exit fullscreen mode

That’s a lot of steps for a single result.

In Clojure, it’s much more direct:

(defn add [a b] (+ a b))
(add 35 7) ;; => 42
Enter fullscreen mode Exit fullscreen mode

The feedback loop is immediate. (Of course, we still need proper tests for
real-world software, but for exploration and problem-solving, a REPL is very
effective.)


The Recipe

So how do we bring that to JavaScript?

I wrote an extension for the Conjure plugin
in Neovim. Setup is simple - just follow the
docs:

  • Install Neovim
  • Install Conjure
  • Install NodeJS
  • Install Treesitter and run :TSInstall javascript inside Neovim
  • Create a new ".js" file and open it in Neovim(for example: nvim repl-test.js in your terminal). Conjure should attach automatically if everything is setup correctly. That’s it - you’re ready to start evaluating JavaScript straight from your editor.

Why bother? Because once you’ve got this REPL loop going, you make fewer bugs,
you can actually feel the flow of your code, and you tweak things way faster.

Example:

const mult = (a, b) => a * b;
mult(3, 4);  // (out) 12
mult(5, 3);  // (out) 15
mult(10, 8); // (out) 80
Enter fullscreen mode Exit fullscreen mode

Want to see the value of an expression quickly? Press <localleader>ee
(Conjure’s default). Need to explore an object? Just evaluate it:

const obj = { a: 1, b: { c: 3 } }; // eval this first
obj.b.c;                           // (out) 3
Enter fullscreen mode Exit fullscreen mode

Debugging on the Fly

Checking intermediate steps becomes simple:

[1, 2, 2, 3].reduce((acc, x) => { 
  console.log("acc", acc);
  console.log("x", x);
  console.log("val", acc[x]);
  return { ...acc, [x]: ++acc[x] || 1 }; 
}, {}); 
Enter fullscreen mode Exit fullscreen mode

You’ll instantly see each step in Conjure’s log buffer. No rerunning files, no
juggling terminals. Just... flow.


A Quick Clojure Example

Clojure developers often define a function and immediately test it inside a
(comment ...) block:

(defn name-extractor [m] (get m :name))
(comment 
   (name-extractor {:name "Kisha"}) ;; "Kisha"
   (name-extractor {:age 20}))      ;; nil
Enter fullscreen mode Exit fullscreen mode

If we want to return :noname when the field is missing, we just adjust the
function:

(defn name-extractor [m]
   (get m :name :noname))
Enter fullscreen mode Exit fullscreen mode

And if we want to handle empty strings as well:

(defn name-extractor [{:keys [name]}]
  (or (not-empty name) :noname))
Enter fullscreen mode Exit fullscreen mode

Each step is tried and refined in the REPL.


Doing the Same in JavaScript

function nameExtractor({ name }) {
  return name || "noname";
}
nameExtractor({ name: "John" }); // 'John'
nameExtractor({ age: 15 });      // 'noname'
nameExtractor({ name: "" });     // 'noname' 
Enter fullscreen mode Exit fullscreen mode

Just like in Clojure, you can write small test cases inline and adapt the
function step by step.


Exploring RXJS

RXJS can feel abstract at first, but with the REPL you can experiment
interactively and see results as you go:

import { BehaviorSubject } from "rxjs"
import { combineLatestWith, map, tap } from "rxjs/operators"

let o1 = new BehaviorSubject({ a: 1 })
let o2 = new BehaviorSubject({ b: 6 })

o1.pipe(combineLatestWith(o2),
  tap(x => console.log("combined:", x)),
  map(([{ a }, { b }]) => a + b),
  tap(x => console.log("sum:", x))
).subscribe()

o1.next({ a: 2 })
o2.next({ b: 8 })

o1.unsubscribe()
o2.unsubscribe()
Enter fullscreen mode Exit fullscreen mode

You can adjust values, rerun them, and instantly observe how the transformations
behave.


Useful Keybindings

  • <localleader>ef - evaluate the whole file
  • <localleader>ts - toggle Stray Out Mode (to see delayed evaluations like setTimeout)
  • <localleader>cr - restart the REPL (clears all previous evaluations)
  • <localleader>E - evaluate a selected block of text in visual mode (great for JSDoc examples)

NodeJS Quirks (Handled by Conjure)

  • Arrow functions can’t be redefined in the NodeJS REPL, but Conjure rewrites them as regular functions.
  • import isn’t supported in the NodeJS REPL, but Conjure translates it into require.

Wrapping Up

These tricks can make your workflow in JavaScript faster, more interactive, and
closer to the Clojure REPL style. A shorter feedback loop not only makes coding
more enjoyable, but also helps you write cleaner, more reliable code.

Top comments (1)

Collapse
 
roshan_sharma_7deae5e0742 profile image
roshan sharma

Wow, this hits the sweet spot, I’ve always wanted JS to feel more interactive without jumping between editor & terminal all the time. Using Conjure + Neovim for REPL sounds great.