IDEA+sbt-appengineで流れるような開発
前回の投稿でIDEAとsbt-appengineが連携してくれたのは嬉しいけど、ソースを修正するたびにappserverの再起動は面倒!! 出来ることなら、IDEAでコーディング→ブラウザ確認→コーディング→...と繰り返したい。
こちらも実現できたので、方法を紹介。 やったことはこれだけ。
- JRebelでクラスリローディング
- クラスファイルの出力先をwebapp配下にする
- sbtでソースコード監視
環境を簡単に書いておくと、IDEA+sbt(appengine plugin)という組み合わせ。 MyProjectがあって、その下にSubProject1, SubProject2がある構成。このMyProjectとかSubProjectはsbtの管理下にある状態。
まずはJRebelの導入から。 JRebel自体は有償だけど、Scala開発者にはライセンスを提供してくれてるのでこれを活用。 ■ ZeroTurnaround http://sales.zeroturnaround.com/ jrebel.jarを適当な場所に置く。ライセンスファイルもjarと同じところに置いておく。
JRebelでクラスリローディング
クラスリローディング対象とするディレクトリを指定するために、rebel.xmlを作成する。 MyProject/src/test/resources/rebel.xml
続いて、sbtでJRebelを有効にする。 sbt-appengine-pluginではJREBEL_JAR_PATHを指定するだけでJRebelが有効になるはずなんだけど、IDEAのsbtコンソールでは環境変数を見てくれないらしいので、直接指定します。 MyProject/project/build/Project.scala
override def scanDirectories = Nil
override val devAppserverJvmOptions = List("-Xdebug", "-Xrunjdwp:transport=dt_socket,server=y,address=2011,suspend=y") ++ List("-noverify", "-javaagent:/Users/ken/dev/jrebel/jrebel.jar") ++ super.devAppserverJvmOptions
JRebelに関係するのは
List("-noverify", "-javaagent:/Users/ken/dev/jrebel/jrebel.jar")
の部分。 ちなみに、XdebugとかはIDEAで接続するための記述。
クラスファイルの出力先をwebapp配下にする
JRebelの設定も終わったので、あとはIDEAからsbtを実行すればいいんだけど、sbtの出力先がappengineの出力先(webapp)とは異なっているためsbtの "~ compile" で監視をしても意味が無い。そこで、SubProjectの出力先をwebapp配下にします。具体的には、MyProject/SubProject1/target/scala_2.8.1/classesを削除して、MyProject/target/scala_2.8.1/webapp/WEB-INF/classesにシンボリックリンクを張る。 手動でシンボリックリンクを張ればいいんだけど、sbt cleanを実行すると再度やり直さなければならないので、symlinkアクションを作った。 MyProject/project/build/Project.scala
lazy val symlinkInstance = new Symlink
lazy val symlink = symlinkAction
def symlinkAction = task
() extends Runnable
コード中の val subs = Set("SubProject1", "SubProject2")" を各自の環境に合わせてください。
sbt reload後に "symlink" アクションが追加されているので、実行してパスを確認して下さい。サブプロジェクトのclassesがシンボリックリンクになっているはず。
使い方
- sbtで "symlink" を実行。
- IDEAでデバッガ実行(=sbtも起動。前回の投稿参照)
- sbtで "~ compile" を実行
簡単に仕組みを説明。 symlinkを実行することによって、appserverの管理下にクラスファイルを出力するようになります。単にシンボリックリンクを張るだけなので初回だけ。sbt cleanしたときは再度実行します。 続いて、IDEAでデバッガを起動し、sbtの "~ compile" を実行してソースファイルを監視します。ソースコードに修正があった場合はsbtの監視によってコンパイルされ、クラスファイルが生成されます(生成先はsbt symlinkによってappsever管理下になっている)。 ブラウザからアクセスすると、JRebelによってクラスの再読込が行われ、sbtには "JRebel: Reloading class 'package.path.to.ClassName'." と出力されます。
これで、IDEAからsbtを起動し、ブラウザで確認しつつコードを書いていくことが出来る♪