TL;DR

  • ClojureScript のビルドは Clojure のビルドシステムから npm 中心へと移り、現在は shadow-cljs がデファクトスタンダードである。
  • Squint は互換性を捨てて JavaScript との親和性を高めた方言で、async / await や JSX を使えるが、既存の資産は使えず仕様もまだ固まっていない。

内容

ClojureScript のビルドの歴史

ClojureScript を npm で使えるようになったのは最近である。それまでは Clojure のビルドシステムに乗っていて、Maven や Gradle から、Leiningen、Boot、Clojure CLI へと移ってきた。パッケージは Clojars に cljsjs という名前空間で登録していた。npm が成熟するにつれてこの方式は相対的に不便になり、ホットリロードもできないので REPL からリロードする必要があった。

Figwheel はホットリロードができ、cljsjs も扱える。頑張れば npm パッケージも使えるらしい。

現在のデファクトスタンダードは shadow-cljs である。npm からインストールでき、npm のライブラリも Clojars のライブラリも使える。ホットリロードもでき、webpack や Vite のような感覚で使える。ただし、起動がやや遅く、CSS はビルドできない。User’s Guide をしっかり読む必要もある。

ClojureScript 自体への不満

ClojureScript の Map や Vector は JavaScript のオブジェクトや配列ではないので、相互に変換する必要がある。また、async / await をサポートしていないので、Promise を扱いにくい。core.async を使えばほぼ同じことはできるが、Promise を返すわけではないので、組み合わせるとうまく動かない。

Squint

Squint は、既存の ClojureScript との互換性を捨てて、JavaScript との親和性を高めた ClojureScript の方言である。Map や Vector は JavaScript の普通のオブジェクトや配列になる。ビルド後のファイルサイズが小さく、JSX や HTML を書けて、async / await も使える。Vite と組み合わせて開発できる。

使うときの注意

仕様が固まっておらず細かい不具合もまだ多いので、本番環境で使うときは注意が必要である。既存の ClojureScript の資産も使えない。たとえば、動的な型チェックに使う Malli は使えない。JavaScript で代わりになる型チェックのライブラリは、軒並み TypeScript 製に置き換わっている。かつて React で使われていた prop-types はあるが、メンテナンスされていなさそうである。

回避策として、Zod や Valibot のようなバリデーションライブラリを、関数の入力値の動的な型チェックに使う。Clojure の関数には pre / post で事前条件と事後条件を設定できる(契約による設計)ので、そこでバリデーションライブラリを使う。チェックは NODE_ENV=development のときだけ行う。

キーワード

自分の理解

shadow-cljs をキャッチアップするとき、User’s Guide はめちゃくちゃ見た気がする。

関連