Sass and Sprockets for Rails 3.1

UPDATE: This article is definitely out of date now. The new sass-rails gem will augment Sass to handle dependencies, load paths, and Rails helpers (like asset_path) in a Sprockets environment. I’m now including edge versions of sass-rails and compass in my Gemfile and everything is working smoothly in development. I no longer have to use Sprocket-style *= require directives, just Sass @imports.

I’m a big fan of the new asset pipeline features in Rails 3.1. I’ve spent way too much time building my own JavaScript and CSS precompilers or forcing Sprockets 1.0 to do things it wasn’t intended to do. When I started using Sprockets 2.0 with Sass and Compass, there were some gotchas I didn’t anticipate and I was surprised not to see bug reports about them. As it turns out I was thinking about it all wrong. Here’s a quick explanation in case other people have the same problem.

I’m used to using Sass with one master stylesheet and several partials, like so:

// application.scss
  1. @import "compass";
  2. @import "common"; // Defines variables and mixins
  3. @import "home"; // Uses variables and mixins defined in _common.scss
  4. @import "checkout"; // Like _home.scss

In Rails 3.1 and Sprockets, this doesn’t work for two reasons:

  1. Sprockets isn’t aware of @import statements in Sass, so it doesn’t invalidate the cached master stylesheet when one of them changes. You can use the *= depend_on directive to handle this, but then you have to list your partial files twice.
  2. If you reference images in assets/images, the Rails precompiler rewrites those files names with an md5 hash, like assets/bg-9c0a079bdd7701d7e729bd956823d153.png (as described in this post on Rails 3.1 in production.) Sass can’t preprocess files with ERB, so you can’t use asset_path.

Being able to use ERB is pretty huge, so I realized I had to use Sprockets require directives to get that preprocessing. But you can’t just require "compass" at the top (it’s not in the load path) or be able to share variables and mixins with a single require.

The trick is to think of Sass files like Ruby files: if you depend on functionality in another file, you have to explicitly include it each time. So my example above becomes:

// application.css.scss
  1. /*
  2.  *= require_self
  3.  *= require "home"
  4.  *= require "checkout"
  5.  *= depend_on "_common"
  6.  */
  7. @import "compass/reset"
// home.css.scss.erb
  1. @import "compass";
  2. @import "common";
  3.  
  4. body {
  5.   background: url();
  6. }
// checkout.css.scss.erb
  1. @import "compass"; // again!
  2. @import "common"; // also again!

I still had to add a depend_on directive for the partial so that application.css updates when that file changes, but otherwise this solution solves all my problems and I have maximum flexibility.

Let me know if I’m overlooking something simple! And this post will probably be out-of-date soon as the Sprockets guys starting adding documentation.

UPDATE: Came across another gotcha today. You can’t use asset_path inside partial Sass files included with @import, so any shared styles can’t reference image files. Arg.

PS: This is how you get Compass in the Sass load path (I forgot where I stole this from):

# config/initializers/sass.rb
  1. Sass::Engine::DEFAULT_OPTIONS[:load_paths].tap do |load_paths|
  2.   load_paths << "#{Rails.root}/app/assets/stylesheets"
  3.   load_paths << "#{Gem.loaded_specs['compass'].full_gem_path}/frameworks/compass/stylesheets"
  4. end

Proof of Concept: Bindings in JavaScript

In another attempt to copy ideas from Actionscript 3 to JavaScript, I spent a few hours trying to implement bindings. I may try to implement an MVC framework like Cairngorm in JavaScript someday, and bindings play an important role in Flex and Actionscript.

Bindings keep UI elements in sync with data with minimal code. In Cairngorm, all application data lives in a ModelLocator singleton, so UI elements have a single point of reference for application data.

I’m sure there are many ways to implement binding in JavaScript, but I started with my ideal API:

Binding.bind(object, “property”, object2, “property2″);
  1. That method call does a few simple things:
  2. <ol>
  3.  <li>Adds generic getter and setter methods. The setter has a hook into the binding utility.</li>
  4.  <li>If an object is an applicable HTML element, it adds the appropriate event listeners that hook into the binding utility.</li>
  5.  <li>It stores the respective object/property pairs for each object.</|>li>
  6. </ol>
  7. This implementation forces you to use <code>object.set("propertyName", value)</code> in order to trigger binding. The binding trigger can easily be implemented in custom objects as well with this method call:
  8. <pre>Binding.trigger(object, "propertyName");

Where object is the bound object. This creates a cascade of calls setting the appropriate values on properties of other bound objects.

I avoided recursion by creating a unique transaction id every time Binding.trigger is called. The set method passes this id along internally so no object is changed twice in the same transaction.

So far I only support text and checkbox inputs, textareas, and select dropdowns. The selected option in a select dropdown doesn’t amount to a single property, but instead to element.options[element.selectedIndex].value. It was easy to override the get and set methods to allow Binding.trigger(element, "value").

See the example and check out the code. I used the Flow JavaScript library to normalize the DOM API (really just for addEventListener), but it doesn’t rely on any particular library.

Developing Silverlight 1.0 RIAs: JavaScript Optimization

(Read the intro here.)

My appreciation and respect for JavaScript increased tremendously while developing Silverlight projects. Not at all because of how easy it was to work with. But its flexibility and power made it interesting and fun to tackle challenges like optimization and application architecture.

Optimization

In Silverlight 1.0, the plugin is only a rendering and animation engine. All of the logic and much of the processing still resides in the browser’s JavaScript interpreter. All web applications need to make optimization a priority, but this is especially true for Silverlight 1.0 applications.

Doing a lot of small things can add up to make a big difference. Swap myArray.push(obj) with myArray[myArray.length] = obj. Avoid string concatenation when possible to give Internet Explorer a little boost.

I made two significant changes to my code between the WWE project and the last Library of Congress project that I believe made a big difference.

Avoid Function.bind

I usually resorted to a Function.bind method (usually the version in prototype.js) to manipulate function scope. This really comes in handy for event listeners:

// inside of a class
  1. function addMouseEvents() {
  2.     this.xaml.addEventListener('MouseEnter', this.onMouseEnter.bind(this));
  3.     this.xaml.addEventListener('MouseLeave', this.onMouseLeave.bind(this));
  4.     this.xaml.addEventListener('MouseLeftButtonDown', this.onMouseDown.bind(this));
  5. }
  6.  
  7. function onMouseEnter(sender, mouseArgs) {
  8.     // "this" still refers to the instance of the class
  9. }

I really like this syntax, even though in an ideal world it wouldn’t be necessary. (Actionscript 3 is an ECMAScript implementation that fixes this). I’ve heard Mozilla might implement it natively, which would be lovely.

The problem with bind() is that it uses apply() internally, which is significantly slower than just executing the function. This makes a big difference for MouseMove or ProgressChanged event handlers.

Fortunately it is easy to avoid, and there are a number of ways to use depending on your personal preference. I usually used:

// inside of a class
  1. function addMouseEvents() {
  2.     var that = this;
  3.     this.xaml.addEventListener('MouseEnter', function(sender, args) {
  4.         that.onMouseEvent(sender, args);
  5.     });
  6.     // .. other events
  7. }

I looked around for any documentation on the effects on bind() on performance and found nothing. This isn’t a Silverlight-specific issue but something other people might run into so it’s probably worth documenting.

Using and Removing Event Listeners

This also isn’t necessarily Silverlight-specific, but it’s also worth mentioning because of a few difference from how HTML DOM event listeners are handled. The crux of the matter is still that adding event listeners is memory intensive and not disposing of them properly can cause leaks and sluggishness.

In HTML you can use event delegation to limit the number of event listeners added. Add a single click event listener to a parent object, and act upon the event based on on the target property of the event, which is usually a child of the parent object. This isn’t possible in Silverlight 1.0 because there isn’t a real event object. The sender argument sent to the listener is always the object to which the event was added.

The only way to combat the overhead from adding event listeners is to reuse objects when possible. For WWE, there is a big grid of thumbnails the user can click on. Instead of creating a whole new grid each page refresh, I just changed the data for each item.

Sometimes reuse isn’t an option, and you’re forced to create and destroy XAML objects repeatedly. Removing event listeners before destroying an object isn’t difficult.

var eventToken = xaml.addEventListener('MouseEnter', function() { … });
  1. xaml.removeEventListener('MouseEnter', eventToken);

I came up with a way to store those event tokens in a simple, behind-the-scenes manner, which made this easier to do than not do. I’ll describe this in the next section on JavaScript/Silverlight Architecture.

Adding CSS rules with JavaScript to hide content on page load

Update: I’ve had to update the code to get it to work reliably in Safari 2. Much thanks to this article on the YUI Blog for another solution.

A lot of ajax-y web pages involve hiding and showing content. My current project has a tons of content related to a video in dynamic reveals that the user can open and close. Of course, accessibility is important, so for users without JavaScript enabled, all of this hidden content should be visible.

Typically, JavaScript would explicitly hide this content as soon as it is available. Something like:

// using prototype.js
  1. document.observe("dom:loaded", function() {
  2.   // initially hide the reveal container
  3.   $('revealContent').hide();
  4. });

I chose prototype.js because of its notorious file size, and I know a lot of you still don’t compress and gzip their JavaScript! If you’re loading a lot of JavaScript, HTML, and CSS, chances are pretty likely that the #revealContent element will display before that that function has a chance to run.

So how do we hide that element before it has a chance to load? The technique I’m using adds a CSS rule to a new stylesheet as soon as possible, i.e. when the JavaScript is interpreted.

/* Add a rule in CSS that lets you override the generated rule */
  1. #revealContent.show {
  2.     display: block;
  3. }
// JavaScript

var CSSRules = function() {

	var headElement = document.getElementsByTagName("head")[0],
		styleElement = document.createElement(”style”);
	styleElement.type = “text/css”;
	headElement.appendChild(styleElement);

	// memoize the browser-dependent add function
	var add = function() {
		// IE doesn’t allow you to append text nodes to
 elements
		if (styleElement.styleSheet) {
			return function(selector, rule) {
				if (styleElement.styleSheet.cssText == ”) {
					styleElement.styleSheet.cssText = ”;
				}
				styleElement.styleSheet.cssText += selector + ” { ” + rule + ” }”;
			}
		} else {
			return function(selector, rule) {
				styleElement.appendChild(document.createTextNode(selector + ” { ” + rule + ” }”));
			}
		}
	}();

	return {
		add : add
	}
}();

CSSRules.add(’#revealContent’, ‘display: none !important’);

// later
$(’revealContent’).addClass(’show’);
</pre>
<p>I haven’t tested this exhaustively, but it works as intended in Internet Explorer 6 and 7, Firefox 2 and 3, Safari 2 and 3, and Opera 9. I originally expected some strange behavior from adding elements to the <code>&lt;head&gt;</code> before it finished loading, but fortunately this isn’t the case.</p>
<p>You could also include a stylesheet or a <code>&lt;style&gt;</code> tag in a <code>&lt;noscript&gt;</code> tag, but I prefer to keep all of this behavior in JavaScript.</p>
<p><strong>Update:</strong> The old code:</p>
<pre lang=”javascript”>
// JavaScript
var CSSRules = function() {

    // create a stylesheet
    var stylesheet = document.createElement(”style”);
    stylesheet.setAttribute(”type”, “text/css”);
    document.getElementsByTagName(”head”)[0].appendChild(stylesheet);
    stylesheet = document.styleSheets[document.styleSheets.length - 1];

    return {
        add: function(selector, rule) {
            // the Microsoft method
            if (stylesheet.addRule) {
                stylesheet.addRule(selector, rule, 0);

            // the standard method
            } else if (stylesheet.insertRule) {
                // safari 2 apparently ignores this
                stylesheet.insertRule(selector.concat(’{’ + rule + ‘}’), 0);
            }
        }
    };
}();

CSSRules.add(’#revealContent’, ‘display: none !important’);

// later
$(’revealContent’).addClass(’show’);
</pre>

Developing Silverlight 1.0 RIAs: XAML

(Read the intro here.)

First, XAML is an awkward language to work with. From a business perspective, this makes sense because Microsoft can push their Expression suite on developers and designers. But this is unacceptable for a client-side developer who wants to write markup by hand and is a Mac user.

XML is a terrible vehicle for describing anything more complicated than nested boxes. It is especially terrible with vectors. This is XAML generated by Blend to describe a tiny arrow pointing left:

  1. <Path Width="5" Height="11.061" Fill="#FFFFFFFF" Stretch="Fill"
  2. Data="M441.46101,604.74493 L445.48904,608.88653 441.52674,613.46898
  3. 442.43734,614.14997 446.91423,608.85206 442.3852,604.04503 z"
  4. Opacity="1" x:Name="back_arrow" Canvas.Left="6" Canvas.Top="8"
  5. RenderTransformOrigin="0.5,0.5">
  6.  <Path.RenderTransform>
  7.   <TransformGroup>
  8.    <RotateTransform Angle="-180"/>
  9.   </TransformGroup>
  10.  </Path.RenderTransform>
  11. </Path>

Opening up 2000 line XAML files full of markup like this is headache inducing.

Second, XAML in SL 1.0 is the Anti-DRY language. It lacks concepts like cascading styles and class names, so if you want all your TextBlock elements to be red, you have to specify Foreground="#FFFF0000" for each one.

It gets worse for repeating elements programmatically. Say you have XAML for a button with a TextBlock label, and you want to create four of them to make a menu:

  1. <Canvas Width="100" Height="20">
  2.  <Rectangle Fill="#FF000000" RadiusX="5" RadiusY="5"
  3.   Width="100" Height="20">
  4.   <TextBlock x:Name="buttonLabel" Canvas.Top="3"
  5.    Canvas.Left="5" Foreground="#FFFFFFFF">Label</TextBlock>
  6.  </Rectangle>
  7. </Canvas>

Of course, you’ll want programmatic access to that TextBlock so that you can change the label text. But because there is only one namespace for x:Names (x:Name="buttonLabel" can only be used once), adding more than one to the XAML hierarchy will throw an exception. Also, there are no utilities like .getElementsByTagName. Solutions like button.children.getItem[0].children.getItem[0] are brittle and don’t scale.

There is a solution to this, but it was nearly impossible to find in the Silverlight 1.0 documentation. The createFromXaml method takes a second boolean argument that can create a new, separate namespace for x:Names. This allows you to create multiple XAML objects from the same source and add them to the XAML hierarchy without x:Name collisions.

A caveat to this technique is that findName won’t find elements created in a new namespace, so you have to save a representation of each new element in JavaScript.

My methodology for using XAML tries to tackle these two big challenges. It breaks down to these steps:

  • Use images instead of XAML vectors when the file size overhead allows it.
  • If Blend is used, only create small, isolated pieces of XAML so each is easier to digest and manipulate.
  • Zip up every XAML file and download it all at the beginning. XAML files are usually light enough that it shouldn’t noticeably delay the start of your application.
  • Create XAML elements dynamically from the files in the zip file. Use createFromXaml(text, true) for repeated elements and always save a representation of the elements in JavaScript to manipulate later.

I built a number of utility functions to make this methodology very easy to use. Here is an example:

  1. var ComplicatedXamlCreator;
  2. new XamlDownloader('cmn/xaml/packaged/xaml.zip', {
  3.     onComplete : function(zip) {
  4.         ComplicatedXamlCreator = zip.save('complicatedXaml.xaml');
  5.         zip.destroy();
  6.     }
  7. });
  8.  
  9. // later, create a xaml object and add it to the XAML hierarchy
  10. var xaml = ComplicatedXamlCreator(true);
  11. root.children.add(xaml);
  12.  
  13. // or create multiple xaml objects and manipulate independently
  14. for (var i = 0; i < 10; i++) {
  15.     var xaml = ComplicatedXamlCreator(true);
  16.  
  17.     // finds a different TextBlock element each iteration
  18.     var label = xaml.findName('label');
  19.     label.text = 'Button Label ' + i;
  20.  
  21.     root.children.add(xaml);
  22. }

My XamlDownloader utility is a simple wrapper for the Downloader class that passes back an instance of a ZipHandler class. The save method grabs a XAML file out of the zip file and returns a XAML creation function that can be run as many times as necessary.

Because the XamlDownloader utility creates a closure around a Downloader instance, you have to destroy that instance or you’ll create a massive memory leak. The WWE project would bring down a fresh instance of Firefox 2 in half an hour easily.

Developing Silverlight 1.0 RIAs

This will be the archive for my advancements in Silverlight 1.0 development, now made pretty much obsolete by the 2.0 Beta 2 plugin released last week.

I’ve worked on four SL 1.0 projects:

All of these projects were developed under extremely tight deadlines and generally had ad-hoc development processes. HSN was a mess because the plugin was released after development had started. The first LOC projects had a lot of UX, creative, and project management complications. WWE actually followed our architecture and development processes very well but it was an overly ambitious project for a technology this immature.

For the last LOC project, I was finally able to piece together techniques developed over the last six months. It was still a very tight deadline and inevitably a bit ad-hoc, but I am still proud of it.

Challenges in Silverlight 1.0 Development

Silverlight 1.0 development is difficult by its reliance on two technologies:

  1. XAML
  2. JavaScript

Of course, that’s all there is to Silverlight 1.0! On top of that, it’s a buggy plugin, but there’s not much we can do about that. Instead, I’ll focus on ways to address the challenges presented by SL 1.0’s core technologies.

Alex Russell at Google I/O

I’m not sure how much I would have gotten out of Google’s I/O conference at the end of May, because so many of the sessions seemed to center around GWT and Gears, which I have little interest in. But fortunately they posted videos of the talks on Youtube, and I really like this one byAlex Russell of the Dojo JS library. It’s not a talk about practical solutions to the larger problems facing the web, but it gives a thoughtful, articulate, big-picture summary of what brought us here, where we’re going, and who to yell at to change something.

How YUI’s event listeners changed the way I write JavaScript

I really like Prototype.js. Its inclusion in Ruby on Rails got me writing JavaScript again. We at Schematic don’t recommend Prototype for client projects however, and I’m glad because the library or framework you use can greatly change the style in which you write code. And sometimes that can make you a better programmer.

Working with YUI helped trigger an epiphany for me this past week. Credit for laying the foundation for this moment goes to the sample chapter on Inheritance of Douglas Crawford’s new book, JavaScript: The Good Parts. I did not understand the practical usage for the techniques in the chapter at first because I learned Object Oriented design in classical OO languages like Actionscript 2, PHP5, and Ruby (which Prototype imitates as best as possible).

I’ve tried to maintain this style in JavaScript, especially in large projects like Silverlight 1.0 RIAs. I usually structured classes like this:

  1. var MyClass = function() {
  2.     // MyClass constructor
  3. }
  4. MyClass.prototype ={
  5.     method : function() {
  6.         // do stuff with the "this" object
  7.     }
  8. }
  9.  
  10. var myInstance = new MyClass();

I eventually extracted the new Class.create function from Prototype.js 1.6.0, because it gives you an elegant syntax for inheritance, mixins, and access to overridden methods without much overhead. It basically does the same as the above with some extra magic for creating the inheritance chain.

There’s nothing inherently wrong with this approach, and I think that anyone who tells you otherwise is a bit of a zealot. But it’s reliance on the this object creates problems, especially with event listeners. YUI made this very apparent:

  1. var GUIElement = function() {
  2.     var button = document.getElementById('button');
  3.     YAHOO.util.Event.addListener(button, 'click', this.onButtonClick);
  4. }
  5. GUIElement.prototype = {
  6.     onButtonClick : function(event) {
  7.         // this === button
  8.     }
  9. }
  10.  
  11. var element = new GUIElement();

The scope of the event handler is the button, which I believe follows the standard. However, I usually want this to refer to the instance of the class so I can access other methods and properties. The bind method in Prototype makes this easy by creating an anonymous function that executes the function in the specified scope:

  1. button.observe('click', this.onButtonClick.bind(this));

There are a few problems with this approach.

  1. bind uses Function.apply which adds overhead. It’s usually negligible but with JavaScript optimization is always a top priority.
  2. We’re not using Prototype! In this case, the client is a large e-commerce site and we’re only coding a small section of it. Prototype doesn’t necessarily place nice with other libraries since it defines a lot of global variables and augments the prototypes of build-in objects (like adding bind to Function).

You can specify the scope of the event handler with YUI, but it has the same effects as the first point above.

  1. // a "truthy" last argument makes the second-to-last argument the function scope
  2. YAHOO.util.Event.addListener(button, 'click', this.onButtonClick, this, true);

This felt very awkward to me, like I was doing something I wasn’t supposed to do. It’s perfectly valid but the awkwardness got a few gears turning in my head. I don’t think I can adequately explain my train of thought without turning this into an unreadable ramble, but here is how I’ve started writing components (using the module pattern):

  1. var GUIElement = function() {
  2.  
  3.     // define constants, like shortcuts to the YUI library
  4.     var Event = YAHOO.util.Event;
  5.  
  6.     // this "constructor" creates an object and passes it to functions
  7.     // instead of calling methods on the object itself
  8.     function create() {
  9.         var object = {}; // the instance
  10.         object.button = document.getElementById('button');
  11.         addEvents(object); // pass it to the function
  12.         return object;
  13.     }
  14.  
  15.     // we'll call the object "that" so it kind of looks like "this"
  16.     function addEvents(that) {
  17.         // pass "that" to the event handler, but don't change scope
  18.         Event.addListener(that.button, 'click', onButtonClick, that);
  19.     }
  20.  
  21.     function onButtonClick(event, that) {
  22.         // do stuff with that
  23.         // as a bonus, "this" still refers to the button
  24.     }
  25.  
  26.     return {
  27.         create: create // make create a public function
  28.     }
  29. }();
  30.  
  31. // the module pattern means no more "new" keyword
  32. var element = GUIElement.create();

And all of a sudden, Crockford’s techniques make sense! My paradigm shift is really just two ideas:

  • Encapsulate code into factories, not classes.
  • Functions act upon objects instead of being methods of the object that act upon itself (addEvents(that) instead of this.addEvents()).

I’ve yet to fully explore the ramifications of these techniques, but I wanted to try writing this down to see if it still makes sense. I won’t throw Class.create out of my toolbox just yet, but if I can understand an elegant way to do inheritance–or more likely, composition–I do think this will be the way to go 90% of the time. More on this topic to come.

Addendum: Curiously, Luke W posted an article while I wrote this about the exact component I was refactoring when this epiphany hit me.

Blog goals

This is the first of what I’m sure will be many navel-gazing posts before I actually get into this blogging thing. I’m not happy with the design I threw together this past weekend. For a future laugh, here’s what I’ve come up with so far:

The first try at a 4-column blog designThe current design as of this writing

The reason I’m unhappy with this so far is that it doesn’t achieve the goals I have for a blog. Of course, I can’t fully achieve my goals unless I know what they are in the first place. What are my goals?

  • To have central homepage that aggregates my three outlets on the web: twitter, tumblr, and this blog. The streams should be kept separate because they have different audiences. The blog is technical, tumblr is social, and twitter is personal.
  • To have URL I can use to identify myself professionally.
  • To have good blog for technical writing. It must be easy to skim and allow code samples.

I could probably manufacture more if I needed to, but I think this is a good starting point.

Don’t worry, nonexistant readers! I have a few topics in mind for real posts in the near future.

Hello world!

First! 

… wait.

A blog design in progress

Having tried to start a blog for, I don’t know, the last 8 years or so, I know that if I try to get the design perfect I will never post it for the world to see. Hell, if I were to wait until it qualified as just “good” you would never read this. So my plan is to put something up that isn’t ugly and tweak it from here. I’ll write a post or two about my development process, or lack thereof, as well.