Grails resources

Preview:

DESCRIPTION

Presentation about Grails' Resources plugin

Citation preview

Grails' Resource Plugin

whoami

Colin HarringtonSenior Consultant

colin.harrington@objectpartners.com@ColinHarrington

Intro

● Resources plugin– http://grails.org/plugin/resources

● Installed by default in Grails 2.0– Available in 1.3.x branches

● Written by Marc Palmer & Luke Daley

Why?

Performance ~ Perception

Performance impacts cost

- less traffic- less load

- better scalability

14 rules

http://stevesouders.com/hpws/rules.php

Good performance tips from Yahoo!

Firefox ySlow pluginGoogle Page Speed - Chrome - Firefox - mod_pagespeed for apache

Rule 1 - Make Fewer HTTP RequestsRule 2 - Use a Content Delivery NetworkRule 3 - Add an Expires HeaderRule 4 - Gzip ComponentsRule 5 - Put Stylesheets at the TopRule 6 - Put Scripts at the BottomRule 7 - Avoid CSS ExpressionsRule 8 - Make JavaScript and CSS ExternalRule 9 - Reduce DNS LookupsRule 10 - Minify JavaScriptRule 11 - Avoid RedirectsRule 12 - Remove Duplicate ScriptsRule 13 - Configure ETagsRule 14 - Make AJAX Cacheable

Example

Example optimized with resources

Modular development

History

● D.I.Y.● 2008 - UI Performance● 2009 - Static Resources Plugin● December 2011 – Resources Plugin included by

default in Grails 2.0 release

DIY

● pre-optimized bundles

● custom filters

● build time jobs

UI Performance plugin

● http://grails.org/plugin/ui-performance/

● minification of CSS and JS● compression● css sprites● bundling of CSS and JS● build time

Resources Plugin

● Pluggable framework for handling static resources

● runtime ":resources:1.2-RC1"

● “This plugin represents a new way of declaring and linking to static resources in your application and plugins. Resource dependencies can be declared (e.g. jQuery UI requires jQuery) and pages simply indicate which resource modules they require. The plugin does the rest, and provides a processing pipeline for advanced optimisations.”

Using Resources in your Layout

<html> <head> <g:layoutTitle/> <r:layoutResources/> </head> <body> <g:layoutBody/> <r:layoutResources/> </body></html>

GSP view

<html> <head> <meta name="layout" content="main"/> <r:require modules="jquery-ui, blueprint"/> <r:script> $(function() { $('#form').dialog('open'); }); </r:script> </head> <body> <div id="form"> Hello World </div> </body></html>

Runtime

● Redirects on legacy URLs to a /static/<resource URI>

● Uses the ProcessingFilter to Process the Resource

Resources

● MyApplicationResources.groovy contains modules, bundles, etc.

● ResourcesArtefactType

– *Resources.groovy

● Definable in Config.groovygrails.resources.modules = { … }

Resource DSLmodules = {

core {

dependsOn 'jquery, utils'

defaultBundle 'ui'

resource url:'/js/core.js', disposition: 'head'

resource url:'/js/ui.js'

resource url:'/css/main.css',

resource url:'/css/branding.css'

resource url:'/css/print.css', attrs:[media:'print']

}

}

dependsOn

modules = {

core {

dependsOn 'jquery, utils'

dependsOn 'other'

dependsOn(['heavy', 'metal'])

}

}

resource method

modules = {

ui {

resource '/css/forms.css'

resource '/js/forms.js'

}

}

resource attributes

● url * required● exclude (exclude:'minify')● bundle● disposition● attrs● id● linkOverride● wrapper

– (wrapper: { s -> "<!--if lt IE 8>$s<!endif-->" } )

defaultBundle method

modules = {

core {

defaultBundle 'core-ui'

...

}

ui {

defaultBundle 'core-ui' …

}

}

TagLib

● <r:resource>● <r:img>● <r:renderModule>● <r:script> ● <r:layoutResources>● <r:require>● <r:external>

CSS

● Bundling

● Rewriting

● Minification

yui-minification for css and js

● runtime ":yui-minify-resources:0.1.5"

● http://grails.org/plugin/yui-minify-resources● Confgurable:

– grails.resources.mappers.yuicssminify.includes = ['**/*.css']

– grails.resources.mappers.yuijsminify.includes = ['**/*.js']

– grails.resources.mappers.yuicssminify.excludes = ['**/*.min.css']

– grails.resources.mappers.yuijsminify.excludes = ['**/*.min.js']

– More...

less.css

● Variables● Mixins● Nested Rules● Functions & Operations

● Client side● Server side● Command Line

● compile ":lesscss-resources:1.3.0.3"● http://lesscss.org/

Smart Sprites Resources

● compile ":smart-sprites-resources:0.2"

● http://grails.org/plugin/smart-sprites-resources● Uses Smart Sprites● http://csssprites.org/● Used in UI Performance

Javascript

● jQuery● Bootstrap (out of date?)● Handlebars● dustjs● gsp

disposition

● link disposition (head vs defer)

● Successive calls to <r:layoutResources>– Once in the <head/>– Once before the closing </body> tag

● Blocking the UI!! Don't do it!

● <r:layoutResources disposition='defer'/>

Asset pipeline

● Pluggable pipeline of ResourceMappers

● Include/exclude logic

● Phases

● Configurable map() method

class TestResourceMapper {

def phase = MapperPhase.MUTATION

static defaultExcludes = [ '**/*.png', '**/*.gif', '**/*.jpg', '**/*.jpeg', '**/*.gz', '**/*.zip' ] static defaultIncludes = [ '/images/**' ]

def map(resource, config) { … }}

enum MapperPhase { GENERATION, MUTATION, COMPRESSION, LINKNORMALISATION, AGGREGATION, RENAMING, LINKREALISATION, ALTERNATEREPRESENTATION, DISTRIBUTION, ABSOLUTISATION, NOTIFICATION }

Mapper Phase

● GENERATION

– create new assets = compile less files

● MUTATION

– alter/improve assets (may mean creating new/deleting aggregated resources) = spriting

● COMPRESSION

– reducing the file size but maintaining semantics = minify

● LINKNORMALISATION

– convert all inter asset references into a normal form = css links

● AGGREGATION

– combining multiple assets into one = bundling

Mapper Phase

● RENAMING

– moving of physical assets = hashing

● LINKREALISATION

– convert normalised inter asset references into real form = css links

● ALTERNATEREPRESENTATION

– attach different representations of the asset = gzipping

● DISTRIBUTION

– moving assets to their hosting environment = s3, cdn

● ABSOLUTISATION

– update inter asset references to their distributed equivalent

● NOTIFICATION

– let the world know about the new resources = cache invalidation

cached-resources

● runtime ":cached-resources:1.0"● http://grails.org/plugin/cached-resources● Files/resources use a SHA-256 hash● Delegates to the cache-headers plugin

– ETag header

– Last-Modified header

zipped-resources

● runtime ":zipped-resources:1.0"● http://grails.org/plugin/zipped-resources● Gzip applied to files● Sends the .gz contents

● Sets the Transfer-Encoding header to 'gzip'

cdn-resources

● compile ":cdn-resources:0.2.1"● http://grails.org/plugin/cdn-resources

● grails.resources.cdn.enabled = true● grails.resources.cdn.url = "http://static.mydomain.com/”

● Configurable URL per modules...

Configuration

● Change the /static/ URI prefix: grails.resources.uri.prefix = 'other'

● grails.resources.work.dir

● grails.resources.debug = true

● grails.resources.processing.enabled = false

● grails.resources.rewrite.css

More Config

● grails.resources.adhoc.patterns = ["/images/*", "*.css", "*.js"]

● grails.resources.mappers.cssrewriter.includes = ['**/*.css', '**/*.less']

● grails.resources.mappers.csspreprocessor.includes = ['**/*.css', '**/*.less']

● grails.resources.mappers.cssrewriter.excludes = ['unsafe/**']

● grails.resources.mappers.csspreprocessor.excludes = ['unsafe/**']

● grails.resources.mappers.bundle.excludes = ['unsafe/**/*.css']

Debugging

● Reloading in development

● Debug with ?_debugResources=y

● anti-cache: ?_refreshResources=y

● log4j:● debug "org.grails.plugin.resource"

● println grailsResourceProcessor.dumpResources()

Write your own plugin?

● Dart?

● Sass?

● Javascript templating du jour?

Issues

● Load balancing bugs

● non-DRY elements in Deep hierarchies

● Others?

Questions?

Thank you