+ All Categories
Home > Documents > The new static resources framework

The new static resources framework

Date post: 17-May-2015
Category:
Upload: marcplmer
View: 3,895 times
Download: 0 times
Share this document with a friend
Description:
My talk on the new Resources plugin for Grails, at Groovy Grails Exchange 2010
Popular Tags:
47
The new static resources framework
Transcript
Page 1: The new static resources framework

The new static resources framework

Page 2: The new static resources framework

About me

Marc Palmer

Paid to develop WeceemFounder at NoticeLocal and Spotty Mushroom

Old skool Grails user since 0.4

Plugin writing maniac

Page 3: The new static resources framework

Resource management

Web performance

Page 4: The new static resources framework

Eternal caching

Minifying

Zipping

Bundling

Load order

Page 5: The new static resources framework

Old Problems

Ant

Java

Boilerplate code

Spring MVC config

Code verbosity

Page 6: The new static resources framework

New Problems

Download performance

Complex UI from plugins

Page 7: The new static resources framework

Blueprint jQuery jQuery UI

Your application

CSS JS JS +CSS

Admin UISecurity UI

Scaffolding

Custom CSS

Custom JS

Page 8: The new static resources framework

Optimization hell

Who includes resources & when?

Is the resource already optimized?

Load order

Performance: I want control

Page 9: The new static resources framework

Plugin version conventions help:

grails-blueprint-0.9grails-jquery-1.4.3grails-jquery-ui-1.8.2

Page 10: The new static resources framework

Resources plugin

Resource declaration DSL

Dependency resolution

Resource tags

Mapping pipeline

Modular and extensible

Processed at runtime

Page 11: The new static resources framework

Runtime?!

Page 12: The new static resources framework

Runtime?!

Page 13: The new static resources framework

Only at startup!

Works in any environment

Can be bypassed

Supports reloading

Tiny trade-off

Page 14: The new static resources framework

Installing itmarcmacbook:AwesomeApp marc$ grails install-plugin resources Welcome to Grails 1.3.1 - http://grails.org/Licensed under Apache Standard License 2.0Grails home is set to: /usr/local/grails-1.3.1

Base Directory: /Users/marc/Projects/AwesomeAppResolving dependencies...Dependencies resolved in 1172ms.Running script /usr/local/grails-1.3.1/scripts/InstallPlugin.groovyEnvironment set to developmentInstalling zip ../checkout/Resources/grails-resources-1.0-RC1.zip... ... [mkdir] Created dir: /Users/marc/.grails/1.3.1/projects/AwesomeApp/plugins/resources-1.0-RC1 [unzip] Expanding: /Users/marc/Projects/checkout/Resources/grails-resources-1.0-RC1.zip into /Users/marc/.grails/1.3.1/projects/AwesomeApp/plugins/resources-1.0-RC1Installed plugin resources-1.0-RC1 to location /Users/marc/.grails/1.3.1/projects/AwesomeApp/plugins/resources-1.0-RC1. ...Resolving plugin JAR dependencies ...Executing resources-1.0-RC1 plugin post-install script ...Plugin resources-1.0-RC1 installedmarcmacbook:AwesomeApp marc$

Page 15: The new static resources framework
Page 16: The new static resources framework

So far so...?Before After

Page 17: The new static resources framework

Resource DSL

modules = { grailsDefaults { resource url:[dir:'css', file:'main.css'] resource url:[dir:'js', file:'application.js'], disposition:'head' resource url:[dir:'js/prototype', file:'prototype.js'] } myStuff { dependsOn 'grailsDefaults' resource url:[dir:'css', file:'branding.css'] resource url:[dir:'js', file:'ui-logic.js'] }}

File: grails-app/config/AwesomeResources.groovy

Page 18: The new static resources framework

Changes to GSP

<html> <head> <title>Welcome to Grails</title> <meta name="layout" content="main" /> <r:use modules="myStuff"/> </head> <body><!-- ... --> </body></html>

File: grails-app/views/index.gsp

Page 19: The new static resources framework

What does this page do?

What does it need to do it?

Explicit resource tags are wrong

Page 20: The new static resources framework

Changes to layout<html> <head> <title><g:layoutTitle default="Grails" /></title> <r:layoutResources /> <link rel="shortcut icon" href="${r.resource(dir:'images',file:'favicon.ico')}" type="image/x-icon" /> <g:layoutHead /> </head> <body> <div id="spinner" class="spinner" style="display:none;"> <img src="${r.resource(dir:'images',file:'spinner.gif')}" alt="Spinner" /> </div> <div id="grailsLogo" class="logo"><a href="http://grails.org">

<img src="${r.resource(dir:'images',file:'grails_logo.png')}" alt="Grails" border="0" /></a></div>

<g:layoutBody />

<r:layoutResources />

<script type="text/javascript"> oneLineAmazingUI(); </script> </body></html>

File: grails-app/views/layouts/main.gsp

Page 21: The new static resources framework

Link disposition

<head> <r:layoutResources/> <!-- head --></head><body> ... <r:layoutResources/> <!-- defer --></body>

Page 22: The new static resources framework

The basic tags

<script src="..."> <script src="..."> <link rel="stylesheet" ... /><link rel="stylesheet" ... />

<r:use modules="myStuff"/>

<g:resource .../> <r:resource .../>

<img .../> <r:img .../>

Page 23: The new static resources framework

Disposition in DSL

modules = { grailsDefaults { resource url:[dir:'css', file:'main.css'] resource url:[dir:'js', file:'application.js'], disposition:'head' resource url:[dir:'js/prototype', file:'prototype.js'] } myStuff { dependsOn 'grailsDefaults' resource url:[dir:'css', file:'branding.css'] resource url:[dir:'js', file:'ui-logic.js'] }}

File: grails-app/config/AwesomeResources.groovy

Page 24: The new static resources framework

Better...Before After

Page 25: The new static resources framework

Bundlingmodules = { grailsDefaults { resource url:[dir:'css', file:'main.css'] resource url:[dir:'js', file:'application.js'], disposition:'head' resource url:[dir:'js/prototype', file:'prototype.js'], bundle: 'core' } myStuff { dependsOn 'grailsDefaults' defaultBundle 'core' resource url:[dir:'css', file:'branding.css'] resource url:[dir:'js', file:'ui-logic.js'] }}

Cross-module bundle!

Page 26: The new static resources framework

Dependency overrides

Text

modules = { grailsDefaults { defaultBundle 'core' resource url:[dir:'css', file:'main.css'] } myStuff { dependsOn 'grailsDefaults, blueprint' defaultBundle 'core' resource url:[dir:'css', file:'branding.css'] resource url:[dir:'js', file:'ui-logic.js'] } overrides { jquery { defaultBundle 'core' } 'jquery-ui' { resource id:'js', bundle: 'core' resource id:'theme', bundle: 'core' } 'blueprint' { resource id:'main', bundle: 'core' } }}

Page 27: The new static resources framework
Page 28: The new static resources framework

Deferred inline JS

<r:script>

initUIThatDoesNotSuck();</r:script>

Page 29: The new static resources framework

We love the debugDevelopment reloads

Turn it all off: add ?_debugResources=y

Cache defeat: add ?_refreshResources=y

X-Grails-Resources-Original-Src:/bundle-grailsDefaults.js, /js/application.js, /js/prototype/prototype.js

Page 30: The new static resources framework

What just happened?

Declarative resources

Single tag mechanism

Optimal, smart ordering

Resource de-deduping

Bundling

Page 31: The new static resources framework

Now the fun part

Page 32: The new static resources framework

Mapping pipelineCopy to work dir

Apply mappers

Modify resource

Add response handler

Update URI

Page 33: The new static resources framework

Mapper Artefacts

Text

class TestResourceMapper {

def priority = Integer.MAX_VALUE def map(resource, config) { def file = new File(resource.processedFile.parentFile,

"_${resource.processedFile.name}") assert resource.processedFile.renameTo(file) resource.processedFile = file resource.updateActualUrlFromProcessedFile() }}

Page 34: The new static resources framework

Bundling Mapper

/js/jquery-ui/jquery-ui.css

/css/blueprint/screen.css

/bundle_main.css

/css/main.css

Page 35: The new static resources framework

CSS rewriting

Both CSS and image may be renamedand/or moved

/css/main.css:

body { background-image: url(../images/bg.png);}

/bundle_main.css:

body { background-image: url(../changed.png);}

Before

After

Page 36: The new static resources framework

Resources Others

Page 37: The new static resources framework

Zipped Resources

Compresses files to xxx.css.gz

Keeps URI the same

Sets Content-Encoding: gzip

grails install-plugin zipped-resources

Page 38: The new static resources framework

Cached Resources

Renames to SHA256 digest of contents

Shortens name to base62 encoding

Flattens directory structure

Sets Expires to 1 year

grails install-plugin cached-resources

Page 39: The new static resources framework

/js/some-bloated-lib/plugin/foo.js

/b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9.js

/UpLdvv429fMac6FhEx5FMU2F3Cg1yj4HwUGmihFvjYR.js

Page 40: The new static resources framework

In production already

Page 41: The new static resources framework
Page 42: The new static resources framework
Page 43: The new static resources framework

Config conventions

grails.resources.<mapper>.excludes = [...]

grails.resources.modules = { ... }

grails.resources.debug = true

grails.resources.work.dir = ...

grails.resources.uri.prefix = 'static'

grails.resources.adhoc.patterns = ...

Page 44: The new static resources framework

Integration into coreDSL

Dependency resolutionTags

Mapping pipelineBundling

CSS Rewriting

Mapper pluginse.g. zipped-resources

Grails Core

grails-resources 2.0

grails-xxxx-resources

Page 45: The new static resources framework

Future

Minify

CSS Sprites

Smart image links with auto w & h

E.S.P. - externalising inline JS

Flavours (content variants)

CDN up loaders

Page 46: The new static resources framework

Special thanks...

Peter Ledbrook

Luke Daley

Stéphane Maldini

Robert Fletcher

Burt Beckwith

Page 47: The new static resources framework

Q & A and linksSample app:http://bit.ly/awesomeapp1http://bit.ly/awesomeapp2

http://grails.org/plugin/resourceshttp://grails.org/plugin/zipped-resourceshttp://grails.org/plugin/cached-resourceshttp://noticelocal.comhttp://www.experienceoz.com.auhttp://www.icescrum.org

Also check out some unsung plugins:taxonomy, invitation-only, cache-headers,one-time-data, email-confirmation


Recommended