Webアプリの実行時にJavaScriptを圧縮する
Webアプリの公開にあたっては、データ転送量や実行効率の点からJavaScriptを圧縮(minify)して配信することが推奨されています。ここでは実行時に圧縮する方法を説明します。
JavaScriptの圧縮にはGoogle Closure Compilerを利用します。Maven pom.xmlに以下を追記するか、zipアーカイブをダウンロードして配置します。
<dependencies> <dependency> <groupId>com.google.javascript</groupId> <artifactId>closure-compiler</artifactId> <version>r1592</version> <exclusions> <!-- 実行時はAntなくても動く --> <exclusion> <artifactId>ant</artifactId> <groupId>org.apache.ant</groupId> </exclusion> </exclusions> </dependency> </dependencies>
圧縮されたJavaScriptを返すサーブレットは以下のようになります。
public class MinifiedController extends Controller { private static final String JS_SRC = "js/src"; protected void run() throws Exception { List<File> sources = findJavaScriptFiles(JS_SRC); String compiled = compile(sources); response.setHeader(/* キャッシュ制御ヘッダ */); response.setCharacterEncoding("UTF-8"); response.setContentType("text/javascript"); response.getWriter().append(compiled); response.flushBuffer(); } /** * Finds JavaScript files under directories. * * @param directories * @return list of files */ private static List<File> findJavaScriptFiles(String... directories) { FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".js"); } }; List<File> result = new ArrayList<File>(); for (String directory : directories) { File[] files = new File(directory).listFiles(filter); if (files != null) { result.addAll(Arrays.asList(files)); } } return result; } /** * Compiles JavaScript sources. * * @param scripts * @return */ private static String compile(List<File> scripts) { List<JSSourceFile> externs = new ArrayList<JSSourceFile>(); List<JSSourceFile> sources = new ArrayList<JSSourceFile>(); for (File file : scripts) { sources.add(JSSourceFile.fromFile(file)); } Compiler compiler = new Compiler(System.err); compiler.disableThreads(); CompilerOptions options = new CompilerOptions(); Result result = compiler.compile(externs, sources, options); if (!result.success) { throw new RuntimeException("Closure Compiler returned error"); } return compiler.toSource(); } }
ここでは最低限(Whitespace)の圧縮しか行っていませんが、Google Closure Compilerは多彩な最適化オプションを持っています。Compilerクラスの詳しい使い方は CompileTask#execute() が参考になります。
APサーバのフロントにいるWebサーバでリソースがキャッシュされるように設定してください。App Engineの場合は Cache-Control: public, max-age=86400 とかしてフロントエンドでキャッシュされるようにします。
ですが、実はフロントエンドキャッシュは使ってません。キャッシュをexpireさせる契機を制御できないので使いづらいと思いました。上記と同じ仕組みを使って、開発環境の実行時にJavaScriptを圧縮してローカルに保存するようにしています。