GWTのSuper Dev Modeでコード変更が反映されない

2018年8月19日

もちろんGWTの開発ではSuper Dev Mode無しではお話しにならない。コンパイルには耐えられないほどの時間がかかるからだ。これは、とにもかくにもJavaからJavaScriptへの変換を行うせいである。単に変換するだけではなく、使用されていないコードを完全に除去し、難読化も行ってくれる。

リリース物やリリース直前のテストとしてコンパイルを行うのは良いのだが、当然のことがならコード修正を確認するのにコンパイルするならとてもやってられない(もしそうだとしたらGWTを捨てるしかない)。

コンパイルとは異なり、Super Dev Modeはその名の通りスーパーに高速だ。もちろん、セーブした途端にコンパイルが完了している通常のJavaプログラムには及ぶべくも無いのだが、日々Super Dev Modeのありがたみを実感する次第だ。

しかし、Super Dev Modeでは「あらゆるものをキャッシュしている」らしく、コード変更が全く反映されないことが良くある。反映されないだけ、動かないだけなら良いのだが、何やら不可解なエラーが大量に吐き出され、ウェブを検索しても意味不明。七転八倒しながら解決策を見出すことになってしまう。

これを避け、解決するための方針について書いてみる。

問題発生の例

以下の記述では、最新Eclipse(2018/1 Oxygen)でGWTサンプルを動かすまでの記述の通り、Eclipseでsampleという名のGWTプロジェクトを作成し、「GWT Development Mode With Jetty」でSuper Dev Modeを動作させて開発することを前提としている。

開発とは言っても、コードを少しいじってみるだけでもよい。Super Dev Modeがキャッシュを保持しているため、少々コードをいじったくらいでは、キャッシュが変更されない場合があるのだ。

実際に、RPCのパスを変更して再度起動してみると、うまくいかない。パス変更だけでは、Super Dev Modeのキャッシュが再構築されないことがわかる。

具体的には、クライアント側の以下の部分を修正し、

package sample.client;

(略)

@RemoteServiceRelativePath("greet1") // 名称変更
public interface GreetingService extends RemoteService {

(略)

war/WEB-INF/web.xmlを以下のように修正する。

  <servlet-mapping>
    <servlet-name>greetServlet</servlet-name>
    <url-pattern>/sample/greet1</url-pattern> <!-- 名称変更 -->
  </servlet-mapping>

しかし、Super Dev Modeをいったん停止し、再度起動しても以下のエラーが発生してしまう。

コンソールを見てみると、以下のようにクライアント側の呼び出しパスが変更されていないことがわかる。変更されたコードではなく、キャッシュの方を見ているのだ。

CodeServerのcleanを行う

最も簡単な解決方法としては、Super Dev Modeと共に自動的に動作しているCodeServerのcleanボタンをクリックすることだ。

これは、デフォルトでは、「http://127.0.0.1:9876/」というURLでアクセスできる。

※Super Dev Modeでのウェブアプリへのアクセスは「http://127.0.0.1:8888/Sample.html」であり、異なるポートが用いられている。

先の9876をブラウザで表示してみると、左下に「clean」というボタンがあるので、これをクリックする。

その後に、ウェブアプリの方「http://127.0.0.1:8888/Sample.html」をリロードして試してみる。すると、正しく以下の表示になる。

なお、CodeServerのページの中のDev Mode On/Offは気にしなくてもよいようだ。これは、Super Dev Modeからではなく、CodeServerのみを起動する場合に使うらしい。

作業ディレクトリの位置を指定する

上記で問題解決されようとしなかろうと、キャッシュの場所(作業ディレクトリの場所)は是非指定して欲しい。プログラムが大きくなってくると、Super Dev ModeやCodeServerの吐き出すキャッシュの量が半端ではなく、OSのデフォルトの一時ディレクトリに残ったままになってしまう。Windowsでのデフォルトは、「C:\Users\admin\AppData\Local\Temp」になる。

また、CodeServerページで問題が解決されない場合には、意図的に全キャッシュを削除したい場合もあるかもしれない。そこで、Super Dev Modeとそれによって自動起動されるCodeServerのどちらにも作業ディレクトリを指定する。これを仮に、「C:\Users\admin\Desktop\gwt-tmp」としてみる。

Super Dev Modeへの作業ディレクトリ指定

まず、Eclipseで一度でも「GWT Development Mode With Jetty」によって起動していれば、次のようなRun Configurationができているはずだ。

-remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -startupUrl Sample.html -logLevel INFO -codeServerPort 9997 -port 8888 -war C:\devel\workspace\sample\war sample.Sample

などとなっているので、-workDirフラグで作業ディレクトリを指定する。

-remoteUI "${gwt_remote_ui_server_port}:${unique_id}" -startupUrl Sample.html -logLevel INFO -codeServerPort 9997 -port 8888 -war C:\devel\workspace\sample\war -workDir C:\Users\admin\Desktop\gwt-tmp sample.Sample

CodeServerの作業ディレクトリ指定

マニュアルには、-workDirの指定だけでCodeServerの作業ディレクトリ指定がされるとあるのだが、実際にはそうはならない。おそらくバグのようだ。別の方法で指定する必要がある。これには二つある。以下のいずれの方法でもよい。

java.io.tmpdirで指定する

以下のようにVM引数として指定る。

-Djava.io.tmpdir=C:\Users\admin\Desktop\gwt-tmp

を追加すればよい。

環境変数で指定する

以下のようにEnvironmentタブでTMPという環境変数を設定する。

作業ディレクトリに出力されるもの

上記のようにして、Super Dev ModeおよびCodeServerの両方の作業ディレクトリを指定した後は、指定ディレクトリに以下のような出力がされる。赤で囲んだ部分はSuper Dev Modeによるもの、それ以外はCodeServerによるものだ。

もし、最初にあげたCodeServer画面でのcleanで対応できない場合には、この内容を全削除すると良いだろう。

その他のキャッシュ

上記以外にも、プロジェクトフォルダ内に作成されるものがある。Super Dev Modeを使う場合には以下の二つと思われる。

gwt-unitCache

Eclipseプロジェクトのトップに、このフォルダが勝手に現れる。単純に削除すればよい。

warフォルダの「モジュール名」フォルダ

warフォルダ直下の「モジュール名」フォルダ、この場合はsampleを削除する。ここには、ウェブアプリからCodeServerの呼び出しを行うコードが自動で格納されている。

war/WEB-INF/classes

上記画面には表示されていないが、このディレクトリがあるはずだ。ここをEclipseのclass出力先としているからだ。もちろんここにはサーバ用のコードしか無いのだが、上記を試してみてまだおかしければ、これを削除し、プロジェクトを再ビルドしてみることを勧める。

コンパイルする

もちろんこれは最終手段なのだが、コンパイルしてみれば本当にコードに問題があるのかがわかる。

素人が想像してもSuper Dev Modeは相当複雑な仕組みであることが予想されるし、バグも多いのだろう(特にキャッシュ管理については)。コードの問題の有無がわからない場合には、コンパイルしてみるのがよい。

Super Dev Modeでおかしな動きをしていても、(コードが確実であれば)コンパイル済コードの方は間違いなく動作してくれる。

コンパイラのバグと思しきものには。。。以前は確かにあった、全く同じコードを再コンパイルすると動作したりしたのだが、最近のバージョンでは見かけない。