スマホ向けのブラウザサービスは、モバイル回線で画像などのリソースを大量にやりとりするので、通信のもたつきを感じることが多いです。
ある時、さすがに読み込みが遅いと感じて、JavaScriptとCSSのリソースの容量を確認したら、11ファイルで742KBになっていました。
そこで、JavaScriptとCSSを圧縮することにしました。
wro4jで全てのファイルをminifyする。
まずは、よくminifyと呼ばれることをしました。
minifyとは、JavaScriptやCSSの動作に影響を与えない範囲で、不要なコメント文や空白文字を除去したり、変数名の文字数を減らしたりする処理です。
Javaには、wro4jと呼ばれるリソース圧縮ツールがあるので、これを使いました。
wro4j – Web Resource Optimizer for Java – wro4j – Google Project Hosting
wro4jは、Mavenプラグインとして導入し、ビルド時にリソースの圧縮をかけられるようにしました。
<plugin> <groupId>ro.isdc.wro4j</groupId> <artifactId>wro4j-maven-plugin</artifactId> <version>1.7.0</version> <configuration> <minimize>true</minimize> <cssDestinationFolder>${project.basedir}/src/main/webapp/css/</cssDestinationFolder> <jsDestinationFolder>${project.basedir}/src/main/webapp/js/</jsDestinationFolder> <contextFolder>${project.basedir}/src/main/webapp/</contextFolder> <wroFile>${project.basedir}/src/main/webapp/WEB-INF/wro.xml</wroFile> <wroManagerFactory>ro.isdc.wro.extensions.manager.standalone.GoogleStandaloneManagerFactory</wroManagerFactory> </configuration> <executions> <execution> <phase>compile</phase> <goals> <goal>run</goal> </goals> </execution> </executions> </plugin> |
JavaScriptとCSSは、wro4jによって複数ファイルの結合とminifyをすることが可能です。どのファイルを圧縮するかの設定は、wro.xmlという設定ファイルに、たとえば次のように書きます。
<?xml version="1.0" encoding="UTF-8"?> <groups xmlns="http://www.isdc.ro/wro" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.isdc.ro/wro wro.xsd"> <group name="main"> <js>/js/templates.js</js> <js>/js/app.js</js> </group> </groups> |
これだけでJavaScriptなどは、20〜30%くらいは容量を削減することができます。
さらにJettyの設定でレスポンスをgzip化する。
CSSは、minifyの効果があまり大きくありません。なぜなら、類似のスタイルをまとめる構文がないので、必然的に反復記述を減らせないためです。
そこで更に、HTTPの通信の際に、レスポンスボディを丸ごとgzipで圧縮します。
サーブレットコンテナにJettyを使っている場合の例です。
Jetty – Servlet Engine and Http Server
jsファイル、cssファイルのマッピングを org.eclipse.jetty.servlet.DefaultServlet にし、gzipパラメータをtrueにすることでgzip転送を利用できるようになります。
<servlet> <servlet-name>gzipServlet</servlet-name> <servlet-class>org.eclipse.jetty.servlet.DefaultServlet</servlet-class> <init-param> <param-name>gzip</param-name> <param-value>true</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>gzipServlet</servlet-name> <url-pattern>/js/*</url-pattern> <url-pattern>/css/*</url-pattern> </servlet-mapping> |
意外と単純です。
事前にgzipファイルを用意しておく必要がある
このJettyのサーブレットによる、gzip転送は、HTTPのリクエストをされるごとにgzip圧縮をするわけではありません。
そのため事前に、非圧縮のファイルとgzip圧縮されたファイルを用意しておく必要があります。
$ ls ./js/ app.js main.js main.js.gz templates.js |
こんな風に、main.jsと並列にmain.js.gzを配置しておくことで、gzipされたファイルをレスポンスしてくれます。
ちなみに、両方置いておく必要がある理由は単純です。gzip圧縮による通信に対応していないブラウザが存在するためです。
HTTP通信の際には、gzip圧縮による通信ができるかをリクエストヘッダに添えるので、これを見て、main.js.gzを返すのか、main.jsを返すのかを判断します。
GET / HTTP/1.1 Host: example.com ... Accept-Encoding: gzip, deflate ...
gzip圧縮されたファイルが用意されていない場合は、ヘッダに関わらず非圧縮のファイルが返されます。
結果、79%も削減できた。
minifyとgzip圧縮によって、容量を742KBから159KBに79%も削減することができました!
モバイルの低速回線だとかなりの体感の差になると思います。
One comment
Pingback: JavaScriptやCSSの開発工程を自動化するGruntとは何か? | 三度の飯とエレクトロン