🔖ClojureScriptの開発環境について.
📝Google Closure Compiler
JavaScriptを最適化するためのコンパイラ.
Closure Compiler は JavaScript の最適化、トランスパイル、タイプチェックを行うツールです。これを使うと、コードを高パフォーマンスでサイズが縮小されたコードにコンパイルすることができます。この仕組みは Google のほとんどのウェブ フロントエンドで使われており、できる限りサイズが小さく高速なコードを提供しています。
🔖ClojureScriptはこの最適化のちからを十二分に利用しているらしい.
- Closure Compiler | Google Developers
- Google Developers Japan: JavaScript の Closure Compiler
- https://github.com/google/closure-compiler
Externs
externsは, 高度なコンパイル中に名前を変更すべきでないシンボルの名前を Closure Compiler に伝える宣言. これをしないとファイル分割でライブラリを呼び出せない.
ヘッダファイルのようなもの.
^:export init
よくみかけるやつ. ^:exportはinit関数に対するmetadataであり, global変数としてGoogle Closureが呼べるようにするとか(by Linivng Clojure).
Debugs
js/console.log
(def log (.-log js/console))
💡Chrome/Firefox Devtools連携
- GitHub - binaryage/cljs-devtools
- A collection of Chrome DevTools enhancements for ClojureScript developers.
- Source mapsの導入によってJavaScriptのデバッグが楽になる.
- sourcemapはJavaScriptのコンパイルの変換前と変換後の対応関係を示すjsonデータ. これがないとJavaScriptからそれに対応するソースが辿れない.
- sourcemapがあればChromeからソースがみれる.
- ClojureScript - Source maps
- GitHub - binaryage/dirac
- ClojureScript用のChrome拡張, fork for Chrome Devtools.
JavaScript Objectの中身をみるには?
inspectだと, #object [Foo [Object Object]]
みたいになって中身がみれない.
最も簡単な方法は, js/console.logでの表示.
helper functionsをつかう
(defn clone-js [jsobj]
(.parse js/JSON (.stringify js/JSON jsobj)))
js->cljでは不十分.
ref. inspect by ‘new’ constructed JavaScript object’s at the ClojureScript REPL - Stack Overflow
Build Tools
🔧shadow-cljsを使うか、figwheelを使うか. lumoは2022はオワコン?
- 🔧shadow-cljs: cljsをコンパイルしたりビルドするためのツールセット.
- figwheel-main: 自動コンパイルとホットコードリローディングの機能を提供.
- ClojureScript + React / React Nativeの雛形まとめ - Qiita
- 2021なので最近の情報.
shadow-cljsとfigwheel-mainの違いはnpmに依存するかどうか. shadow-cljsはnpmを利用する i.e. よりJavaScriptとの連携や共存がしやすい. この観点でどちらのツールを選択するかは選んだほうがよさそう.
💡ClojureScript with Node.js
ClojureScriptのコンパイル結果を📝Node.jsで実行可能なものにする.
ClojureScriptはコンパイラなので, コンパイルオプションでNode.jsをターゲットにすることを指定することになるが, 大抵の場合はビルドツールをつかって指定することになる. このとき, Clojure(JVM)に依存するツールとそうでないものにわけられる.
- 🔧nbb
- 🔧shadow-cljs
- Lumo
🔧shadow-cljs
cljsをコンパイルしたりビルドするためのツールセット.
- https://github.com/thheller/shadow-cljs
- shadow-cljs.edn に設定を書いていく.
ライブラリの追加方法
shadow-cljs.ednの :dependencies に追加していく. インストールはshadow-cljsのコマンドを走らせる延長で走る.
ref. Dependencies: Shadow CLJS User’s Guide
shadow-cljsコマンドの基本的な使い方
npm pacakgeとしてインストールしたshadow-cljsコマンドの使い方まとめ.
プロジェクトの新規
$ npx create-cljs-project my-project
# すでにpackage.jsonがプロジェクトにあるとき
$ npm install --save-dev shadow-cljs
# もしくはglobal環境へ
$ npm install -g shadow-cljs
Basic Development Commands
# compile a build once and exit
$ shadow-cljs compile app
# compile and watch
$ shadow-cljs watch app
# connect to REPL for the build (available while watch is running)
$ shadow-cljs cljs-repl app
# connect to standalone node repl
$ shadow-cljs node-repl
# Running a release build optimized for production use.
$ shadow-cljs release app
Server Mode Commands
# running server-mode
$ shadow-cljs server
$ shadow-cljs clj-repl
$ shadow-cljs start
$ shadow-cljs stop
$ shadow-cljs restart
node.jsでつかう
ref. https://shadow-cljs.github.io/docs/UsersGuide.html#target-node
shadow-cljs.ednに設定を書く. :targetが :node-scriptになる.
{:source-paths ["src"]
:dependencies []
:builds {:app {:target :node-script
:output-to "target/helloworld.js"
:main demo.helloworld/main}}}
Tips
REPLのlocahostのport整理
server modeで立ち上げるといろいろでてくるので整理.
shadow-cljs - HTTP server available at http://localhost:3000
shadow-cljs - HTTP server available at http://localhost:8080
shadow-cljs - server version: 2.18.0 running at http://localhost:9630
shadow-cljs - nREPL server started on port 38105
- localhost:3000は shadow-cljs.ednで自分で設定, devtools用.
- localhost:8080は shadow-cljs.ednで自分で設定, Web表示確認用.
- localhost:9630はshadow-cljsのデバッグツールが並ぶ.
- localhost:38105はnREPLようでCIDERから接続する.
例えばcider-connectをするときはnREPLのための38105にアクセスする.
3つのREPLの整理(clj-repl/node-repl/browser-repl)
shadow-cljsの起動オプションで3つを抑えておく.
- clj-repl(server-mode)
- node-repl
- browser-repl
$ shadow-cljs server
$ shadow-cljs clj-repl
clj-repl(server-mode) は 開発用サーバを立ち上げるときにつかう. clojurescriptを長時間Loopさせている.
$ shadow-cljs node-repl
$ shadow-cljs browser-repl
node-repl はnode.jsで起動するREPL. これはJavaで動くClojureのREPLと同じ.
browser-repl は node-replと機能が変わらないもののBrowserの JavaScriptコンソールと接続することができるモード.
Emacs CIDERでつかう
cider-jack-in-cljsですべてできる. プロンプトでshadow-cljsを選択.
もしくは,
- shadow-cljs watch app
- cider-connect-clj
- watch で起動して表示されたportを入力(nREPL server start on port x)
- shadowを選択
- アプリケーションを選択.
ここでの注意点は, shadow-cljs.ednのdependenciesにcider-nreplを追加すること. これがないとevalできない.
{
:dependencies
[[cider/cider-nrepl "0.28.4"]]}
ref. https://docs.cider.mx/cider/cljs/shadow-cljs.html
deps.ednとshadow-cljsを共存させるには?
defaultではnode.jsの管理ツールであるpackage.jsonを利用するがやはりClojureをつかってると Leiningen や Clojure CLI と共存させたいところだ.
shadow-cljs inspect with tap
🔧clojure.core/tapと連携できる. shadow-cljsのブラウザに Inspect Stream/Inspect Latestというタブかあり, ここに tap>で追加した要素が表示される.
JavaScript LibraryをClojureScriptから呼び出す
shadow-cljsはnode_modules配下のjsファイルを直接読める.
// node_modules/dev/calculator.js
var calculator = {
add: function (a, b) {
return a + b;
},
subtract: function (a, b) {
return a - b;
}
};
module.exports = calculator;
(ns dev.playground
(:require ["dev/calculator" :refer [add]]))
(add 1 2)
Typescriptだとtscコマンドでコンパイルしたものを配置する必要がある.
shadow-cljsではdefaultでは🔖ES6の記法を認識する(!= commonJS). すなわち, module.exportsではなく, export class.
export class HelloWorld {
constructor(name) {
this.name = name;
}
greet() {
return `Hello, ${this.name}!`;
}
}
The previously used runtime disappeared. Will attempt to pick a new one when available but your state might be gone.
shadow-cljsのheartbeat. 処理が15秒以上かかるとこうなる.
Promiseをつかって非同期で処理させたり, cliからshadow-cljs を立ち上げてcider-connectすることで回避.
- https://github.com/thheller/shadow-cljs/issues/963
- https://shadow-cljs.github.io/docs/UsersGuide.html#missing-js-runtime
References
- Shadow CLJS User’s Guide
- clojurescriptのshadow-cljsについて - Qiita
- shadow-cljs - Qiita
- shadow-cljs/quickstart-browser/README-ja.md· GitHub
- 誰かがquickstartを日本語に訳してくれた.
- https://t-cool.github.io/shadow-cljs-users-guide-ja/docs/UsersGuide.pdf
Format
- node-cljfmt
エディタ連携
💡ClojureScript with CIDER
Emacs CIDER連携.
M-x cider-jack-in-cljsでjack-in or M-x cider-connect-cljsでconnect.
shadow-cljsを利用するには Select ClojureScript REPL type: のプロンプトでshadowを選択する. さらにshadow-cljs.ednで定義したbuild nameを選択すると接続完了. もしくは .dir-locals.el に設定を書いておくことでプロンプト入力は省略できる.
((nil . ((cider-default-cljs-repl . shadow)
(cider-shadow-default-options . "<your-build-name-here>"))))
jack-inによって ClojureScriptのREPLがnREPLと連携するためのツールが自動で組み込まれる.
- nrepl/nrepl
- refactor-nrepl
- cider/cider-nrepl
- cider/piggieback
したがってコンソールからcljで起動してEmacsからcider-connectする場合はこれらの依存パッケージをdeps.ednに記入する必要がある.
shadow-cljsの場合, jack-in-cljsをすることでshadow-cljs.ednがおいてあればshadow-cljsと解釈されて自動でserverが立ち上がってconnectまでしてくれる. もしくは shadow-cljs server コマンドでサーバを立ち上げM-x cider-connectで接続できる.
Topics
バイナリデータはjs/console.logを使わないとsegfault
デコードが必要なデータを取得したあとそのままREPLにprnとかで出力しようとするとセグメンテーションフォルトが発生する.
この場合, js/console.logのprint出力ならば問題ない. データを特定してデコードする.