Wednesday, February 27th, 2008

Include: Pack your JavaScript with ease

Category: JavaScript, Performance, Utility

Brian Moschel just told us about Include:

It determines which files to compress at runtime and automatically compresses them into one script using Dean Edwards’ Packer.

You can include any JavaScript from any other JavaScript with a relative path:

javascript

  1. include('myscript.js');

Then turn on compression like this:

javascript

  1. include.setup({env: 'compress'});
  2. include('javascripts/prototype', 'javascripts/myapplication');

When you reload the page, a window will open that contains a list of the scripts as they are loaded, the uncompressed collection of code, and the code compressed with Packer. You save the compressed code on your server and turn on production mode:

javascript

  1. include.setup({env: 'production', production: 'path/to/prod'});
  2. include('javascripts/prototype', 'javascripts/myapplication');

Scripts load in the same order across all browsers (last-in first-out), which is nice, considering document.write by default works differently in Opera.

Another aspect we’re excited about is that Include makes it so you’ll never have to write a custom server-side compression script again. Since the scripts to compress are determined at runtime, you can easily compress large libraries with conditional plugins, like TinyMCE.

javascript

  1. if (selected_plugins['fullscreen']);
  2.     include('dependencies','fullscreen');
  3. // conditionally include plugin
  4. if (selected_plugins['search']);
  5.     include('search');

Instead of duplicating that logic in a server-side script, you can choose your plugins, turn on compress mode, and you’ve got your compressed code. To demonstrate this, we ported TinyMCE and plugins to use Include.

Include is open-source with an MIT license. I hope you find it as useful as we have.

Posted by Dion Almaer at 12:24 am
8 Comments

+++--
3.6 rating from 34 votes

8 Comments »

Comments feed TrackBack URI

Interesting idea but server side concatenation and gzip compression is still the best way of reducing script size. But I’ve been having an idea to use Flash to load compressed contents this way it can be done 100% client side and still be gzipped one could make a detection script to use Flash if flash is enabled in the browser it otherwise fall back to an old school loading method. I think this would be possible but I haven’t tired it.

Comment by Spocke — February 27, 2008

Include produces a list of included files which can be used in a ‘standard’ compression script. We’ve written one of these compression scripts for Rails. The great thing about these ‘standard’ scripts is that only one needs to be written per language – ever. You can still get your server-side compression, concatenation, and gzip, but you won’t have to write the script yourself. You simply provide the script a list of files to be compressed.

Comment by JustinMeyer — February 27, 2008

Scripts load in the same order across all browsers (last-in first-out), which is nice…

Huh? Nice? Every server-side compression script I use works like HTML: First In First Out. Makes sense to me, load jQuery first, then its dependent plugins. Plus, isn’t the overhead of packing well-known to be slower than gzip in most applications, as Spocke suggested?
.
Ok, I see that they’re suggesting that every time I change my script, I re-run their packer method through my browser, and then save and upload a new file? Also, after ‘setup’ I have to change the HTML file to ‘production’ mode? Why not just paste the damn packed JS into my HTML, since Include is handing it to me, and save an HTTP request? Wouldn’t that save a lot more time?
.
+1 @JustinMeyer — I can appreciate it giving me a list of the file and its dependencies, and compressing server-side with automatic caching and almost no extra work. That’s why I use Minify (PHP). Also, what is wrong with the build/make method, used by the major frameworks?

No need to repeat any plugin loading logic in a server-side script.

Instead, just the plugin logic is client-side, and still requires the same type of code, and possibly more work.
.
What advantage am I missing? I would like to see some hard numbers on load times, comparisons with other methods are conspicuously absent. Perhaps I should put up a flashing neon sign for those who missed the boat, gZip & server-side concat & caching FTW.

Comment by Charles — February 27, 2008

Let’s break this down a little:

On FILO … I wrote include to mimic how most libraries that load plugins, load them. They all use document.write( script tag ). Include loads the same way document.write would loads scripts. Its FILO between files, and FIFO within a file.

Also, you have to do FILO if you want to support loading dependencies. I can explain why if needed.

Now, there are more libraries than just TinyMCE that can automatically load plugins for you. This is a nice feature. Users don’t have to be bothered adding a script tag for everything feature they want. It allows for cooperation between plugins to load only what they need. For example in the framework Include was built for, JavaScriptMVC, if someone loads Prototype, it will not load its own Event, Ajax, and CssQuery functionality. I call this library INTERdependence. Frameworks like MooTools kinda provide this, but you have to go to their site to get your custom version. How would you provide this ability and still let your framework be easily compressed?

Include makes this very simple since it provides a way to easily load files in JavaScript, and a way to compress them without recreating all that logic server side.

On being slower … The default behavior is not to pack the JavaScript but to simply shrink temporary variable names. So there is no cost of unpacking, since it doesn’t happen. For our applications, we typically compress and gzip.

Yes, you could paste the file directly into your html. However, there are times (JavaScriptMVC’s documentation pages being an example), where you want the same JavaScript to run across all pages. This wouldn’t be suggested in this case.

What’s wrong with the build/make methods used?

The build/make methods cannot easily compress things like TinyMCE. And for every library like TinyMCE, or JavaScriptMVC, those that allow you to dynamically include JavaScript files, you would have to create a special compressor for each framework. TinyMCE has one for Rails, Asp, JSP, Coldfusion, etc. But, with include, there only EVER has to be one server-side compressor per framework. And the hobbyist can still compress their app without even having to setup server-side compression scripts.

Instead, just the plugin logic is client-side, and still requires the same type of code, and possibly more work.

I’m confused by this. Yes, the plugin logic is client side. It requires you to include your javascript files. But you do that with or without include. If your page has loads of script tags, you are basically writing the same thing as include(‘file1′,’file2′,’file3’). However, you don’t have to write something that compresses them. Include takes care of that for you. I don’t see how this is more work.

What comparisons would you like to see? Include vs gZip wouldn’t make sense because you can still do that.

After actually using include, I find it very useful. It adds no cost to having lots of JavaScript files. I know that no matter how complex the dependencies get, it will still compress. I don’t have to worry about modifying my compression script.

For things like JavaScriptMVC’s documentation, I just used the client side compression. However, when I’ve worked on more serious applications like F->IT (http://fit.jupiterit.com), I use the server-side compression.

Using include with F->IT was great because it relies on EditArea which can load its own plugins. Once I was no longer adding files to EditArea, and getting ready to try it out in production, I used the client to provide a list of files. I put that in the appropriate place for the server-side script, added that to Capistrano, and changed
include({env: ‘development’})
to
include({env: ”})

And now everytime I migrate to production, it generates a new production script from that list of files, and loads that in production.

Easy as pie. Much easier that it would have been to write my own custom ruby compression script for EditArea.

Comment by JustinMeyer — February 27, 2008

sorry, that last include didn’t turn out right

include({env: '<%= @environment>'})

Comment by JustinMeyer — February 27, 2008

On F->IT (http://fit.jupiterit.com), using include, we take 431 kb of JavaScript files to 180 kb using include. Gzip takes it from 180kb to 60 kb (this is production.js seen in firebug).

Comment by JustinMeyer — February 28, 2008

I have no idea, why compressing js in the browser is usefull.

Comment by Aimos — July 15, 2008

compressing isn’t as much as joining

Comment by JustinMeyer — March 18, 2009

Leave a comment

You must be logged in to post a comment.