Client-side assets management with ASPAX
What if you could watch, compile, concatenate, minify, compress and fingerprint all your web assets using just a simple file written in clear, human-readable YML syntax?
A few weeks ago, I was having a chat with a couple of fellow Node.js developers about the importance of client-side asset management and packaging.
As we all know, although no more than two years ago Node.js was just an exotic emerging technology, it now lays a solid foundation for building really fast web applications and websites. However, the "snappy" behaviour of your products depends on more than just the underlying platform speed, one of the other factors being the way you're packaging and delivering your client-side assets to the browser.
For maintainability and readability during development, you want your scripts and style files in a rich and meaningful hierarchy - everyone using Backbone.js, Bootsrap / Zurb plus five or six other libraries surely knows what I'm talking about. And not all of them are suitable for CommonJS/Component usage style. Not to mention the fact that some of us like CoffeeScript, some prefer to write in LiveScript, and some favour Stylus or LESS over plain CSS. It's a rich and free ecosystem, but browsers only understand plain JS and CSS.
For the sake of speed, in your production environment you'll want all your files concatenated, minified and compressed as efficiently as possible - ideally just one app.js
file and one app.css
file.
And there's also the issue of fingerprinting - if you care for speed, you'll want to use browser and proxy caching to the maximum, which means you're also going to need a "cache busting" mechanism.
In the RoR world, there's the excellent Asset Pipeline that helps you achieve all that.
In the world of Node.js, there is, of course, more than just one way to do it, but lately more and more developers are talking about using the excellent Grunt task runner for client-side asset management and packaging. While grunt is an extraordinary general purpose tool, there are people (including myself :-P) who believe that writing a complex asset management Gruntfile.js
is a bit cumbersome and runs the risk of becoming difficult to maintain for medium-to-large projects. Too much configuration, too much code mixed with file names... For instance, this sample gruntfile is a very simple one; I've seen asset management scenarios measuring over 300 lines.
So why not sticking to convention over configuration and sensible defaults instead?
What if you could watch, compile, concatenate, minify, compress and fingerprint all your web assets using just a simple file written in concise yet human-readable YML syntax, like this:
js/app.js|fp|min|gz:
- lib/bootstrap/js/bootstrap.js
- lib/moment.js
- lib/jade/runtime.js
- scripts/namespaces.coffee|bare
- templates/item.jade
- scripts/index.ls|bare
css/app.css|fp|min|gz:
- lib/bootstrap/css/bootstrap.css
- lib/bootstrap/css/bootstrap-theme.css
- styles/index.styl|nib
favicon.png: images/favicon.png
fonts/bs-glyphs.eot|fp: lib/bootstrap/fonts/glyphicons.eot
fonts/bs-glyphs.svg|fp|gz: lib/bootstrap/fonts/glyphicons.svg
fonts/bs-glyphs.ttf|fp|gz: lib/bootstrap/fonts/glyphicons.ttf
fonts/bs-glyphs.woff|fp: lib/bootstrap/fonts/glyphicons.woff
No complicated .initConfig()
, no redundant code to describe tasks in JavaScript or CoffeeScript, just a simple YML file in your assets folder.
If you like the idea, please have a look at ASPAX, a command-line utility I've bee working on that enables you to do just that - manage your client-side assets based on a single, human-readable YML file.
Ok, there are also plugins you have to install for compiling various source file types (.coffee
, .styl
, etc., just as you have in the Grunt ecosystem), but since ASPAX aims to be just an asset management tool, there's a lot less plumbing and configuration to do than you'd normally need for a grunt scenario.
At the moment, there's a spartan mobile-friendly project website hosted on GitHub at aspax.github.io, a quick step-by-step tutorial on using ASPAX with Express.js here, and plugins to handle six common source file types:
- aspax-coffee-handler for CoffeeScript;
- aspax-iced-handler for IcedCoffeeScript;
- aspax-ls-handler for LiveScript;
- aspax-jade-handler for client-side Jade templates;
- aspax-styl-handler for Stylus;
- aspax-less-handler for LESS.
Oh, and there's also a demo repository with an Express.js application here: aspax-demo.
Hopefully I'll get back in January with a module for koa.js and another tutorial...
Thank you all for reading so far, please feel free to have a look at the project page and GitHub repos, give it a try and share your thoughts here! :-)
UPDATE:
Thanks to Eugeny Vlasenko's feedback, we're most likely going to drop the asset compression feature in favour of using St or similar middleware in the application.
Written by Ionut-Cristian Florescu
Related protips
10 Responses
Thanks for the post, it's a VERY important issue obviously. I'm missing however your comparison to Grunt tasks in this case, do you have some insights about that?
Thanks for the ASPAX, it's great!
I have exactly the same basic ideas:
...plus five or six other libraries surely knows what I'm talking about. And not all of them are suitable for CommonJS/Component usage style.
Even if they support the package system, it is not useful if for example you need a custom build of bootstrap (CSS and JS).
excellent Asset Pipeline
Yeah!
A complex asset management Gruntfile.js is a bit cumbersome and runs the risk of becoming difficult to maintain for medium-to-large projects.
Yes, build phase should be separated from asset management phase.
I think ASPAX should do:
For small projects:
- watch and compile only by plugins (build phase)
- concatenate, minify and fingerprint
- copy file to assets directory
For medium-to-large projects:
- only watch changes
- concatenate, minify and fingerprint
- copy file to assets directory
For large projects, it makes sense to divide build to compile phase and asset management phase. Complex assets can be compiled by well known tools like Grunt or Make (not 300 lines of code but 100). And complex asset management phase can be done by ASPAX.
But I also have a few questions and remarks:
- I find it more appropriate to use hash like fingerprint. To avoid unnecessary "cache busting" for identical files. example
- Executing not JavaScript files are not best practice (Iced Coffee in this case). And it is deprecated
- File compression is a task for static server. In case of express it is compress middleware. It compresses according to http headers, not for all requets.
I think that I can close my similar project and join to ASPAX development.
Hi @sagish,
Thank you for reading!
I'm planning to do a Gruntfile.js
vs. aspax.yml
comparison soon and I'll let you know about it :-)
Hi @mahnunchik,
Thanks a lot for your feedback!
Just a few quick comments on your questions/remarks:
About using hash fingerprints to avoid unnecessary cache busting - yes, that's a very good idea, I thought about it but couldn't come up with a clean and elegant solution. It would be kind of complicated to implement, since ASPAX is also replacing asset URLs in CSS files where needed. Please have a look at the code and if you can come up with a solution, I'm open.
Executing non-js files (ICS in this case) - this has already been addressed in CoffeeScript here and ported to IcedCoffeeScript 1.6.3-j, that's why I'm using
require('iced-coffee-script/register')
.Compression with ASPAX vs. server compression - yes, it can be done with compress or a static server, but as far as I remember there's no caching mecanism behind the "standard" compress connect-middleware. So I see no reason why it shouldn't be done just once before deployment, especially since all contemporary browsers suport gzip.
I see this feature useful for (let's say small) projects deployed on PaaS providers like Heroku or OpenShift without using a separate server (i.e. nginx) or a CDN for static assets.
I'm not sure I follow you on what ASPAX should do for small vs. medium or large projects, though...
Hi @icflorescu,
I have created issue for each question/remark https://github.com/icflorescu/aspax/issues
I think it will be more convenient than discuss all together.
Hi @mahnunchik, thanks a lot for your feedback! Yes, it makes sense to carry on this discussion on GitHub. I'll just mention here that St does look good, which means we could probably drop the compression feature entirely from ASPAX.
Jonah Ruiz is also interested in contributing to ASPAX, so let's see what we can do :-)
@sagish - a Gruntfile.js
vs. aspax.yml
comparison, as promised :-P
@icflorescu @jonahoffline I hope that we can make a great tool like Asset Pipeline!
@mahnunchik - Sprockets has years of development behind and a well-deserved place in RoR world. Can't really hope to achieve the same with ASPAX :-)
Leaving the joke aside, I'm not sure there's room for something so complex, complete and well-established as Sprockets in the Node.js world. The ecosystem is much more dynamic than Ruby/RoR, things are changing really fast, Harmony is closing in, a new frameworks will soon become the de-facto standard for a while...
Personally, I'd rather keep ASPAX codebase as simple as possible and choose to focus on plugin development. So, if you have an idea...
The ecosystem is much more dynamic than Ruby/RoR, things are changing really fast,
Personally, I'd rather keep ASPAX codebase as simple as possible and choose to focus on plugin development. So, if you have an idea...
Yes, NodeJS community likes simple and small modules for solving only one problem (like unix=). In this case comparison with Sprockets was inappropriate.