Plugins - Holly
Add to favoritesHolly
Holly is an automated dependency manager for JavaScript and CSS assets in Ruby on Rails projects. Its name is ‘Holly’, as in ‘the holly and the ivy’, Ivy being a Java-based dependency manager. It was begun just after Christmas and I had to call it something.
Copyright © 2008 James Coglan, released under the MIT license
The problem
You’re building part of your site, which has a little bit of script on the page. Something to the effect of:
var myWidget = new Widget('elementID');
To implement that, you know you need to include the .js file for Widget, so you put this in the document’s head:
<%= javascript_include_tag 'widget' %>
What you don’t know (and what I don’t think you should need to know) is that Widget uses dragdrop.js, which itself relies on effects.js, which again relies on prototype.js. Holly allows each script/css file to declare its dependencies using special comments. Whenever you use javascript_include_tag or stylesheet_link_tag, Holly examines the file’s dependencies and makes sure they are included into your HTML, in the correct order and without duplication. This allows all script files to make sure they will run properly when loaded, and to load additional script files and stylesheets without the template author needing to know which files to add to the page.
How to use
Let’s say our Widget class lives in widget.js. It has two other classes it uses; Widget.Item in widget/item.js and Widget.Page in widget/page.js. These classes should be loaded after Widget. It needs dragdrop.js to be loaded first, and it also has a stylesheet associated with it, called widget.css. Add the following lines to the top of widget.js:
// @require dragdrop // @load widget/item // @load widget/page // @load widget.css
dragdrop.js has it own dependencies. Add this line to dragdrop.js:
// @require effects
and this line to effects.js:
// @require prototype
You can also use /* comment syntax - as long as the line begins with a comment opening, it will be parsed by Holly.
Now, when you call javascript_include_tag ‘widget’, you’ll get:
<script src="/javascripts/prototype.js" type="text/javascript"></script> <script src="/javascripts/effects.js" type="text/javascript"></script> <script src="/javascripts/dragdrop.js" type="text/javascript"></script> <script src="/javascripts/widget.js" type="text/javascript"></script> <script src="/javascripts/widget/item.js" type="text/javascript"></script> <script src="/javascripts/widget/page.js" type="text/javascript"></script> <link href="/stylesheets/widget.css" media="screen" rel="stylesheet" type="text/css" />
If any of these assets have already been rendered to the page, they will be omitted; Holly will not allow javascript_include_tag or stylesheet_link_tag to render any asset more than once per request.
@require vs. @load
@require means that the given file must be loaded before the current file. @load means that the given file should be loaded after the current file. Files are rendered to the page as early as they are required, and as late as they are loaded.
Source resolution
It may help you to know how Holly resolves paths to files you require or load. Follow these rules and you shouldn’t go wrong:
- Remote URLs: these are left unmodified unless they lack a file extension. .js is added if the URL is within a JavaScript file, .css if within a CSS file.
- Absolute paths: these are also left untouched unless they lack a file extension. If the path begins with /javascripts/, a .js extension is added. If the path begins with /stylesheets/, a .css extension is added. Otherwise, an extension is added based on which type of file is making the require or load call.
- Relative paths: these are resolved relative to /javascripts/ or /stylesheets/. If the given filename has an extension, that extension is used to determine the directory. For example, if you @require widget/item.js, that will always look for /javascripts/widget/item.js, whether you call @require from a JavaScript or a CSS file. If no extension is present, Holly assumes that you want a .js file if the current file is .js, and a .css if the current file is .css.
Rake tasks
Holly provides some rake tasks for inspecting the dependencies of the script/css files in your project. Just run rake holly:inspect q=somefile to see a report on its dependencies. For example:
> rake holly:inspect q=effects.js
Requires:
/javascripts/prototype.js
Loads:
(none)
Full expansion:
/javascripts/prototype.js
-> /javascripts/effects.js
Referring files:
/javascripts/dragdrop.js
Dependants:
/javascripts/dragdrop.js
/javascripts/widget.js
> rake holly:inspect q=widget.js
Requires:
/javascripts/dragdrop.js
Loads:
/javascripts/widget/item.js
/javascripts/widget/page.js
! /stylesheets/widget.css
Full expansion:
/javascripts/prototype.js
/javascripts/effects.js
/javascripts/dragdrop.js
-> /javascripts/widget.js
/javascripts/widget/item.js
/javascripts/widget/page.js
! /stylesheets/widget.css
Referring files:
(none)
Dependants:
(none)
Requires and Loads list the files directly referenced by somefile. Full expansion shows the full list of assets loaded by Holly when you include somefile in one of your pages, in order. -> indicates somefile in the list. In all these lists, a ! next to a filename indicates that the file is missing. Referring files lists all the files that contain direct references to somefile, and Dependants lists any files whose full expansion contains references to somefile.
