Skip to content
This repository was archived by the owner on Nov 23, 2018. It is now read-only.
roblarsen edited this page May 1, 2012 · 32 revisions

The build script

The build script is a tool that optimizes your code for production use on the web.

Why use it?

Faster page load times and happy end users :)

What it does

  • Combines and minifies javascript (via yui compressor)
  • Inlines stylesheets specified using @import in your CSS
  • Combines and minifies CSS
  • Optimizes JPGs and PNGs (with jpegtran & optipng)
  • Removes development only code (any remaining console.log files, profiling, test suite)
  • Basic to aggressive html minification (via htmlcompressor)
  • Autogenerates a cache manifest file (and links from the html tag) when you enable a property in the project config file.
  • Revises the file names of your assets so that you can use heavy caching (1 year expires).
  • Upgrades the .htaccess to use heavier caching
  • Updates your HTML to reference these new hyper-optimized CSS + JS files
  • Updates your HTML to use the minified jQuery instead of the development version
  • Remove unneeded references from HTML (like a root folder favicon)
  • Runs your JavaScript through a code quality tool (optional)

##How to Use it

Running JSHint and JSLint

Optionally, you can have the build script run your JavaScript files through JSHint or JSLint to help detect errors or potential problems. This is not necessary for any of the other build options, and build failure when running these targets only means that errors were found during the quality check. To run, simply specify one of the following:

ant build jshint
ant build jslint

JSHint and JSLint can both be configured with a variety of options. The defaults can be found in the default.properties file, and you can override them in project.properties. See http://jshint.com/ and http://www.jslint.com/lint.html for more information.

Note that these targets are set to exclude any JavaScript files ending in ".min.js", as well as files located within the js/libs directory.

Running CSSLint

You can check if your CSS files have any issues by running your files through CSSLint and detecting potential problems (note that CSSLint parser is not perfect and has bugs). Build failure when running these targets only means that errors were found during the quality check of your stylesheet. To run, use:

ant build csslint

Hooking your assets up to a CDN

Read this guide by Justin Ribeiro on CDN'ing your build script

Advanced Tasks

The following require a bit more work, often touching on editing or creating tasks in the build.xml itself

(new) Inlining @imports

Splitting style.css

Running the ant command ant css-split from the build directory will split the monolithic style.css file that you're familiar with into multiple css files. It then renames itself to style.css.orig and creates a new style.css that @imports the newly split files.

This is done via special marker comments (ex: ==|== filename ====), so if you're merging from a personal version of style.css, make sure to include these markers.

If everything went correctly you should see no difference in the behavior of your pages. The browser should follow the @import directives and load all your CSS.

Importing Rules

Browser rules for @imports are very strict. They must follow any @charset rules and come before anything else. Any @imports that follow other blocks in the .css file will be ignored by the browser. The build script isn't this strict, but if you want to maintain browser compatibility you should adhere to these rules.

w3.org @import rules

Building with Imports

Now whenever the build script is creating a publish directory for you it will attempt to bring in any @import directives it finds to create a single concatenated and minified css file. This makes it easier for you to add and remove blocks of functionality from your .css during development, while keeping the benefits of a single http GET when deployed.

  • If you are adding your own @imports you should make the path relative to the .css you are adding the @import to.
  • @import URLs that start with http: or https: won't be inlined, because it is assumed that these are meant to change independent of the file importing them.
  • @import URLs that start with http: or https: need to come before any @imports that will be inlined, otherwise they will break (see the strict rules above).
  • You can specify media types after an @import (ex: @import url('print.styles.css') print;). The build script will wrap these in an @media [type]{[file contents]} block.

Compiling LESS CSS (http://lesscss.org/)

The build script can now optionally compile your LESS code into CSS ready for use on a production site. Currently the script will only work on LESS code in your main stylesheet, so if you want to process more than one stylesheet you must use @import references in this file.

To enable the LESS compiler, in project.properties your must set file.root.stylesheet to the name of your LESS stylesheet and build.css.less to true.

Example project.properties

...
file.root.stylesheet = style.less
build.css.less = true
...

Now when you run ant your LESS code will be compiled, and as it replaces the main stylesheet your code will also be minified and have a new hashed filename.

Tidying up LESS references in your HTML

To make the build script remove references to your LESS JavsScript from your HTML wrap it in a comment block like so.

<!-- less script -->
  <script>var less = { env: ‘development’ };</script>
  <script src="js/vendor/less-1.3.0.min.js"></script>
<!-- end less script -->

The build script will also change the rel attribute of your main stylesheet link to stylesheet from stylesheet/less.

Some notes

  • The build script makes some assumptions about how your javascript files are sorted.
    • /js/libs/ contains files from boilerplate. These are minified but not concatenated with others. Modernizr should be alone in the head. jQuery might be pulled off the CDN.
    • plugins.js and script.js in the /js/ folder are all yours. These will also be minified and concatenated.
  • When the build script changes your HTML to reference the new minified script (with an neat 7-character SHA-1 hash) it looks for some HTML comments which refer to the beginning and end of the script block. Currently it looks for <!-- scripts concatenated and <!-- end scripts-->. If you change or strip these comments, the build script will kinda die. :)
  • It likes your filename extensions to be lowercase. Some things might be skipped if you use a .JPG extension, for example.
  • Right now, the build.xml et al all have to be in the ./build/ folder. You can't rename it.
  • Although not officially supported, it is possible to set the publish directory to a relative path outside the project folder. This is useful for generating a snapshot onto a staging server, for instance. In order to do so, set the publish directory to a path relative to the project: dir.publish = ../mysite/. Then tell the htmlcompressor script to put the files back where it found them, instead of defining a specific directory. In build.xml, this line <mapper type="glob" from="*" to="../${dir.publish}/*"/> becomes this line <mapper type="glob" from="*" to="*"/>.
  • Intermediate stages are stored in a new intermediate folder, and only files that should be published are copied into the publish folder.
  • Files are not deleted at the beginning of every build, and files that have already been processed will not be reprocessed unless the source has changed.
  • Versioned files are referenced by a SHA-1 hash of the content rather than a build number. This means that changing your HTML and rebuilding will not cause your users to redownload the same CSS and Javascript, and a reverted change may cause users to use a copy that was previously downloaded. It may be better to use only part of the hash so the HTTP request is shorter.

Platforms

It should work fine on Windows, Mac and Linux. We are committed to this working cross-platform.

Dependencies

On Linux/Mac, the image tasks assume you have jpegtran (part of the libjpeg-progs package http://www.ijg.org/) and optipng (http://optipng.sourceforge.net/) installed and on your path. The binaries are included for Windows users.

On Mac OSX

Using homebrew, install the following packages:

brew install libjpeg optipng

Using MacPorts, install the following packages:

port install jpeg optipng

On Ubuntu

Using apt, install the following packages:

apt-get install libjpeg-progs optipng

Easy VCS-based deployment

Check out the entire repo incl the build/ folder onto your server.

Then go into build/ and run ant.

Then drop this into the top of your .htaccess:

RewriteEngine On
RewriteCond $1 !^yourapp/publish/
RewriteRule ^(.*)$ yourapp/publish/$1 [L]
# and change yourapp to your actual checkout folder name

This allows you to serve a subfolder as if its the root of your site. So now to update production you can just to do a git pull && cd build && ant build or what have you, whenever you want it updated.

Troubleshooting

Build Script users - On occasion, your site may not render in browser exactly as it did using the original code. In this case, you may have poorly constructed JavaScript or CSS in your original directory. Oftentimes, plugins are to blame.

  • Debug in your browser developer tool of choice.
  • Check your console tab within the dev tool. This should tell you on which line you can find the error.
  • Once you have successfully debugged the error within your original directory, go back to terminal and rerun the build script. Refresh the site in your browser. If it looks good, you're ready for the WWW! :)

If you are using Ubuntu Linux and receiving the following error when running ant:

Unable to locate tools.jar. Expected to find it in /usr/lib/jvm/java-6-openjdk/lib/tools.jar

See this blog post for how to resolve the problem.


If you receive the following errors:

  BUILD FAILED
  build.xml:136: The following error occurred while executing this line:
  build.xml:441: concat doesn't support the "overwrite" attribute

This is because versions of Ant prior to 1.8.2 do not support the overwrite="no" attribute.

You will need to either upgrade to a later version of Ant or remove all of the occurrences of overwrite="no" from the build.xml file.

Clone this wiki locally