-
Notifications
You must be signed in to change notification settings - Fork 22
Maven plugin for web resource optimization
The plugin shows statistic in the output console, e.g.
[INFO] === Statistic ===========================================
[INFO] Size of original resources = 2.709 MB
[INFO] Size of optimized resources = 1.307 MB
[INFO] Optimized resources have 48.23% of original size
[INFO] =========================================================
Another goal and feature of this Maven plugin is creation of Source Maps and handling of Data URIs.
If you're doing front end web development, your web resources such as JavaScript and CSS files might be minificated, transpiled or compiled from a completely different language. If you now want to debug the generated code in the browser, you can not do that because the output code is obfuscated from the code you wrote. The solution is to use source maps. A good introduction to the source map can be found in the articles [Introduction to JavaScript Source Maps](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/) and [Enhance Your JavaScript Debugging with Cross-Browser Source Maps](http://www.sitepoint.com/enhance-your-javascript-debugging-with-cross-browser-source-maps). Currently, the plugin only supports the creation of source maps for JavaScript files. If your generated code is JavaScript, one way to let the development tools know where to look is to add a comment to the end of the generated code which defines the sourceMappingURL - the location of the source map. For example: `//# sourceMappingURL=mylib.js.map` or `//# sourceMappingURL=/mypath/mylib.js.map` or `//# sourceMappingURL=http://sourcemaps/mylib.js.map` If you now open a development tool and the source map support is enabled, the browser will stream down the source map which points to the original file and show the original file instead of generated one (minificated, compiled, transpiled, etc.). Now, you can set a breakpoint in the original file and debug it as it would be delivered with you web application. Such debugging is possible due to the fact that a source map provides a way of mapping code within a generated file back to it's original position in a source file. Data URIs are an interesting concept on the Web. Read ["Data URIs explained"](http://www.nczonline.net/blog/2009/10/27/data-uris-explained/) please if you don't know what it does mean. Data URIs allow any file to be embedded inline within CSS. This technique allows separate elements such as images to be fetched in a single HTTP request rather than multiple HTTP requests, what can be more efficient. Decreasing the number of requests results in better page performance. "Minimize HTTP requests" is actually the first rule of the ["Yahoo! Exceptional Performance Best Practices"](http://developer.yahoo.com/performance/rules.html), and it specifically mentions data URIs. The plugin allows to embed data URIs for referenced images in style sheets. Data URIs are supported for all modern browsers: Gecko-based (Firefox, SeaMonkey, Camino, etc.), WebKit-based (Safari, Google Chrome), Opera, Konqueror, Internet Explorer 8 and higher. For Internet Explorer 8 data URIs must be smaller than 32 KB. Internet Explorer 9 and higher don't have this 32 KB limitation. How does the conversion to data URIs work? Plugin reads the content of CSS files. A special `java.io.Reader` implementation looks for tokens `#{resource[...]}` in CSS files. This is a syntax for image references in JSF 2. Token should start with `#{resource[` and ends with `]}`. The content inside contains image path in JSF syntax. Examples: ```css .ui-icon-logosmall { background-image: url("#{resource['images/logosmall.gif']}") !important; }.ui-icon-aristo { background-image: url("#{resource['images:themeswitcher/aristo.png']}") !important; }
In the next step the image resource for each background image is localized. Images directories are specified according to the JSF 2 specification and suit WAR as well as JAR projects. These are `${project.basedir}/src/main/webapp/resources` and `${project.basedir}/src/main/resources/META-INF/resources`. Every image is tried to be found in those directories.
If the image is not found in the specified directories, then it doesn't get transformed. Otherwise, the image is encoded into base64 string. The encoding is performed only if the data URI string is less than 32KB in order to support IE8 browser. Images larger than that amount are not transformed. Data URIs looks like
```css
.ui-icon-logosmall {
background-image: url("data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgA ... ASUVORK5CYII=") !important;
}
.ui-icon-aristo {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA ... BJRU5ErkJggg==") !important;
}
Supported mime-types are: image/gif
, image/jpeg
and image/png
, so that GIF, JPEG, JPG and PNG images can be converted to data URIs.
The more complex use case is shown below.
<plugin>
<groupId>org.primefaces.extensions</groupId>
<artifactId>resources-optimizer-maven-plugin</artifactId>
<version>2.1.0</version>
<executions>
<execution>
<id>optimize</id>
<goals>
<goal>optimize</goal>
</goals>
</execution>
</executions>
<configuration>
<compilationLevel>ADVANCED_OPTIMIZATIONS</compilationLevel>
<warningLevel>VERBOSE</warningLevel>
<failOnWarning>true</failOnWarning>
<suffix>-min</suffix>
<useDataUri>true</useDataUri>
<resourcesSets>
<resourcesSet>
<inputDir>${project.build.directory}/your_resource_directory_for_js_files</inputDir>
<includes>
<include>**/*.js</include>
</includes>
<excludes>
<exclude>**/jquery.layout.js</exclude> // example of file exclude
<exclude>jquery/**</exclude> // example of directory exclude
</excludes>
</resourcesSet>
<resourcesSet>
<inputDir>${project.build.directory}/your_resource_directory_for_css_files</inputDir>
<includes>
<include>**/*.css</include>
</includes>
<aggregations>
<aggregation>
<outputFile>${project.build.directory}/webapp/resources/${project.artifactId}.css</outputFile>
</aggregation>
</aggregations>
</resourcesSet>
</resourcesSets>
</configuration>
</plugin>
This sample shows how to overwrite default configuration and work with resources sets. You can overwrite default settings: input directory, compilation level, warning level, behavior in case of warnings, file encoding, files to be included / excluded, aggregation rules and desired suffix for minified resources. See the next section for more details. Resources sets are optional and allows more configuration control. In the example above we have two resources sets. One for JavaScript files and one for CSS files. Each resources set can overwrite (redefine) settings for input directory where files are located, compilation level, warning level, includes, excludes and aggregation rules. The first resourcesSet
includes JavaScript files except jQuery files which are usally already minified and can't be compressed with ADVANCED_OPTIMIZATIONS
at the moment. Therefore, they are excluded. You can exclude single files or entire directories. The second resourcesSet
compresses CSS files and merges them to one file according to the tag outputFile
. Merging to one big file is possible from different resourcesSet
as well. Merged content is always appended to an output file if the file already exists. The configuration above also shows how to enable data URI feature. To enable this feature set useDataUri
flag to true
.
The next example demonstrates simple settings for source map configuration.
<plugin>
<groupId>org.primefaces.extensions</groupId>
<artifactId>resources-optimizer-maven-plugin</artifactId>
<version>2.1.0</version>
<configuration>
<sourceMap>
<create>true</create>
<outputDir>${project.basedir}/src/sourcemap/${project.version}</outputDir>
<sourceMapRoot>
https://raw.githubusercontent.com/someproject/master/src/sourcemap/${project.version}/
</sourceMapRoot>
</sourceMap>
</configuration>
...
</plugin>
That means, a compressed file, say timeline.js
, has the following line at the end:
//# sourceMappingURL=https://raw.githubusercontent.com/someproject/master/src/sourcemap/3.2.0/timeline.js.map
The source map timeline.js.map
has the content:
{
"version":3,
"file":"timeline.js",
"lineCount":238,
"mappings":"A;;;;;;;;;;;;;;;;;;;;AA4DqB,WAArB,GAAI,MAAOA,MAAX,GACIA,KADJ,CACY,EADZ,CAUsB,...
"sources":["timeline.source.js"],
"names":["links","google","undefined","Array","prototype","indexOf","Array.prototype.indexOf",...]
}
If the browser development tools has identified that the source map is available, it will be fetched along with referenced uncompressed source file timeline.source.js
. The source file appears in the development tools, you can set breakpoint(s) and debug it. Note: the value of the create
tag can be set to false
for development and to true
for release via a Maven property.
Tag | Type | Default value | Description |
inputDir | File | ${project.build.directory}/webapp | Input directory. Command-line parameter is "inputDir". |
compilationLevel | String | SIMPLE_OPTIMIZATIONS | Compilation level. Possible values are: WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS. Command-line parameter is "compilationLevel". |
warningLevel | String | QUIET | Warning level. Possible values are: QUIET, DEFAULT, VERBOSE. To understand errors und warnings see this reference. Command-line parameter is "warningLevel". |
encoding | String | UTF-8 | Encoding to read files. Note: output files are ASCII encoded to avoid issues with proxy-servers. Command-line parameter is "encoding". |
failOnWarning | boolean | false | Flag whether this plugin must stop/fail on warnings. |
suffix | String | null | Suffix for compressed / aggregated files. |
useDataUri | boolean | false | Flag if images referenced in CSS files should be converted to data URIs. |
includes | String[] | {"**/*.css", "**/*.js"} | Files to be included. Files selectors follow patterns specified in org.codehaus.plexus.util.DirectoryScanner. |
excludes | String[] | empty array | Files to be excluded. Files selectors follow patterns specified in org.codehaus.plexus.util.DirectoryScanner. |
aggregations | Aggregation[] | null | Aggregations describing configurations how the files have to be aggregated to one big file (outputFile mode, s. below) or less files (subDirMode mode, s. below). |
sourceMap | SourceMap | null | Configuration of the source map for all resource sets. See more details below. |
resourcesSets | List<ResourcesSet> | null | List of resource sets describing resources to be processed (s. below) |
- If the same parameter was configured in
configuration
directly, the value of this parameter inresourcesSet
takes precedence (overwrites the corresponding value inconfiguration
). - If a parameter is missing in
resourcesSet
, the value of the corresponding parameter inconfiguration
will be taken into account.
Tag | Type | Default value | Description |
inputDir | File | null | Input directory for this resource set. |
compilationLevel | String | null | Compilation level. Possible values are: WHITESPACE_ONLY, SIMPLE_OPTIMIZATIONS, ADVANCED_OPTIMIZATIONS. |
warningLevel | String | null | Warning level. Possible values are: QUIET, DEFAULT, VERBOSE. To understand errors und warnings see this reference. |
useDataUri | boolean | false | Flag if images referenced in CSS files should be converted to data URIs. |
includes | String[] | null | Files to be included. Files selectors follow patterns specified in org.codehaus.plexus.util.DirectoryScanner. |
excludes | String[] | null | Files to be excluded. Files selectors follow patterns specified in org.codehaus.plexus.util.DirectoryScanner. |
aggregations | Aggregation[] | null | Aggregations describing configurations how the files have to be aggregated to one big file (outputFile mode, s. below) or less files (subDirMode mode, s. below). |
sourceMap | SourceMap | null | Configuration of the source map for this resource set. See more details below. |
- If a parameter is missing in
aggregation
, the value of the corresponding parameter inresourcesSet
will be taken into account. - If a parameter is missing in
resourcesSet
, the value of the corresponding parameter inconfiguration
will be taken into account. - If the same parameter was configured in
resourcesSet
andconfiguration
, the value of this parameter inresourcesSet
takes precedence.
Tag | Type | Default value | Description |
inputDir | File | null | Input directory for this aggregation. This allows to define different directories to aggregate compressed and not compressed files simultaneously, at the same time. This makes sense if you have "production" and "development" modes and would like to use uncompressed files in the "development" mode. Uncompressed files can be better debugged and produce better error messages. See the next section with examples how to do such configuration. |
subDirMode | boolean | false | Aggregation per sub-folder. Names of aggregated files should be the same as their folder names where they are placed. Files are aggregated in the lexicographic order. If you want to aggregate files in the pre-defined order, you shoud give all files proper names. It's a good practice to use prefixes to sort them lexicographically. E.g. 0-firstfile.js, 1-seconfile.js, 2-thirdfile.js. See the next section with examples how to do such configuration. |
removeIncluded | boolean | true | Flag whether included original files must be removed. |
withoutCompress | boolean | false | Flag whether included files must be compressed or not. |
outputFile | File | null | Output file for aggregation to one big file. |
prependedFile | File | null | File to be prepended to the aggregated file. |
subDirMode
is probably one of the most benefits of this plugin for modular software. Resources of each module can be optimized separately in an easy way. It makes sense e.g. for component / widget development. Developers can write their scripts / cascading style sheets well-arranged and as much as they want (for better maintenance) - all files will be combined during project build. Web pages should reference combined files from the start of course.
- If a parameter is missing in
sourceMap
configured forresourcesSet
, the value of the corresponding parameter inconfiguration
will be taken into account. - If the same parameter was configured in
resourcesSet
andconfiguration
, the value of this parameter inresourcesSet
takes precedence.
Tag | Type | Default value | Description |
create | boolean | false | Boolean flag if the source map should be created. |
sourceMapRoot | String | null | Path to the location of source maps and original source files. The path is prepended to the file name in the source mapping URL declaration //# sourceMappingURL which is appended to all minified files of corresponding resource set. The default value null means nothing will be prepended. |
outputDir | String | ${project.build.directory}/sourcemap/ | Output directory for created source maps and original source files. |
detailLevel | String | V3 | Source maps details level as Enum name. See com.google.javascript.jscomp.SourceMap.DetailLevel. |
format | String | ALL | Source maps format as Enum name. See com.google.javascript.jscomp.SourceMap.Format. |
/* float clearing for IE7 */
-
- html .ui-module { min-height: 1%; }
A solution is simple - remove comments `/* .... */`.