(Quick Reference)

4 Usage - Reference Documentation

Authors:

Version: 3.2.1

4 Usage

Asset-Pipeline automatically creates a series of folders within your grails-app directory:

grails-app/assets/javascripts
grails-app/assets/images
grails-app/assets/stylesheets

Place your static assets in those directories and simply include them in your layouts.

Setting up Manifests

Example grails-app/assets/javascripts/application.js:

//This is a JavaScript file with its top level require directives
//= require jquery
//= require app/models.js
//= require_tree views
//= require_self

console.log("This is my javascript manifest");

The above is an example of some of the require directives that can be used. Custom directives can be created and overridden into the DirectiveProcessor class.

These directives can be used across ALL of your files. A dependency graph is built from the recursive require tree and a proper order is determined.

Optionally, assets can be excluded from processing if included by your require tree. This can dramatically reduce compile time for your assets. To do so, simply leverage the excludes configuration option:

grails.assets.excludes = ["tiny_mce/src/*.js"]

Or Exclude at the plugin level:

grails.assets.plugin."twitter-bootstrap".excludes = ["**/*.less"]
grails.assets.plugin."twitter-bootstrap".includes = ["bootstrap.less"]

The above will tell asset-pipeline not to precompile less files individually within the twitter-bootstrap plugin, but will compile bootstrap.less.

It is also possible to exclude files from minification

grails.assets.minifyOptions.excludes = ["**/*.min.js"]

Partials

Another piece of information to know is that files that are prefixed with _ Are not compiled individually by the asset-pipeline. These files are considered partials and should be required into another manifest file for compilation. If, in the event, you need to add these files back to the precompile phase you can define a global includes property like so.

grails.assets.includes = ["**/_*.*"]

Including Assets in Views

Asset pipeline provides several new tag libs for including JavaScript and CSS into your GSP files. For example:

<head>
    <asset:stylesheet href="application.css"/>
    <asset:javascript src="application.js"/>
    <asset:link rel="shortcut icon" href="favicon.ico" type="image/x-icon"/>
</head>

These helpers will automatically adjust to point to the cache-digested versions of the files when running in a non-development environment.

In development mode your stylesheets and scripts will be included as individual script tags. This is intended to make it easier for debugging. Bundling is enabled in all other environments and can be forced in development mode by adding grails.assets.bundle=true to your Config.groovy or setting the bundle="true" attribute on the taglib.

Using with Plugins

Asset pipeline makes it easy to serve assets from within plugins. It's actually quite simple. The grails-app/assets, and web-app (for legacy plugin support) folders from all plugins are considered include paths. Essentially, when a file is requested (e.g. jquery.js), the Asset-Pipeline first will check the local applications assets folder. If not found there, it will scan through all the installed plugins and serve the requested file. This has the added benefit of allowing you to override a plugins copy of a JavaScript file in your local project.

Using with Stylesheets

Asset Pipeline now automatically tries to convert relative URLs specified in your CSS files to absolute paths. This makes it easier to use third party libraries within the Asset-Pipeline stack.

Precompiling for Production

Assets are now automatically precompiled into target/assets when you create a war file. This should further simplify the deployment process. During WAR creation, only the changed assets are compiled making your precompiler phase a bit quicker. If, for any reason, you want to ensure a clean assets folder, feel free to run grails asset-clean.

During WAR build your assets are also minified using Closure Compiler. To disable this feature, you can add the following option to your config:

grails.assets.minifyJs = false

Serving Assets from External Storage Directory

Asset Pipeline can be configured to copy your assets files out to an external storage path. This can be useful for setting up your web server (e.g. nginx) to directly serve your static assets. To do so, simply define a config variable in your Config.groovy environment block.

environments {
    production {
        grails.assets.storagePath = "/full/path/to/storage"
    }
}

It is also possible to configure a custom CDN asset URL for serving these assets:

environments {
    production {
        grails.assets.url = "http://s3.amazonaws.com/asset-pipe/assets/"
    }
}

Custom Files

Asset Pipeline uses classes of type AssetFile. By default, this plugin comes with a JsAssetFile, and CssAssetFile. These define the match pattern syntax for understanding requires directives, known extensions, processors, and content-type. The application bases its file look-up on content-type of the request rather than extension. This allows the user to maybe define a CoffeeAssetFile with the JavaScript content type and a request to localhost/assets/app.js would be able to find assets/app.coffee. To add custom file definitions you must add the definition in 2 locations:

Create a META-INF/asset-pipeline/asset.specs file with the name of your class file (line seperated) to be added to the list of valid implementations. For more information check out the section on extending the asset-pipeline.

4.1 Manifests and Directives

Asset Pipeline controls asset depdencency by using a custom syntax with commands called "directives". These directives give more fine grained control over what needs included as well as load order.

Manifest Files

In the Grails asset pipeline, the concept of a manifest file exists. This is typically the root/parent JavaScript or CSS file which requires all of your application code. This file is then included into your application with a taglib. Another comparison that can be made here is to the 'Resources Plugin' modules; the difference being, your manifest is kept within the source code of your JavaScript or CSS rather than within a separate file you keep having to jump back to.

An example JavaScript manifest called 'application.js' might look like this:

//= require jquery/jquery
//= require_self
//= require_tree .
//= require_full_tree .

Or an example stylesheet syntax may look like this:

/*
*= require_self
*= require header
*= require navigation
*= require_tree .
*= require_full_tree .
*= encoding UTF-8
*/

Directives

DirectiveMeaning
requireIncludes a single file into the manifest
require_treeRecursively includes all files and subdirectories in the path
require_selfInserts the body of the current file
require_full_treeInclude files from all plugins that contain the relative base path
encodingSet the processor encoding for this bundle (i.e. UTF-8 or ANSI or Latin1)

In JavaScript files, the directive begins with '//='. These directives tell us which files should be injected into this JavaScript file and in what order.

The require_tree directive will tell asset-pipeline to recursively include all JavaScript in the specified directory. This will include JavaScript sorted in alphabetical order, but the ordering of this type of require should not be relied upon. You can adjust the require order of the require_tree directive by using directives within any sub-JavaScript file. For example, lets say we have a folder called 'models' with a Book and an Author. Let's go further and say we want to ensure the Book model requires author first in a require_tree. This can be done by simply adding "//=require author" at the top of book.js file.

The require_full_tree directive is an additional directive similar to require_tree except that it will include files from all plugins that contain the relative base path. This is helpful when developing an application that is split into multiple plugins.

The require_self directive allows you to control where in the manifest the contents of the current file should reside. If the require_self directive is not specified, the contents of the current file are appended to the end of the manifest.

In the examples above, 2 different directive prefixes were shown, one for CSS, and one for JavaScript. It is important to note that the syntax of these directives can vary based on the file type and preprocessor definition. For example, CoffeeScript files begin with "#=".

Dynamic Directives

The asset-pipeline require directives also support the use of the Groovy Templates via the GStringTemplateEngine. This means you can use some conditional require situations based, for example, on the grails Environment.

//= require ${grails.util.Environment.currentEnvironment.toString() == 'DEVELOPMENT' ? 'ember.debug.js' : 'ember.prod.js'}
or
//= require ${grails.util.Environment.currentEnvironment == grails.util.Environment.DEVELOPMENT ? 'ember.debug.js' : 'ember.prod.js'}

It is important to note that when prepping for a production release these conditionals are only evaluated in dev runtime and in war build. If you build a war in prod environment but start it up in staging, the evaluation will have already occurred in prod.

4.2 Asset Organization

Asset pipeline organization occurs within the "grails-app/assets" folder. This folder can exist within both the main application as well as a plugin.

A plugin will also include its web-app directory to better deal with plugins that wish to support both the resources plugin as well as asset-pipeline.

Organization

Within the "grails-app/assets" directory are several subfolders

grails-app/assets/javascripts
grails-app/assets/stylesheets
grails-app/assets/images

The first level deep within the assets folder is simply used for organization purposes and can contain folders of any name you wish. File types also don't need to be in any specific folder. These folders are omitted from the URL mappings and relative path calculations. For example, if I had "grails-app/assets/stylesheets/application.css" and "grails-app/assets/images/logo.png", I would include this in my CSS by the following means:

#logo {
	background: url('logo.png');
}

You can also directly reference it to better help with support for prebuilt third party CSS libraries like so:

#logo {
	background: url('../images/logo.png');
}

The above path will automatically be processed and converted to "logo.png" assuming the file exists.

A common folder that gets added to this set of organization is a "lib" folder. This folder can be useful in organizing third party libraries like jQuery, or Bootstrap.

Plugins

Plugins also can have the same "grails-app/assets" folder and their URL mapping is also the same. This means it can be more important to ensure unique naming / path mapping between plugins. This is also powerful in the sense that a plugin can add helper manifests to be used within your apps like jquery, bootstrap, font-awesome, and more.

These plugins also differ in the fact that the assets within their web-app directory also become available under a similar structure

web-app/css
web-app/js
web-app/img

These paths also get flattened just like the "grails-app/assets/javascripts" folder does.

If, in the event, a file within a plugin needs to be overridden within your application, simply create the same file with the same relative path to "grails-app/assets" and it will override / take precedence over the plugin. More on that later.

Since plugins share the same file structure for assets, as well as web-app. It can become more important to "namespace" your plugins by creating further nested folders. (i.e. the plugin SpudCore puts its application.js file within "grails-app/assets/javascripts/spud/admin/application.js").

Search Paths

When a file is referenced via a taglib or a manifest require directive, the asset-pipeline checks for the file in several locations.

First it tries to find the file relative to the manifest including it. For example "admin/application.js" looking for "table.js"

// FileName: admin/application.js
//= require table

The first place we will look is within "grails-app/assets/javascripts/admin/" We will proceed to do this within all of the asset sub folders across plugins after the main application is searched.

The next place we will look is the root of all grails-app/assets sub folders (e.g. "grails-app/assets//table.js", and "web-app/*/table.js" for plugins).

In all cases, the applications assets folder takes precedence between the two search paths, but plugins get scanned as well.

These same conditions should be implemented on any preprocessor extension plugin, e.g. LESS-asset-pipeline follows the same scan for @import directives.

4.3 Linking to Assets

Asset Pipeline adds a few new taglibs to properly reference your assets. These taglibs automatically handle swapout of cache digest names during production use as well as any custom URL mapping changes.

Views

<head>
  <asset:javascript src="application.js"/>
  <asset:stylesheet src="application.css"/>
</head>

The primary include tags, as shown above, are quite useful for including your relevant JavaScript or stylesheet files. Notice that you do not have to prefix with '/assets', as this is handled automatically by the tag.

In GSP views, you can also reference images included in the asset-pipeline with the following tag:

<asset:image src="logo.png" width="200" height="200"/>

Assets can also be referenced within subdirectories if required and simply require the use of the relative path.

<asset:image src="icons/delete.png"/>

It is also possible to return an assetPath as a string for injection in your own tags:

<link href="${assetPath(src: 'manifest.json')}"/>

It is also possible to execute a code section only if an asset exists or to simply test for existence

<asset:assetPathExists src="test.js">
This will only be displayed if the asset exists
</asset:assetPathExists>

or

asset.assetPathExists(src: 'test.js') //returns true or false

Getting Resource

As of version 0.8.2 a new bean exists called assetResourceLocator This can be used to find assets by URI in both development and production mode.

class ExampleService {
  def assetResourceLocator

def someMethod() { Resource myResource = assetResourceLocator.findAssetForURI('test.css') } }

Deferred Scripts

Asset-Pipeline provides a set of tags that can be used to ensure script blocks are deferred to the end of your page. This is not recommended as its not very unobtrusive, but has been added to help newcomers upgrade existing apps from resources.

<asset:javascript src="application.js" asset-defer/>
<asset:script type="text/javascript">
  console.log("Hello World");
</asset:script>
<asset:script type="text/javascript">
  console.log("Hello World 2");
</asset:script>

Now to render the output of these scripts simply use the following:

<asset:deferredScripts/>

Stylesheet References

Stylesheets commonly make reference to images and in some cases other CSS files using the '@import' directive. With the asset-pipeline in Grails, relative paths can be recalculated and automatically reference the proper file. For example, if you have a CSS file that looks like this:

body {
	background: url('/assets/mybg.png') top left repeat-all;
}

The generated output of this css file will be exactly the same:

body {
	background: url('/assets/mybg.png') top left repeat-all;
}

But, if we use a relative path, the asset-pipeline understands this path and can recalculate a new relative path based on whatever root file may have required the CSS:

body {
	background: url('mybg.png') top left repeat-all;
}

Would then become:

body {
	background: url('mybg-a87c78f.png') top left repeat-all;
}

In production mode, your image references or CSS references will automatically get their cache-digested name appended to them when using relative paths. More on this later.

4.4 Encoding

In some cases it may be necessary to specify an encoding for your assets. An example might be for Japanese characters in a JavaScript file. To do this, two things must be done. First, we simply set the charset attribute when we include are JavaScript file:

<asset:javascript src="application.js" charset="utf-8"/>

This should take care of testing in development mode and debugging. However, when we move to production/WAR mode the precompiler has no way to infer the desired encoding for compilation. To accomplish this, we have the //= encoding directive. This can be placed at the top of your application.js to define the desired compilation encoding.

//=encoding UTF-8
//=require_self
//=require_tree .

That's all there is to it.