Squint: a ClojureScript syntax to JS compiler

Introducing squint, a ClojureScript syntax to JavaScript compiler!

The primary use case for squint is to produce JavaScript using ClojureScript syntax while producing ultra-small bundle sizes, by leveraging the JS platform directly. Squint does not protect you from the pitfalls of JS (mutability, equality), but lets you use the concepts you already know from ClojureScript and maps them more or less directly to JS where this makes sense. It comes with a standard library which has many of the core functions you know: map-indexed , for example, works like you would expect, but returns a mutable JS array instead of an immutable vector.

Repo: https://github.com/squint-cljs/squint

Npm: npm install squint-cljs

Read Differences with ClojureScript for… well, the differences with ClojureScript.

It has support for async/await and JSX.

Squint is open to contribution, especially in the area of porting core functions.

An example of a SolidJS app written using Clava:

https://squint-cljs.github.io/demos/squint/solidjs/ (source)

Give it a spin and let us know what you think.

On behalf of the core team, have fun!

10 Likes

Uh oh, the equality and truthiness pitfalls of JS :scream_cat:

Ok, one question, what does = become? Does it become === ?

2 Likes

Yes (and here are some extra characters, so I’m allowed to post this reply).

2 Likes

I’m really excited by this project. I work primarily with JS and can’t see that changing. I’d like to use Clojure to build tooling around my current work - being closer to JS will be a big help. Looking forward to macros and the REPL!

Very cool! Next web project I hope I can try it out! :smiley:

Curious what the averages end up looking like here. And would you lean on a js build tool for tree shaking?

Yes, the idea is to use JS tooling for “build” stuff. esbuild performs quite well with clavascript.

1 Like

The name was changed from ClavaScript to squint.

1 Like

Really cool stuff. the jsx integration is great though the language is a bit too close to clojure for my liking. As in… I’ll likely get the immutable ops mixed up with the mutable ones.

Are there examples of compiler outputs?

The language resembles ClojureScript so that you don’t have to learn new APIs and porting between cherry and squint is easy. E.g. I’ve taken a Hacker News reader that was built in cherry and could port it to squint with almost no changes:

clava-hn-reader (ported from cherry-hn-reader, it has the name clava, because squint was called clavascript before).

The “immutable” core functions in squint, like assoc, do not mutate the original, but create shallow copies of the original, so they are never causing “spooky action at a distance” effects. There is also the mutating assoc!.

Something like immer could be used to get back cheap full-blown immutability. I’ve made a little
start with that here: squint-immer. Compiling an example using squint + immer comes down at around 11kb with esbuild.

You can see the compiler output of squint in the playground: Squint
Or you can run npx squint --no-run --show -e '(+ 1 2 3)' on the command line.

haha. that’s so cool. I did something really something really similar when I started going down this rabbit hole:

… and like about 20 more repos…


It’s a pretty steep climb down though cos JS is just too vast an ecosystem right now. Good on you. Really jealous. Wish I had the luxury to do open source.

You can also do similar things with ink and nbb:

sorry… was showing off there… I’ll stop.

oh cool… you’re using ink.

that’s a good library. have you tried terminal-kit?

I think it’s better than both blessed and ink if done right.

I’ve heard of it, but I haven’t tried it. I might now!

it needs to be reactified… but it’s still being maintained and worked upon. I was a bit sort on time and gave up trying to and just built on top of react-blessed but it’s got really good primitives to build upon. ink is too opinionated for me and not as flexible as either blessed or terminal-kit. But it’s really well maintained.

I got really into terminal apps for a while. still love to do more of it if I get the opportunity.

Just wanted to say that I’ve been using Squint and it works great. I really like that fact that it can be used as a Clojure library.

We have a static site builder tool and I use Squint to replace small JavaScript scripts (eg jquery type popups, tracking, etc) where Clojurescript would be overkill, but I still want Clojure syntax.

I’m embedding the Squint code directly in the Clojure template functions, and it works pretty well.

2 Likes

@mjmeintjes This is very helpful to know. Can you let me know which API you are currently using from Clojure? I’ll take care to write some unit tests for it and try to not break the API.

Thanks. I’m just using the squint.compiler/compile-string function.

(ns mattsum.squint
  (:require [squint.compiler :as sq]
            [backtick :as bt]
            [mattsum.hashing :as hash]
            [clojure.string :as str]))

(defn to-js [code {:keys [requires]}]
  (sq/compile-string
   (str "(ns module" (str/replace (hash/uuid-str [code requires]) "-" "_")
        "(:require " (str/join "\n" requires) "))"
        code)))

(defmacro js [ctx & code]
  `(to-js (bt/template (do ~@code)) ~ctx))

(defmacro compile-js [ctx & code]
  `(js ~ctx ~@code))


(comment
  (compile-js
   {}
   (let [a 123]
     (println a))))
1 Like