Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
squint-cljs
Advanced tools
Squint is a light-weight dialect of ClojureScript with a compiler and standard library.
Squint is a light-weight dialect of ClojureScript with a compiler and standard library.
Squint is not intended as a full replacement for ClojureScript but as a tool to target JS when you need something more light-weight in terms of interop and bundle size. The most significant different with CLJS is that squint uses only built-in JS data structures. Squint's output is designed to work well with ES modules.
If you want to use squint, but with the normal ClojureScript standard library and data structures, check out cherry.
:warning: This project is a work in progress and may still undergo breaking changes.
Although it's early days, you're welcome to try out squint
and submit issues.
$ mkdir squint-test && cd squint-test
$ npm init -y
$ npm install squint-cljs@latest
Create a .cljs
file, e.g. example.cljs
:
(ns example
(:require ["fs" :as fs]
["url" :refer [fileURLToPath]]))
(println (fs/existsSync (fileURLToPath js/import.meta.url)))
(defn foo [{:keys [a b c]}]
(+ a b c))
(println (foo {:a 1 :b 2 :c 3}))
Then compile and run (run
does both):
$ npx squint run example.cljs
true
6
Run npx squint --help
to see all command line options.
Squint lets you write CLJS syntax but emits small JS output, while still having parts of the CLJS standard library available (ported to mutable data structures, so with caveats). This may work especially well for projects e.g. that you'd like to deploy on CloudFlare workers, node scripts, Github actions, etc. that need the extra performance, startup time and/or small bundle size.
(slides)
"squint-cljs/core.js"
, a smaller re-implemented subsetconst x = [...y];
Symbol.iterator
, not custom data structuresmap
, filter
, etc. produce lazy iterable values but their
results are not cached. If side effects are used in combination with laziness,
it's recommended to realize the lazy value using vec
on function
boundaries. You can detect re-usage of lazy values by calling
warn-on-lazy-reusage!
.(def x (js-await y))
. Async functions must be marked
with ^:async
: (defn ^:async foo [])
.assoc!
, dissoc!
, conj!
, etc. perform in place mutation on objectsassoc
, dissoc
, conj
, etc. return a new shallow copy of objectsprintln
is a synonym for console.log
pr-str
and prn
coerce values to a string using JSON.stringify
(currently, this may change)If you are looking for closer ClojureScript semantics, take a look at Cherry 🍒.
Solve Advent of Code puzzles with squint here.
Squint does not implement Clojure seqs. Instead it uses the JavaScript iteration protocols to work with collections. What this means in practice is the following:
seq
takes a collection and returns an Iterable of that collection, or nil if it's emptyiterable
takes a collection and returns an Iterable of that collection, even if it's emptyseqable?
can be used to check if you can call either oneMost collections are iterable already, so seq
and iterable
will simply
return them; an exception are objects created via {:a 1}
, where seq
and
iterable
will return the result of Object.entries
.
first
, rest
, map
, reduce
et al. call iterable
on the collection before
processing, and functions that typically return seqs instead return an array of
the results.
With respect to memory usage:
(js/global.gc)
(println (js/process.memoryUsage))
(defn doit []
(let [x [(-> (new Array 10000000)
(.fill 0)) :foo :bar]
;; Big array `x` is still being held on to by `y`:
y (rest x)]
(println (js/process.memoryUsage))
(vec y)))
(println (doit))
(js/global.gc)
;; Note that big array is garbage collected now:
(println (js/process.memoryUsage))
Run the above program with node --expose-gc ./node_cli mem.cljs
You can produce JSX syntax using the #jsx
tag:
#jsx [:div "Hello"]
produces:
<div>Hello</div>
and outputs the .jsx
extension automatically.
You can use Clojure expressions within #jsx
expressions:
(let [x 1] #jsx [:div (inc x)])
Note that when using a Clojure expression, you escape the JSX context so when you need to return more JSX, use the #jsx
once again:
(let [x 1]
#jsx [:div
(if (odd? x)
#jsx [:span "Odd"]
#jsx [:span "Even"])])
To pass props, you can use :&
:
(let [props {:a 1}]
#jsx [App {:& props}])
See an example of an application using JSX here (source).
Play with JSX non the playground
Similar to JSX, squint allows you to produce HTML as strings using hiccup notation:
(def my-html #html [:div "Hello"])
will set the my-html
variable to a string equal to <div>Hello</div>
.
Using metadata you can modify the tag function, e.g. to use this together with lit-html:
(ns my-app
(:require ["lit" :as lit]))
#html ^lit/html [:div "Hello"]
This will produce:
lit/html`<div>Hello</div>`
See this playground example for a full example.
Squint supports async/await
:
(defn ^:async foo [] (js/Promise.resolve 10))
(def x (js-await (foo)))
(println x) ;;=> 10
Anonymous functions must have ^:async
on the fn
symbol or the function's name:
(^:async fn [] (js-await {}) 3)
Generator functions must be marked with ^:gen
:
(defn ^:gen foo []
(js-yield 1)
(js-yield* [2 3])
(let [x (inc 3)]
(yield x)))
(vec (foo)) ;;=> [1 2 3 4]
Anonymous functions must have ^:gen
on the argument vector:
(^:gen fn [] (js-yield 1) (js-yield 2))
See the playground for an example.
If for some reason you need to emit arrow functions () => ...
rather than
function
, you can use :=>
metadata on the function expression, fn
symbol
or argument vector:
(fn ^:=> [] 1)
See doc/defclass.md.
The JavaScript API exposes the compileString
function:
import { compileString } from 'squint-cljs';
const f = eval(compileString("(fn [] 1)"
, {"context": "expr",
"elide-imports": true}
));
console.log(f()); // prints 1
Squint has a console repl which can be started with squint repl
.
A (currently immature!) nREPL implementation can be used on Node.js with:
squint nrepl-server :port 1888
Please try it out and file issues so it can be improved.
You can use this together with inf-clojure
in emacs as follows:
In a .cljs
buffer, type M-x inf-clojure
. Then enter the startup command npx squint repl
(or bunx --bun repl
) and select the clojure
or babashka
type
REPL. REPL away!
Squint respect CLJS truth semantics: only null
, undefined
and false
are non-truthy, 0
and ""
are truthy.
To load macros, add a squint.edn
file in the root of your project with
{:paths ["src-squint"]}
that describes where to find your macro files. Macros
are written in .cljs
or .cljc
files and are executed using
SCI.
The following searches for a foo/macros.cljc
file in the :paths
described in squint.edn
.
(ns foo (:require-macros [foo.macros :refer [my-macro]]))
(my-macro 1 2 3)
squint.edn
In squint.edn
you can describe the following options:
:paths
: the source paths to search for files. At the moment, only .cljc
and .cljs
are supported.:extension
: the preferred extension to output, which defaults to .mjs
, but can be set to .jsx
for React(-like) projects.:copy-resources
: a set of keywords that represent file extensions of files
that should be copied over from source paths. E.g. :css
, :json
. Strings
may also be used which represent regexes which are processed through
re-find
.See examples/vite-react for an example project which uses a squint.edn
.
Run npx squint watch
to watch the source directories described in squint.edn
and they will be (re-)compiled whenever they change.
See examples/vite-react for an example project which uses this.
A svelte pre-processor for squint can be found here.
See examples/vite-react.
See examples/expo-react-native.
See examples/babashka/index.clj.
Squint is licensed under the EPL. See epl-v10.html in the root directory for more information.
FAQs
Unknown package
The npm package squint-cljs receives a total of 282 weekly downloads. As such, squint-cljs popularity was classified as not popular.
We found that squint-cljs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.