Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to minify a filtered javascript file using maven?

I have a javascript file that is used to track events using Google analytics. I have created different accounts for the staging and production environment. The script to invoke GA code has a place holder for my account Id. The account Ids have been specified in the filter files. Using the webResources element in the maven-war plugin, we are able to successfully replace the property in the final WAR file.

Now, we are also using maven-yuicompressor plugin to minify and aggregate all our javascript files. The problem is that if I attach the execution of minify goal to the package phase, the WAR is created before the Javascript has been minified. If I attach the minify goal to anything earlier, the filter has been not applied till the time of minification producing an invalid file.

So, I am looking for a way to run the minify goal between the WAR plugin copying the filtered JS files and creating the WAR file. Here are the relevant portions of my pom.xml:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-war-plugin</artifactId>
            <version>2.1.1</version>
            <configuration>
              <webResources>
                <resource>
                  <directory>src/main/webapp/js</directory>
                  <targetPath>js</targetPath>
                  <filtering>true</filtering>
                </resource>
              </webResources>
            </configuration>
          </plugin>
          <plugin>
            <groupId>net.alchim31.maven</groupId>
            <artifactId>yuicompressor-maven-plugin</artifactId>
            <version>1.1</version>
            <executions>
              <execution>
                <goals>
                  <goal>compress</goal>
                </goals>
                <phase>package</phase>
              </execution>
            </executions>
            <configuration>
              <linebreakpos>-1</linebreakpos>
              <nosuffix>true</nosuffix>
              <force>true</force>
              <aggregations>
                <aggregation>
                  <output>${project.build.directory}/${project.build.finalName}/js/mysite-min.js</output>
                  <inputDir>${project.build.directory}/${project.build.finalName}/js</inputDir>
                  <includes>
                    <include>jquery-1.4.2.js</include>
                    <include>jquery-ui.min.js</include>
                    <include>ga-invoker.js</include>
                  </includes>
                </aggregation>
              </aggregations>
            </configuration>
          </plugin>
like image 503
Chandranshu Avatar asked May 20 '11 08:05

Chandranshu


2 Answers

Great question, great anwser by artbristol, which i voted up. It helped me a lot. For future reference i post a complete solution:

  • Put your Javascript files into src/main/resources/js (or whatever fits your needs)
  • Put your CSS files into src/main/resources/css (or whatever fits your needs)
  • Resources plugin is filtering your javascript resources and copies them to target/classes/js/
  • Yui is picking up the files at target/classes/js/ and aggregates them to src/main/webapp
  • You can test your setup with jetty:run. Jetty is picking up the compressed and aggregated files in src/main/webapp
  • war plugin at package phase is picking up your files under src/main/webapp
  • optional put a SCM ignore file like .svnignore or .cvsignore file into src/main/webapp to exclude all.js from your favourite SCM tool.

The excludes section is necessary to avoid compressing anything in src/main/resources and src/main/webapp. yui should just pickup already filtered files for aggregation.

<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <filtering>true</filtering>
        </resource>
    </resources>
    <plugins>
        <plugin>
            <groupId>net.alchim31.maven</groupId>
            <artifactId>yuicompressor-maven-plugin</artifactId>
            <version>1.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>compress</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <excludes>
                    <exclude>*/*</exclude>
                </excludes>
                <force>true</force>
                <nosuffix>true</nosuffix>   
                <removeIncluded>true</removeIncluded>
                <aggregations>
                    <aggregation>
                        <insertNewLine>true</insertNewLine>
                        <output>${project.basedir}/src/main/webapp/js/all.js</output>
                        <includes>
                            <include>${project.build.directory}/classes/js/file1.js</include>
                            <include>${project.build.directory}/classes/js/file2.js</include>
                    </aggregation>
                    <aggregation>
                        <insertNewLine>true</insertNewLine>
                        <output>${project.basedir}/src/main/webapp/css/all.css</output>
                        <includes>
                            <include>${project.build.directory}/classes/css/file1.css</include>
                            <include>${project.build.directory}/classes/css/file2.css</include>
                    </aggregation>
                </aggregations>
            </configuration>
        </plugin>

Why would you want filtering of css files?

i use it to reference my images like this

div.header {
  background-image: url(/img/background.${project.version}.png)
}

Maven filters my project version into my css files. Any incoming request on our imageserver is filtered like this

protected void doHttpFilter ( HttpServletRequest request, HttpServletResponse response, FilterChain chain ) throws IOException, ServletException
{
    String uri = request.getRequestURI();
    if (isStaticRequest(uri))
    {
        String uriWithoutVersion = stripVersionString(uri);
        String versionRequested = getVersionString(uri);
        if (version.equals(versionRequested))
        {
            response.setHeader(CACHE_CONTROL_HEADER_NAME, CACHE_CONTROL_HEADER_VALUE);
            response.setHeader(EXPIRES_HEADER_NAME, EXPIRES_HEADER_VALUE);
        }
        RequestDispatcher dispatcher = request.getRequestDispatcher(uriOhneVersionsnummer);
        dispatcher.forward(request, response);
    } else {
        chain.doFilter(request, response);
        return;
    }
}

this way the browser caches each file forever. but when i upload a new version all file reference have a new version number, so the browser is fetching the image or css again. this helped us a lot to reduce traffic.

like image 128
Janning Avatar answered Sep 17 '22 08:09

Janning


Can you put the filtered js files in src/main/resources/filtered-js, use the resources plugin instead, which binds to process-resources, then point the webresources config of the maven-war-plugin to target/classes/filtered-js?

like image 24
artbristol Avatar answered Sep 19 '22 08:09

artbristol