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 <[email protected]>

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の接続を確認できます。

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

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

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