Otimizando o carregamento de CSS e JS em aplicações Java com Wro4j

A quantidade de bibliotecas existentes permite desenvolver aplicações cada vez mais ricas e elaboradas. Em contrapartida, a quantidade de arquivos a serem baixados pelo usuário e, consequentemente, o número de requisições realizadas para o servidor aumenta, podendo deixar a aplicação lenta e aumentar o custo envolvendo tráfego de dados, tanto para o usuário final quanto para o mantenedor do sistema.

Há várias técnicas para se diminuir o tempo de carregamento de um site, como o uso de cache, CDNs, uso de versões reduzidas das bibliotecas ou carregamento assíncrono dos arquivos e várias delas são destacadas em ferramentas como o Google PageSpeedTools. No entanto, o objetivo desse artigo é demonstrar como diminuir a quantidade de requisições e dados transmitidos em uma aplicação Java utilizando o Wro4j (Web Resource Optimizer for Java) em tempo de execução.

Para fins demonstrativos, será desenvolvida uma simples aplicação Web com apenas uma página e uso de algumas bibliotecas, permitindo comparar os resultados obtidos antes e depois da inclusão do Wro4j. Os resultados aqui demonstrados possuem apenas fins ilustrativos, já que não estão sendo obtidos de maneira empírica, mas nos permite verificar grandes ganhos usando uma simples ferramenta.

Projeto Inicial

Para início, será criada uma estrutura do nosso projeto utilizando o archetype padrão fornecido pelo Maven:

mvn archetype:generate -DgroupId=com.matera.blog -DartifactId=wro4j -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Listagem 1 – Criação do projeto básico usando o archetype

Dessa forma, o projeto será criado no diretório wro4j, contendo uma simples aplicação Web composta do arquivo de build do Maven (pom.xml), um arquivo jsp (index.jsp) e o descritor da aplicação (web.xml). Essa configuração inicial é suficiente para a geração de um war que, quando instalado em um servidor como o Tomcat e acessado pelo navegador, exibe uma mensagem de “Hello World!”.

Abaixo estão expostos o conteúdo de cada arquivo.

Configuração da build

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.matera.blog</groupId>
  <artifactId>wro4j</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>wro4j Maven Webapp</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>wro4j</finalName>
  </build>
</project>

Listagem 2 – pom.xml contendo a descrição da build, gerada pelo archetype

Conteúdo da Página

<html>
<body>
<h2>Hello World!</h2>
</body>
</html>

Listagem 3 – Arquivo src/main/webapp/index.jsp com o conteúdo da página

Web Descriptor

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
</web-app>

Listagem 4 – Arquivo src/main/webapp/WEB-INF/web.xml

Execução do Tomcat pelo Maven

Para facilitar a validação, será adicionada a configuração do plugin do Tomcat 7[1] na build do projeto. Essa configuração permite que um Tomcat seja executado já apontando para a aplicação.

Configuração do Plugin

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

  <modelVersion>4.0.0</modelVersion>
  <groupId>com.matera.blog</groupId>
  <artifactId>wro4j</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>

  <build>

    <finalName>wro4j</finalName>

    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>

  </build>

</project>

Listagem 5 – Arquivo pom.xml alterado. O código desnecessário foi removido e a configuração do plugin foi adicionada.

Execução do Plugin

Após a configuração, o comando abaixo dispara a execução do plugin[2]:

mvn tomcat7:run-war

Listagem 6 – Comando que inicia o Tomcat apontando para a aplicação

Acesso à aplicação

A aplicação estará acessível a partir da url http://localhost:8080

wro4j-versao-inicialFigura 1 – Screenshot da aplicação padrão sendo executada

Utilização de bibliotecas externas

O código será alterado para utilizar algumas bibliotecas externas, por questões didáticas:

O objetivo é exibir uma imagem que será animada ao clique de um botão. No entanto, detalhes sobre o funcionamento de cada biblioteca não serão abordados.

Conteúdo da Página

<html>
<head>

  <!-- jQuery -->
  <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.js"></script>

  <!-- Bootstrap -->
  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css">
  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap-theme.css">
  <script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js"></script>

  <!-- Font Awesome -->
  <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.css">

  <!-- animate.css -->
  <link rel="stylesheet" href="//cdn.jsdelivr.net/animatecss/3.5.1/animate.min.css">

  <script src="script.js"></script>

</head>

<body>
  <br/><br/>
  <center>
      <img id="logo" src="http://www.matera.com/br/wp-content/uploads/2014/10/Logo_MATERA.png" class="animated"/>
      <br/><br/>
      <a id="btn-animar" class="btn btn-success" href="#"> <i class="fa fa-trash-o fa-lg"></i> Animar</a>
  </center>
</body>

</html>

Listagem 7 – Arquivo src/main/webapp/index.jsp atualizado com a implementação de exemplo

Arquivo javascript

Novo arquivo, contendo código Javascript responsável pelo gerenciamento da animação e do clique no botão:

function animate(element_ID, animation) {
    $(element_ID).addClass(animation);
    var wait = window.setTimeout( function(){
        $(element_ID).removeClass(animation)}, 700
    );
}

$(document).ready(function() {

  $("#btn-animar").click(function() {
    animate("#logo", "jello");
  });

});

Listagem 8 – Arquivo src/main/webapp/scripts.js contendo o javascript referente à aplicação de exemplo

Verificação da aplicação

Após a atualização do código e da aplicação (através do comando exposto acima) o resultado será esse:

wro4j-versao-nao-otimizadaFigura 2 – Screenshot da aplicação de exemplo

Pelas ferramentas de inspeção do navegador é possível perceber que foram realizadas 10 requisições totalizando, aproximadamente, 231KB de dados transferidos:

localhost:8080 - Google Chrome_006Figura 3 – Screenshot das requisições realizadas ao acessar a aplicação de exemplo

Utilização do Wro4j

O Wro4j é uma ferramenta de análise e otimização de recursos Web como CSS e Javascript. Seu uso consiste em, basicamente[3]: adição de um filtro, criação dos grupos e utilização dos recursos otimizados.

A criação dos grupos permite gerar um recurso específico agrupando e compactando vários recursos diversos. Desse modo, ao invés de se utilizar cada recurso individualmente, eles são utilizados de maneira agrupadas.

Adição da dependência

  <dependencies>
    <dependency>
      <groupId>ro.isdc.wro4j</groupId>
      <artifactId>wro4j-core</artifactId>
      <version>1.7.9</version>
    </dependency>
  </dependencies>

Listagem 8 – Adição da dependência ao pom.xml

Configuração do filtro

A configuração do filtro cria uma URL que será gerenciada pelo Wro4j.

  <filter>
    <filter-name>WebResourceOptimizer</filter-name>
    <filter-class>ro.isdc.wro.http.WroFilter</filter-class>
  </filter>

  <filter-mapping>
    <filter-name>WebResourceOptimizer</filter-name>
    <url-pattern>/wro/*</url-pattern>
  </filter-mapping>

Listagem 9 – Configuração do filtro no web.xml

Configuração dos grupos

A criação dos grupos consiste em listar cada recurso, individualmente, dentro de um ou mais grupos. Nesse exemplo está sendo criado apenas um grupo, denominado wro4j, contendo os mesmos arquivos incluídos individualmente em nossa página anteriormente:

<groups xmlns="http://www.isdc.ro/wro">

  <group name="wro4j">

    <!-- jQuery-->
    <js>http://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.0/jquery.js</js>

    <!-- Bootstrap -->
    <css>http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap-theme.css</css>
    <css>http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css</css>
    <js>http://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js</js>

    <!-- Font Awesome -->
    <css>http://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.5.0/css/font-awesome.css</css>

    <!-- animate.css -->
    <css>http://cdn.jsdelivr.net/animatecss/3.5.1/animate.min.css</css>

    <js>/script.js</js>

  </group>

</groups>

Listagem 10 – Configuração do grupo no arquivo src/main/webapp/WEB-INF/wro.xm

Uso dos recursos otimizados

Com a configuração do filtro e do grupo realizada, agora é necessário utilizar o grupo otimizado diretamente na página:

<head>
  <script src="/wro/wro4j.js"></script>
  <link rel="stylesheet" href="/wro/wro4j.css">
</head>

Listagem 11 – Uso dos recursos otimizados na página

Resultados

Com a mesma metodologia utilizada anteriormente, é possível perceber que o número de requisições caiu de 10 para 5 e quantidade de dados transferida caiu de 231KB para 184KB:

localhost:8080-- - Google Chrome_007Figura 4 – Screenshot das requisições realizadas ao acessar a aplicação utilizando os recursos otimizados pelo Wro4j

Conclusão

O uso do Wro4j permite às aplicações Web baseadas em Java realizarem uma primeira otimização no carregamento de seus CSS e JS, dando meios ao desenvolvedor para otimizar o sistema sem a necessidade de utilizar ferramentas externas ou agrupar e compactar os arquivos em um passo adicional do seu processo de build, convergindo diretamente para economia de recursos no servidor e melhoria da experiência do usuário final.

Referências

  1. http://tomcat.apache.org/maven-plugin-2.0/tomcat7-maven-plugin/plugin-info.html
  2. http://tomcat.apache.org/maven-plugin-2.0/tomcat7-maven-plugin/usage.html
  3. https://github.com/wro4j/wro4j

Por MARCO ANTONIO ROCHA

Pai, marido, nerd e programador (não necessariamente nessa ordem). Analista de Sistemas ancorado na MATERA desde 2008. Desenvolvedor Java na maior parte do tempo, fuçador em tempo integral.

Postado em: 01 de fevereiro de 2016

Confira outros artigos do nosso blog

[Webinar] Profile de aplicações Java com Oracle Mission Control e Flight Recorder

24 de julho de 2017

Danival Calegari

Criando Mocks de serviços REST com SoapUI

27 de junho de 2017

Monise Costa

Three laws that enable agile software development

09 de março de 2017

Celso Gonçalves Junior

Medindo performance de uma API REST

21 de fevereiro de 2017

Monise Costa

Deixe seu comentário