Aggregation

Good practice :

  • on web, is to download/call one big js file instead of several small files.
  • in source code organisation is to have unit file (with one "concern").

The major js and css framework/lib provide source code in both version (one big, lot of small), or provide a online tool to generate the big.

The following option allow you to use/store small files into your source and generate the big at build time. The aggregation is done after yuicompression

Basic sample

To Compress every js and css files and aggregate every js file under ${project.build.directory}/${project.build.finalName}/static/ into all.js :

<project>
...
  <build>
    <plugins>
...
      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>yuicompressor-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compress</goal>
            </goals>
          </execution>
        </executions>        
        <configuration>
          <nosuffix>true</nosuffix>
          <aggregations>
            <aggregation>
              <!-- remove files after aggregation (default: false)
              <removeIncluded>true</removeIncluded>
              -->
              <!-- insert new line after each concatenation (default: false) -->
              <insertNewLine>true</insertNewLine>
              <output>${project.build.directory}/${project.build.finalName}/static/all.js</output>
              <!-- files to include, path relative to output's directory or absolute path-->
              <!--inputDir>base directory for non absolute includes, default to parent dir of output</inputDir-->
              <includes>
                <include>${basedir}/src/licenses/license.js</include>
                <include>**/*.js</include>
              </includes>
              <!-- files to exclude, path relative to output's directory
              <excludes>
                <exclude>**/*.pack.js</exclude>
                <exclude>**/compressed.css</exclude>
              </excludes>
              -->
            </aggregation>
          </aggregations>
        </configuration>
      </plugin>
...
    </plugins>
  </build>
...
</project>
 

Removing included files

Using removeIncluded option, remove file, but the war plugin will then add file. So if you want to remove file after aggregation and don't want war plugin copy them, then you need to use warSourceExcludes :

<project>
...
  <build>
    <plugins>
...
      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>yuicompressor-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compress</goal>
            </goals>
          </execution>
        </executions>        
        <configuration>
          <nosuffix>true</nosuffix>
          <aggregations>
           <aggregation>
              <!-- remove files after aggregation (default: false) -->
              <removeIncluded>true</removeIncluded>
              <!-- insert new line after each concatenation (default: false) -->
              <insertNewLine>true</insertNewLine>
              <output>${project.build.directory}/${project.build.finalName}/static/all-2.js</output>
              <!-- files to include, path relative to output's directory -->
              <includes>
                <include>toAggregateAndRemove/**.js</include>
              </includes>
            </aggregation>
          </aggregations>
        </configuration>
      </plugin>
...
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
          <warSourceExcludes>**/toAggregateAndRemove/**</warSourceExcludes>
        </configuration>
      </plugin>
...
    </plugins>
  </build>
...
</project>
 

Adding header (copyright)

When aggregating minified js files, the copyright headers have been stripped out which is fine because we don't want to repeat it several times in the output file. However it would be great to be able to insert one at beginning of output file.

For simple cases, the maven-license-plugin is enough if you use the same header for all files but it is not enough if you want to have a different header per aggregation (different libraries with different licensing schemes).

  1. you put license header in its own file (ex license_js.txt)
  2. aggregate a license header to minified files.
  <includes>
    <include>${project.build.sourceDirectory}/../webapp/js/mylib/copyright.txt</include>
    <include>mylib/**/*.js</include>
  </includes>
 

Adding filename headers

When aggregating minified js or css files, the file headers have been stripped out. However it would be great to be able to easily identify the corresponding input files when looking at the aggregated file.

<project>
...
  <build>
    <plugins>
...
      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>yuicompressor-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compress</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <aggregations>
           <aggregation>
              <!-- insert new line after each concatenation (default: false) -->
              <insertNewLine>true</insertNewLine>
              <!-- insert file header before each aggregated file (default: false) -->
              <insertFileHeader>true</insertFileHeader>
              <output>${project.build.directory}/${project.build.finalName}/static/all-3.js</output>
              <!-- files to include, path relative to output's directory -->
              <includes>
                <include>**/*.js</include>
              </includes>
            </aggregation>
          </aggregations>
        </configuration>
      </plugin>
...
    </plugins>
  </build>
...
</project>
 

Automatically exclude wildcard matches that were included in previous aggregations

When multiple aggregations are defined for the same type of file, such as css, it can be tedious to maintain matching exclusions on the final aggregation which uses a wildcard inclusion. It would be convenient to automatically exclude wildcard matches that have been included in previous aggregations.

<project>
...
  <build>
    <plugins>
...
      <plugin>
        <groupId>net.alchim31.maven</groupId>
        <artifactId>yuicompressor-maven-plugin</artifactId>
        <executions>
          <execution>
            <goals>
              <goal>compress</goal>
            </goals>
          </execution>
        </executions>
        <configuration>
          <aggregations>
           <aggregation>
              <output>${project.build.directory}/${project.build.finalName}/static/IE.css</output>
              <!-- files to include, path relative to output's directory -->
              <includes>
                <include>**/IE*.css</include>
              </includes>
            </aggregation>
           <aggregation>
              <!-- exclude any wildcard matches that have been included by prior aggregations (default: false) -->
              <autoExcludeWildcards>true</autoExcludeWildcards>
              <output>${project.build.directory}/${project.build.finalName}/static/everything-except-IE.css</output>
              <!-- files to include, path relative to output's directory -->
              <includes>
                <include>**/*.css</include>
              </includes>
            </aggregation>
          </aggregations>
        </configuration>
      </plugin>
...
    </plugins>
  </build>
...
</project>