GreenScript module
The GreenScript module help you to manage javascript and CSS dependencies and do minimizing work in the same time.
What’s New for v1.2d
- configuration change (COMPATIBILITY BROKEN!): resource dir location shall NOT include resource root dir now.
- Previously: greenscript.dir.js=/public/javascripts
- Now: greenscript.dir.js=javascripts (suppose greenscript.dir.root=/public)
- Previously: greenscript.dir.css=/public/stylesheets
- Now: greenscript.dir.css=stylesheets (suppose greenscript.dir.root=/public)
- Fix bug: https://github.com/greenlaw110/greenscript/issues#issue/11
- greenscript now support dependency management in modules (your css/js files in modules, your greenscript.conf file in moduels)
- Support ‘.bundle’ suffix in resource dependency configuration via greenscript.conf
- E.g. js.jq.bundle=http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js,http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.10/jquery-ui.js
- You can use ‘.bundle’ to define an alias for a resource, or
- you can use ‘.bundle’ to define a group of resources that always been used together
- Support inline dependency declaration (search for ‘inline dependency declaration’ in this document)
What’s New for v1.2c
- Fix bug: dependency management breaks for complicated dependencies
- Support reverse dependency declaration (search for “reverse dependency declaration” in this document)
What’s New for v1.2b
- Support transparent compression. You don’t even invoke #{greenscript.css|js /} tag to get your css and js file compressed
What’s New for v1.2a
- Fix bug: IllegalStateException thrown out when app restart (in DEV mode)
What’s New for v1.2
- Completely rewrite.
- GreenScript core logic detached from Play plugin project
- Clearly defined interface and well documented code comment
- Unit test cases for core logic
- Circular dependence relationship detect
- Unified javascript/css tag syntax
- Support inline javascript/css
- new tag options:
- media: pass media (screen, project, all, etc) to #{greenscript.css /} to specify the css file media target
- browser: pass to #{greenscript.css /} and #{greenscript.js /} to specify which browser it is targeted
What’s New for v1.1c
- greenscript.compress and greenscript.cache now default to true without regarding to the Play mode
- Unused compressed files in “gs” folder get cleaned
- Notice in configuration html page and demo application.conf file about greenscript.compress|cache option
- Fix bug in css.html tag: NPE encountered when trying to output without argument or "load/import"
- Add support to CDN
- Support reload dependency configuration at runtime
What’s New for v1.1
- Many bug fixes
- Completely new Plugin Configurator
- Add Command to enable user copy module tags/templates to user app directory
- More clear configuration settings
- Even more simplified tag syntax
- Support zero configuration
- Document improvement
What’s New for v1.0
- Bug fixes:
- dependency management fail while in ‘dev’ mode
- <a href=‘http://github.com/greenlaw110/play-greenscript/issues#issue/1’>greenscript should use play configuration file
- Enhancements:
- Tag simplified: ‘sm:gsSM’ parameter no longer needed for greenscript.css and greenscript.javascript tag
- Simplified alias for greenscript.javascript tag: greenscript.js
- Use ‘import’ to replace 'load'
Three steps to use GreenScript
- Install the module and enable it in your application.conf file
- you know what I am talking about ...
- Document your javascript/css dependencies in conf/greenscript.conf file
- Check the demo’s greenscript.conf file and you will know what it is
- Use greenscript tag in your template files: #{greenscript.js “myjs1 myjs2 ...” [options] /}
- Yes, this part is a little bit complicated, but not that much. I am sure it won’t be difficult as #{list} tag
Step 2 and 3 are optional. The simplest form of using GreenScript is to add the following line into your application.conf file:
module.greenscript=${play.path}/modules/greenscript-xx
Immediately you have done that, your javascript file and css file will be compressed automatically.
Manual
Configure GreenScript Plugin
# The GreenScript module
module.greenscript=${play.path}/modules/greenscript-xx
File locations
This part set the javascript, css and compressed file location in the filesystem, start from your application’s root.
# Default greenscript.dir.js point to /public/javascripts
greenscript.dir.js=/public/javascripts
#
# Default dir.css point to /public/stylesheets
greenscript.dir.css=/public/stylesheets
#
# Default minimized file folder point to /public/gs
greenscript.dir.minimized=/public/gs
URL Path
This part set the url path GreenScript used to output javascript, css or compressed files, start from root url.
Usually you will not need to set this part as it will reuse the dir settings, which is comply with Play’s default folder layout and route mapping. However, if you have shortcut set in your application’s route file (as what I did in the demo app), you are encouraged to override defalt setting here:
greenscript.url.js=/js
greenscript.url.css=/css
##
# IMPORTANT: make sure the mapping does not conflict with
# the mapping of greenscript module in your route file.
# see <a href="dyna-conf">Configuration at runtime</a>
greenscript.url.minimized=/compressed
Note that js and css url is used only when greenscript.miminize set to false, in which case, GreenScript will output links refer the original javascript/css files.
greenscript.url.minimized setting is used only when greenscript.minimize set to true, in which case, GreenScript will output links refer to the compressed(minimized) files
Minimize Settings
# Enable/Disable minimize
# Once minimize disabled, GreenScript will output the original javascript/css
# files without any processing. However, the order of the files is guaranteed
# to follow the dependency graph you have defined in "greenscript.conf" file
#
# When minimize turned on, GreenScript will merge all javascript/css files
# within one HTTP request into a single file. Again the merge order is
# guaranteed to follow the dependency graph you have defined in the
# "greenscript.conf" file
#
# Note if you turn off minimize, the rest 2 settings (compress, cache) will
# not function whatever the value they are
#
# By Default minimize is turned on in prod mode and turned off in dev mode
greenscript.minimize=false
#
# Enable/Disable compress
# Once compress is enabled, GreenScript will compress the javascript/css files
# while doing the merge operation.
#
# By default compress is turned on in prod mode and turned off in dev mode
greenscript.compress=false
#
# Enable/Disable cache
# Once cache is turned on, GreenScript will try best to reuse the processed
# file instead of repeat the merge/compress process.
#
# By default cache is turned on in prod mode and turned off in dev mode
greenscript.cache=false
Configure javascript/css dependencies
Javascript/css dependencies are documented in a separate configuration file named greenscript.conf, which should be put into the conf dir (the same place with your application.conf). Start from v1.2d, greenscript.conf could be put under conf dir of modules, and these module level greenscript configuration will be merged with application greenscript.conf to define the whole depenedency graph of javascript and css files located in your application and module folders. One limitation to this module level greenscript.conf support is that your javascript and css file must be put in the same directory hierarchy. For example, if you app js/css files are put into ${app.root}/public/javascripts and ${app.root}/public/stylesheets, then all your module you want to use with greenscript must also store their javascripts and css files inside ${module.root}/public/javascripts and ${module.root}/public/stylesheets.
It’s fairly straght forward to document the file dependencies. Let’s say your have four javascript files a.js, b.js, c.js and d.js, the dependency relationship is b.js depends on a.js, c.js depends on both b.js and d.js, then here is the content of your greenscript.conf file:
js.b=a
js.c=b,d
The same way applies to css file dependencies. The only difference is css dependancy rule starts with css. while javascript file rule starts with js.. Below is the content of greenscript.conf file of the demo application:
# js.default means the file get loaded always, even no other file depends on it
js.default=prototype
# Javascript Dependencies
js.datepicker=prototype-base-extensions,prototype-date-extensions
js.livevalidation=prototype
js.pMask=prototype-event-extensions
js.prototype-base-extensions=prototype
js.prototype-date-extensions=prototype
js.prototype-event-extensions=prototype
js.dumb_1=prototype
#
# CSS Dependencies
css.color=reset
css.form=color,layout
css.layout=reset
#
# Other configuration should go to application.conf
reverse dependency declaration (new in 1.2c)
bc. js.b-=a,c,d
The above line equals to three lines below:
bc. js.a=b
js.c=b
js.d=b
Using tags
Now that your have understand how to configured the plugin and file dependencies, it’s time to see how GreenScript can simplify your life of dealing with javascript/css in your play template files.
The base template: main.html
Normally you should have a main.html (you might call it “base” or other names, but that doesn’t matter) served as a base template for all other templates, and in the "
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/stylesheets/main.css'}">
#{get 'moreStyles' /}
<script src="@{'/public/javascripts/jquery-1.4.2.min.js'}" type="text/javascript" charset="utf-8"></script>
#{get 'moreScripts' /}
And here is how it should be when you are using GreenScript:
#{greenscript.css "main", output:'all'/}
#{greenscript.js output: 'all'/}
Yes! that’s it. I know you might have some questions, don’t worry. Let me unveil the curtain.
- Where is my “jquery-1.4.2.min.js” ?
- When you put output: 'all' in #{greenscript.js} tag, it will output all unloaded js dependency files as well as the default js file you’ve defined in greenscript.conf. I am sure jquery-1.4.2.min.js will be reached by either of the 2 lookup paths, otherwise, I assume you will not need that file. For perfectionist, here is how to load the file anyway: #{greenscript.js “jquery-1.4.2.min.js”, output: true/}
- How can I get “moreStyles” and “moreScripts”?
- You get them automatically when you have output: true for #{greenscript.css} or output: 'all' for #{greenscript.js}. The assumption is you have told GreenScript that you need them in other places. I will let you know how to do that later at next section.
- Why do you use output for css while loadAll for js?
- loadAll is deprecated now. Both css and js use ‘output: "all"’ to output all inline declared and dependencies that has not output yet
Other templates
The differences of using GreenScript tag in other templates and in the main.html is that ususally you don’t “output” javascript or css files in your other templates, instead, you declare them (for the template usage). Here is a sample (found in ${play.path}/samples-and-tests/booking/app/views/Hotels/book.html) of how to declare javascripts and css when you don’t have GreenScript:
#{set 'moreScripts'}
<script src="@{'/public/javascripts/jquery-ui-1.7.2.custom.min.js'}" type="text/javascript" charset="utf-8"></script>
#{/set}
#{set 'moreStyles'}
<link rel="stylesheet" type="text/css" media="screen" href="@{'/public/ui-lightness/jquery-ui-1.7.2.custom.css'}" />
#{/set}
And see how you do with GreenScript available:
#{greenscript.js "jquery-ui-1.7.2.custom.min" /}
#{greenscript.css "/public/ui-lightness/jquery-ui-1.7.2.custom" /}
Easy, right? You might noticed that I have put the full path for the css file in this case. This is needed because the file is not in the default stylesheet file folder (configured with greenscript.dir.css, which default to /public/stylesheets).
Inline body
Greenscript Play module support inline body start from v1.2.
#{greenscript.css}
dl > dt {
font-weight: bold;
color: #600;
}
#{/greenscript.css}
In the above sample, the block that defines dl > dt’s style will be captured by greenscript and moved to your html page header. (Suppose you have “#{greenscript.css output:'all'}” in the header block of your main.html template. By using “output: true” parameter, the following sample will output the block in place rather than moving the enclosed body to the header:
#{greenscript.js output:true}
var rule = ruleById('first_name');
rule.add(Validate.Presence)
rule = ruleById('last_name');
rule.add(Validate.Presence)
rule = ruleById('email');
rule.add(Validate.Email)
rule.add(Validate.Presence)
$$('input.date').each(function(el){
new Control.DatePicker(el, {icon: '/public/images/calendar.png', locale: 'en_iso8601'});
});
#{/greenscript.js}
Inline Dependency Declaration
There is a long time complaint that greenscript does not guarantee the output sequence of resource (js/css) files match the sequence of declaring those files in tags. For example, #{greenscript.js ‘a b c’/} does not necessarily output or marge javascript ‘a.js’, ‘b.js’ and ‘c.js’ in a sequence that a.js followed by b.js and then c.js. This is because greenscript output is driven by dependencies (which is defined in greenscript.conf), rather than the sequence declared in tag. Actually greenscript cannot and shouldn’t follow the sequence declared in tag at all. The reason is
1. the sequence of tag declaration might conflict with dependencies declared in greenscript.conf
2. it is hard to tell the sequence of tag declaration when the developer declare resources in multiple templates with inheritance relationships
Now (start from v1.2d) greenscript support inline dependency declaration in tags, which basically remove the inconvenience that simple resource file dependencies are also require developer to provide a greenscript.conf file:
#{greenscript.js 'myapp < mylib < jquery-1.5.min'/}
The above javascript declaration also setup the dependencies among the declared javascript resources: myapp.js relies on mylib.js which in turn relies on jquery-1.5.min. Therefore you no longer need a greenscript.conf file to define the dependencies among myapp, mylib and jquery-1.5.min javascript files.
The limitation of inline dependency declaration is you can’t use it across multiple template files. Say you have a javascript A declared in main.html and then you have another javascript B declared in index.html, you can’t use inline dependency declaration to declare the dependency relationship between A and B unless you declare them all in index.html: #{greenscript ‘A > B’/}
Reference
A > B means B relies on A
A < B means A relies on B
Media and Browser
GreenScript support media and browser options start from v1.2. Issue tag "#{greenscript.css ‘print.css’, media: ‘printer’}
" to declare a css resource target to “printer” media. Later when you output all css files by "#{greenscript.css output:‘all’}
", one line will be output as:
Declare resource specific to a browser in the following way:
#{greenscript.css ‘ie’, browser: ‘lt IE 8’/}
The corresponding output is:
<!--[if lt IE 8]>
<![endif]-->
h3. Configuration at runtime
This beautiful feature enable app developer to turn on/off minimizing dynamically and could be very helpful when you need to debug your javascript/css. In order to use the feature, you will need to add an entry in your route file to map a url request to the controllers.greenscript.Configurator actions, for example:
# Enable GreenScript dynamic configuration
# IMPORTANT: make sure this routine map be different from your
# staticDir map to compressed file folder
GET /gsconf module:greenscript
Once you have done with that, you can reach the configuration page by typing http://localhost:9000/gsconf in the address bar of your favorite browser. The configuration is designed to be self guided and you won’t lost yourself there. Please be noted that runtime configuration will not be flushed to your configuration file. When you restart your app all the configurations you’ve made during last session are lost. Meaning if you want to change a configuration permanently, you must update your application.conf file. See Configuration section for detail.
You can also force GreenScript to reload the dependency configuration from “greenscript.conf” file if you have changed it. Just go to “css/js dependencies” tab and click “reload”. This feature is very friendly to developer, especially in the early stage of javascript involved development.
About Security p. There is no integrated security to access the configuration page. And here is my 2 cents on how to secury your GreenScript dynamic configuration access:
- Option 1: Remove the url mapping entry in your route file in a prod environment
- Option 2: If you are a real hack and reject any manual operations, you will probably implement your own controller extends (or @With) controllers.greenscript.Configurator, and then add security to your controller. You will need to copy the configurator templates to your views folder. Don’t worry, GreenScript provides command to help you with that. I will get there now.
Module command
I’ve just told you that you can use command to copy the greenscript Configurator.configure.html template file to your app folder. Here is how to do it. First make sure you have enabled greenscript in your application.conf file. And then go to the console, enter your app root dir, and type:
play greenscript:cp -t MyGSConfigurator
The template file will be ready in {your-app-root}/app/views/MyGSConfigurator folder. Obviously your controller should be named MyGSConfigurator. It probably should looks like:
package controllers;import play.mvc.*;
@With({Secure.class, controllers.greenscript.Configurator.class})
@Secure(role=‘developer,admin’)
public class MyGSConfigurator extends Controller {
}
Keep it secret!
Okay, how do you feel about this Plugin? Still not satisfied because you don’t like to type 11 charaters for tag name each time? Well I have a secret weapon to alleviate your pain with that: Once you have enabled greenscript in your conf/application.conf file, go to console, enter your app root, and type:
play greenscript:cp -a gs
Now guess what happened? You are right, it copied the tags from module folder to your app folder: your-app-root/app/views/tag/gs. And now you can use tags in short version: #{gs.js “js1 js2 ...” /} and #{gs.css “css1 ...” /}. What? you are still not satisfied? how come? it’s already shorter than play’s #{script} tag! Okay, here is my nuclear weapon:
play greenscript:cp -a .
...
#{js output: 'all'/}
#{js "js1 js2 ..." /}
..
#{css "css1 css2" /}
How do you expect anything more simpler than this?
Zero configuration
GreenScript plugin now support zero configuration. It means besides enabling it in your application.conf, you don’t need to do any configuration to use it, you don’t even need to create “greenscript.conf” file in your conf dir. But what do you get if you don’t do any configuration? Well basically you can still benefit from GreenScript with zero configuration:
- The tags. You are free to utilize all the knowledges you’ve learned from Using Tags section.
- Minimize/compress. You can also benefit from minimizing/compressing/cache capability of GreenScript.
- Dynamic configuration. You can also use the dynamic configuration controller.
So what do you lost without any configuration?
- Dependency management. Without dependencies infomation defined in greenscript.conf file, you are on your own to take care of js/css file dependencies. When you are declare a javascript or css file in a template, you should also make sure all its dependencies are explicitly declared before that scripts “IN PLACE”! If you failed to do that, you might get a lot of script/css errors in your final rendered html page.
- Dir/URL path bound to play’s default. With zero configration, you need to make sure your dir structure (the public) and route mapping of public dir strictly follow Play’s convention. Otherwise GreenScript won’t be able to locate the javascript/css files.
As an example to demonstrate zero configuration, I put the ${play.path}/samples-and-tests/booking sample in the samples-and-tests dir of greenscript, makes the minimum changes to the templates and application.conf files.
Transparent Compression
GreenScript support Transparent Compression start from v1.2b. With Transparent Compression, even you don’t use greenscript tag, your js file and css file will automatically get compressed even without your attention (in PROD mode).
In conclusion, GreenScript is a flexible and powerful javascript/css management tool for your Play applicaiton development. You can use it in simple way (zero configuration) or in a way sophsicated enough to manage your complicated javascript and css dependencies.
CDN Support
Greenscript support CDN start from version 1.1a.
Configure CDN dependencies
# Note you must escape ':' if it is in the 'key' part, no need to escape if
# it's in the 'value' part. This is due to the java.util.Properties treat ':'
# as separator between key and value
js.http\://ajax.googleapis.com/ajax/libs/scriptaculous/1.8.3/scriptaculous.js=http://ajax.googleapis.com/ajax/libs/prototype/1.6.1.0/prototype.js
Load CDN items in tags
#{greenscript.js 'http://www.google.com/jsapi' /}
FAQ
I found there is no javascript and css links at all in my html file rendered out!!
Make sure you have add the following lines in your main.html (or in any other name) template:
#{greenscript.css "css files separated by blank", output:'all'/}
#{greenscript.js output:'all'/}
Do I need to surround #{greenscript } tag with #{set ‘moreStyles’} in my other templates?
No, you just use #{greenscript.css ‘...’ /} to declare your css files. With greenscript, you can say ‘byebye’ to ‘moreStyles’ and ‘moreScripts’.
How to use GreenScript? Is it hard to configure?
You can use GreenScript with zero configuration. However, it’s suggested to create “greenscript.conf” file to describe your javascript and css file dependancies. You will love this feature because you just need to declare explicitly used javascript/css files in your templates, leave the dependencies to GreenScript.
I want to debug javascript, can GreenScript output uncompressed version of javascript/css files?
Yes, put “greenscript.minimize=false” in your application.conf file. Actually the setting is turned off by default when you are running app in “dev” mode. An nice feature you can use is dynamic configuration which enable you turn on/off minimizing/compressing without restart your app. See Configuration at runtime section for detail
Why don’t you use GreenScript in the dynamic configuration feature?
Well, I have no idea how you will configure the dir/url path settings, so I have to hard code my javascript/css links in my template. Fortunately it’s not a big work for a single page web app ;-)