Sammy 0.7: Boy Meets Girl
Another long time in the making, Sammy 0.7 is here and its sexy. Check out the HISTORY and the full Changes to get the full details. The Boy of “Boy meets Girl” is Sammy, and the Girl is HTML5.
It’s probably seemed like Sammy development had stopped a while ago. With all the other similar frameworks bouncing around these days, I’ll admit there were some dark days of doubt leading up to this release. In fact, most of the code that comprises Sammy 0.7 has been in the master branch for over 4 months. However, development and my belief in this project hasn’t wained, its more just that I’ve been completely consumed by my work at Paperless Post (and in a very good way). One of the benefits of leading the team there has been the ability to push the boundaries of what we can do with our code and our libraries. We use Sammy extensively at PP and I was super excited to have a use case and a way to develop and test this latest version and all its power. The big addition of HTML5 History support has made the big new app we’ve been working on for the past 6 months seamlessly deep-link between full urls and hash urls between multiple browsers. We’re pretty psyched about it.
History is History
Despite which side you fell in on in the Great hashchange debacle of '11 you can’t argue with the pure fact that regular URI paths are just better than hash (#) paths. The makers of the great browsers of the world and the HTML5 History spec have a solution that attempts to appeal to everyone. The premise is simple – create a JS API for manipulating the full path of the current browsers location without forcing a page reload. Meaning, you can tell the url to change from http://www.example.org/one
to http://www.example.org/two
without having to reload the window, and allowing you to then manipulate the state of the page. Seems sort of like a dream, doesn’t it? Not only that but it really is a perfect fit for the way Sammy manages state and how Sammy applications are already built around routes and paths. I knew this was the case the first time I saw it, but I was unsure how to mix it with the existing hash based routing that works (and would have to persist) across every browser, not just the latest and greatest.
I believe Sammy 0.7 presents a pretty solid solution. Now, instead of routing on paths that look like #/mypath
you just route on paths that look like a server side path /mypath
var Sammy('#container', function() {
this.use('Mustache');
this.get('/', function() {
this.partial('templates/index.mustache');
});
this.get('/:user', function() {
this.load('users/' this.params.user '.json')
.partial('user.mustache');
});
});
The beauty and magic of above is a those routes will match both quirkey.com/#!/aq
and quirkey.com/aq
and execute the user route as expected. I’ve created a simple working example for you to play with at http://pushstate.quirkey.com/ (source here). We’ve been using and testing this for the past months and I can say its pretty solid (and pretty awesome).
There are some known caveats:
- History only works in latest and greatest browsers (Chrome, FF5, Safari 4) but support for it is growing. Ben Cherry and the team at twitter also found some issues with certain versions of webkit and URLs getting out of sync (though its been resolved
- Your server side needs to be able to handle whatever urls you’re changing to. This means that if you route/redirect to something like
/path/one/two
in Sammy, the server better be able to handle that url as well and point you in the right direction. Otherwise, refreshing the browser will lead users to a 404 or worse. The sammy-pushstate example has a pretty clever way of dealing with this in couchapps. It uses CouchDB rewrite rules to route any url request (minus the key files) to the index.html page (and hence allows sammy to handle the routing). - Currently, mobile webkit (aka Mobile Safari and the Android browser) report support for pushState/History when in fact they don’t have it. Since I’ve tried to keep browser sniffing out of the core Sammy repo, it currently doesn’t detect for this. You can manually disable push state per application, though, and do the browser sniff yourself if you plan to use your app on mobile.
- This causes some possible breaking changes for upgrading Sammy apps. If you previously did any routing (or path checking) the path reported in a route (EventContext.prototype.path) is now the full path starting at
/
not just the path beyond the hash. Also HashLocationProxy was renamed to DefaultLocationProxy.
That being said, its a pretty awesome feature and it makes writing Sammy apps really powerful when exposed to the full path. Theres more information in the API docs here.
Templating engines are so 2010
One thing thats frustrated a number of Sammy users is that previously all the template plugins (aka Sammy.Mustache, Sammy.Handlebars, etc) included the source for the engine in the plugin. In the beginning, I thought this was a great idea because it reduced the number of potential headaches and complaints of ‘Mustache isn’t working (because I didn’t include the source)’. However, what turned out to be a bigger issue was keeping up with all the plugins and their individual rapid development cycles. Because of this, all templating plugins (with the exception of Sammy.Template and Sammy.Meld) are now just simple wrappers and expect you to include the respective templating library in your own source. This also makes the case of using Mustache outside of Sammy in the same source/app as a Sammy.Mustache application a lot easier. For the sake of making the transition easier, the latest version of all of the engines is included in the repo (in vendor/templating).
More!
Those are certainly the biggest things with this release but its also not the whole deal. There were 12 other changes, bug fixes, and new plugins written by 10 different contributors! I can’t thank the people who use and contribute patches and ideas back to Sammy, enough. You guys rock.
So cool!! I’ve just updated from 0.6.2 my demo and works like a charm!! <3 new Sammy!!