0%

ReagentでClojureScript REPLをリモートから操作する

ReagentはFacebook ReactのClojureScriptで書かれたインタフェースです。OmよりもよりClojureらしく書けるので使いやすいです。Reagentを使うとClojureScriptのREPLが使えるのですが、devモードではブラウザはlocalhostとWebSocketで通信するようになっています。開発はクラウド上で行っているのでdevモードでもリモートから操作できる必要があるので動作する環境を作ってみました。

プロジェクト作成

いつものようにDocker Composeを使って開発環境を作ります。

$ cd ~/clojure_apps
$ tree .
.
├── Dockerfile
├── cookies
├── docker-compose.yml
└── m2

今回はデバッグができるようにDockerfileを修正してnetstatをインストールしておきました。

~/clojure_apps/Dockerfile
FROM clojure
MAINTAINER Masato Shimizu <ma6ato@gmail.com>

WORKDIR /usr/src/app

RUN apt-get update && apt-get install sudo net-tools && \
rm -rf /var/lib/apt/lists/*

RUN adduser --disabled-password --gecos '' --uid 1000 docker && \
adduser docker sudo && \
echo 'docker ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers && \
mkdir /home/docker/.m2 && \
chown -R docker:docker /usr/src/app /home/docker/.m2

VOLUME /home/docker/.m2
USER docker
RUN lein

ENTRYPOINT ["lein"]

Dockerイメージをビルドしておきます。

$ cd ~/clojure_apps
$ docker build -t clojure .

Leiningenのreagent-template

Leiningenで作成するプロジェクトのテンプレートはreagent-templateを使います。docker-component.ymlにfigwheelサービスとleinサービスを作成します。

~/clojure_apps/docker-component.yml
figwheel: &defaults
image: clojure
volumes:
- .:/usr/src/app
- ./m2:/home/docker/.m2
# working_dir: /usr/src/app/hello-reagent
ports:
- "3449:3449"
lein:
<<: *defaults
ports:
- "3000:3000"

working_dirディレクティブをコメントアウトしてからlein newでプロジェクトを作成します。

$ cd ~/cloure_apps
$ docker-compose run --rm --service-ports lein new reagent hello-reagent
Retrieving reagent/lein-template/0.8.1/lein-template-0.8.1.pom from clojars
Retrieving reagent/lein-template/0.8.1/lein-template-0.8.1.jar from clojars
Generating fresh 'lein new' Reagent project.
Removing clojureapps_lein_run_1...

コードの修正

reagent-templatedev.cljsはlocalhostがハードコードされているのでproject.cljにwebsocket-urlやwebsocket-hostを指定しても反映されません。作成されたdev.cljsを手動でpublicなIPアドレスに変更します。

~/clojure_apps/hello-reagent/env/dev/cljs/hello_reagent/dev.cljs
(ns ^:figwheel-no-load hello-reagent.dev
(:require [hello-reagent.core :as core]
[figwheel.client :as figwheel :include-macros true]
[weasel.repl :as weasel]
[reagent.core :as r]))

(enable-console-print!)

(figwheel/watch-and-reload
:websocket-url "ws://210.xxx.xxx.xxx:3449/figwheel-ws"
:jsload-callback core/mount-root)

;;(weasel/connect "ws://localhost:9001" :verbose true)

(core/init!)

FigwheelはClojureScriptを自動でリロードしてくれる便利なツールです。Emacsでファイルを編集するとブラウザでClojureマークのアイコンが表示されてリロードされるので楽しくなります。最近Figwheelが3449ポートでREPLも提供してくれるみたいなのでWeaselのconnectはコメントアウトしました。

project.cljのlein-figwheelのバージョンを0.3.3にあげます。

~/clojure_apps/hello-reagent/project.clj

:plugins [[lein-figwheel "0.3.3"]
[lein-cljsbuild "1.0.5"]]

Figwheelの起動

docker-compose.ymlのworking_dirディレクティブにleinコマンドで作成したReagentプロジェクトを指定します。

~/clojure_apps/docker-component.yml
figwheel: &defaults
image: clojure
volumes:
- .:/usr/src/app
- ./m2:/home/docker/.m2
working_dir: /usr/src/app/hello-reagent
ports:
- "3449:3449"
lein:
<<: *defaults
ports:
- "3000:3000"

Figwheelサーバーを起動します。

$ cd ~/clojure_apps
$ docker-compose run --rm --service-ports lein figwheel
...
Started Figwheel autobuilder

Launching ClojureScript REPL for build: app
Figwheel Controls:
(stop-autobuild) ;; stops Figwheel autobuilder
(start-autobuild [id ...]) ;; starts autobuilder focused on optional ids
(switch-to-build id ...) ;; switches autobuilder to different build
(reset-autobuild) ;; stops, cleans, and starts autobuilder
(build-once [id ...]) ;; builds source one time
(clean-builds [id ..]) ;; deletes compiled cljs target files
(fig-status) ;; displays current state of system
(add-dep [org.om/om "0.8.1"]) ;; add a dependency. very experimental
Switch REPL build focus:
:cljs/quit ;; allows you to switch REPL to another build
Docs: (doc function-name-here)
Exit: Control+C or :cljs/quit
Results: Stored in vars *1, *2, *3, *e holds last exception object
Prompt will show when figwheel connects to your application

この後ブラウザから接続するとClojure ScriptのREPLが起動します。

To quit, type: :cljs/quit
cljs.user=>

Chromeの開発者ツールを開くとWebSocketの接続を確認できます。

http://210.xxx.xxx.xxx:3449/

reagent-chrome.png

REPLにJavaScriptのアラートを表示してみます。

cljs.user=> (js/alert "REPLからアラート表示")

iTermで入力した値がChromeブラウザのアラートに表示されました。

repl-alert.png