wshlst.com: A Webapp With A Pure-Javascript UI
Posted: October 25th, 2007 Tags: Javascript, My Software, Web development, wshlst.comI created a little wish list website called wshlst.com for my family to use. (Read more about it here.) I worked on it a little bit before Christmas last year, and a little bit again this year.
It’s been a lot of fun to write, and one reason is that the entire UI is written in Javascript. No HTML, no CSS. There’s no HTML generation on the server-side either; it’s all client-side Javascript. I’d really like to write more apps like this.
The Server
There is of course a server-side component. I decided to write the server in Rails because I had just finished working on a Rails project at Pivotal Labs and had Rails on the brain. Plus, my web host, DreamHost, supports Rails and doesn’t support Java, which is the language I’ve written all my other web apps in.
DreamHost’s support of Rails is a bit limited though: they kill any long-running processes, which means that a response from your Rails app could take 10 seconds if no other requests have been made lately. It’s good enough for a little project like Wshlst with only a few users and for initial development, but not much beyond that. (If I were to do it over again, I’d probably just use Ruby CGI, or maybe even PHP. Or use a VPS from Rimu, but that costs money.)
Because all of the UI is in Javascript, the Rails side of things doesn’t have to generate any HTML. Instead, it takes standard Rails requests and returns JSON using JSON for Ruby. For example, the client sends the following AJAX request:
GET http://wshlst.com/user/list
and the server uses ActiveRecord magic to find all the users that are “friends” with the current user and uses JSON for Ruby to convert that list to JSON, which it returns back to the client like this:
[{name: "Andy Acorn", id: 12, email: "andy@example.com"},
{name: "Betty Beets", id: 13, email: "betty@example.com"},
{name: "Chad Carrot", id: 14, email: "chad@example.com"},
{name: "Donna Donut", id: 15, email: "donna@example.com"}]
which Prototype automatically converts to Javascript objects.
The server is of course also responsible for sending static files, but those are all handled by DreamHost’s Apache servers.
The Client
Here’s where it gets interesting. The app consists of an HTML file that does little more than include the Javascript files. (In development mode, there are multiple Javascript files, but when I deploy to production, there’s just one file. Read this blog post on concatenating and compressing Javascript files with Ruby.)
The app relies heavily on Prototype, and also uses Animator.js for a few visual effects. Everything else I wrote from scratch. I like to write a lot of code from scratch when I’m working on a personal project so I can get a good understanding of what’s really going on and be able to better evaluate pre-written libraries when I’m programming for money.
The app’s main class is called Application and acts as a controller. There are many view classes which are combined to form the app’s UI. For example, the “Change Password” box is implemented by a ChangePasswordForm class and consists of a ModalBox with a FormPanel inside. The FormPanel contains instances of Buttons and Fields. Writing a Field class of course takes more time than putting <input type=”text”> in some template file somewhere, but it allows for easy reuse and the ability to add a feature to all fields in just one place. (I hope to post some of the code from Wshlst on this blog in the future.)
Responding to user actions is just a matter of one Javascript method directly calling another method. No parsing of parameters, no layers of actions and filters, no guessing client state on the server side. It’s very liberating.
Lessons Learned
Test early and often in lots of browsers. This is obviously important when doing any web development, but when it’s 100% Javascript, there’s even more chance of incompatibilities. My JsUnit tests caught some issues (Date.now turns out to be Firefox-only), but most issues I had were visual.
MVC is good. Again, I already knew this, but I didn’t do nearly a good enough job with it in this app, probably because it was the first time I wrote an entire UI in Javascript. Next time, I’ll have multiple controllers and keep app logic out of the views as much as possible.
Events are probably the way to go. Wshlst suffers from some tight coupling of objects because they directly notify each other of actions. Next time, I’ll try having all my objects send custom events to and receive custom events from some global event source (perhaps document.body), like I did back in the days when I wrote Mac software.
UI is hard. I’m glad I did all the UI myself, but next time I’d like to build on the work of others. I’m still looking for a good Javascript widget library. Some of the widget libraries I’ve seen are trying to make web apps look application-y, and I’d prefer my web app to look web-y. Also, some libraries don’t have great support for calling everything from Javascript. I think I’ll look into Dojo again now that version 1.0 has been released, and more importantly, now that there’s more documentation.
Try It Out
There’s no way yet to sign up for Wshlst (if there’s enough interest I’ll do it), but the front page of the site lists some demo users you can use to play around: www.wshlst.com.
October 27th, 2007 at 12:40 pm
Have a look at Ext JS Javascript UI Library. http://www.extjs.com It will take the drudgery out of coding the UI for you. As I’ve said before, Ext is like UFC when all the other UI libraries are still backyard wrestling.
October 27th, 2007 at 1:17 pm
I’ll definitely look at Ext next time. All the demos look very desktop-y, but perhaps I can style things myself to look more web-y.
March 2nd, 2008 at 11:16 pm
[...] uses a lot of Javascript. When developing, I want to have all of my JS files listed in my index.html page. But in production [...]