4 Usage - Reference Documentation
Authors:
Version: 3.2.1
Table of Contents
4 Usage
Asset-Pipeline automatically creates a series of folders within yourgrails-app
directory:grails-app/assets/javascripts grails-app/assets/images grails-app/assets/stylesheets
Setting up Manifests
Examplegrails-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_selfconsole.log("This is my javascript manifest");
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"]
grails.assets.plugin."twitter-bootstrap".excludes = ["**/*.less"] grails.assets.plugin."twitter-bootstrap".includes = ["bootstrap.less"]
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>
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 addinggrails.assets.bundle=true
to yourConfig.groovy
or setting thebundle="true"
attribute on the taglib.
Using with Plugins
Asset pipeline makes it easy to serve assets from within plugins. It's actually quite simple. Thegrails-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 intotarget/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 yourConfig.groovy
environment block.environments {
production {
grails.assets.storagePath = "/full/path/to/storage"
}
}
environments {
production {
grails.assets.url = "http://s3.amazonaws.com/asset-pipe/assets/"
}
}
Custom Files
Asset Pipeline uses classes of typeAssetFile
. 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 .
/* *= require_self *= require header *= require navigation *= require_tree . *= require_full_tree . *= encoding UTF-8 */
Directives
Directive | Meaning |
---|---|
require | Includes a single file into the manifest |
require_tree | Recursively includes all files and subdirectories in the path |
require_self | Inserts the body of the current file |
require_full_tree | Include files from all plugins that contain the relative base path |
encoding | Set the processor encoding for this bundle (i.e. UTF-8 or ANSI or Latin1) |
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 theGStringTemplateEngine
. 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'}
//= 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 subfoldersgrails-app/assets/javascripts grails-app/assets/stylesheets grails-app/assets/images
#logo { background: url('logo.png'); }
#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 structureweb-app/css web-app/js web-app/img
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
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>
<asset:image src="logo.png" width="200" height="200"/>
<asset:image src="icons/delete.png"/>
<link href="${assetPath(src: 'manifest.json')}"/>
<asset:assetPathExists src="test.js"> This will only be displayed if the asset exists </asset:assetPathExists>
asset.assetPathExists(src: 'test.js') //returns true or false
Getting Resource
As of version 0.8.2 a new bean exists calledassetResourceLocator
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>
<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; }
body { background: url('/assets/mybg.png') top left repeat-all; }
body { background: url('mybg.png') top left repeat-all; }
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"/>
//= 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 .