Saturday, September 5, 2009

GWT for JavaScript Junkies

The most appealing thing about GWT for me isn't the fact that I, as a Java developer, don't have to write JavaScript anymore (hey, I like JavaScript!), but the single development experience. Since everything is in Java, you can have common libraries, coding patterns, frameworks, and editor behavior, drastically simplifying the development experience. My second favorite aspect of GWT is its component library. For far too long, we Java developers have treated HTML as just text to output, which is like treating programming as a series of ones and zeros - surely we can work at a higher level than that.

Therefore, I set out to explore what it would be like to have a GWT-like development experience for JavaScript developers, only instead of Java everywhere, you write JavaScript. Also, I wanted the bulk of the UI to be built on the server-side to minimize XHR calls and improve accessibility. To implement the server-side component library, I ripped of as much of Apache Wicket as I could, while keeping it 100% stateless (no session usage or complicated state sharing schemes). I'm not sure how to package this yet (new framework, Struts 2 plugin, require OSGi, or whatever), but before I go too far down the road of making it a proper framework, I thought I'd get some feedback on the basic design.

This is what the code of a simple application looks like:
/controllers/comment.js
/templates/comment/comment.html

comment.html

The comment.html template is a simple HTML page with "jsid" attribute markers to determine where the components are rendered. Absolutely no logic is allowed in a template:
<html>
<head>
// import jquery and json
</head>
<body>
<form jsid="commentForm" action="#">
<input jsid="title" type="text">
<input jsid="body" type="text">
<input jsid="submit" value="Submit" type="submit">
</form>
<script type="text/javascript" jsid="proxies"></script>
<body>
</html>

comment.js

Where it gets interesting is in comments.js. This follows the basic design of Ruby on Rails controllers with some interesting twists:
page({
comment : function(params) {
this.commentForm = new Form();
this.commentForm.add(new TextField("title"));

var body = new TextField("body", {
value : "Great feature",
label : "Body",
description : "The body of the comment"
});
this.commentForm.add(body);
this.commentForm.add(new Submit("submit"));

this.commentForm.onsubmit = function() {
alert('calling comment');
saveComment({
title : jQuery('#title').val(),
body : jQuery('#body').val()
}, function() {
alert("Comment saved");
});
return false;
}.toString();

this.proxies = new Proxies(['saveComment']);
},
saveComment : function(comment) {
print("comment title: " + comment.title + " body: " + comment.body);
this.result = "success";
}
});
Ok, starting from the top. You pass into the "page" function a map of methods to be used as controller methods, although there is a mix of HTML and JSON-producing methods: "comment" returns a comment page, while "saveComment" is a JSON-invokable method.

comment()

Since this is the method that will render HTML, we will build up our component tree. Instance variables like 'commentForm' are the first to be matched against comment.html, with subcomponents matching accordingly as the template processor works its way through the HTML. There are four components used in this page:
  1. "Form" - represents an HTML form
  2. "TextField" - represents an HTML text input field
  3. "Submit" - represents a submit button
  4. "Proxies" - generates client-side proxy methods that call the corresponding server-side ones
The main advantage of building your components in server-side code and not in a template is the much greater options you have for presentation logic. In this example, I just use hard-coded strings, but you can see how these could just as easily be initialized using service calls.

Nothing eye-opening so far...until you get down to the onsubmit() method. What we are doing is creating a method that will be executed on the client-side in our server-side code, using the nifty toString() feature on functions to get the source. We could have just as easily wrote it in a big string, but this way we get better editor support and fail-fast parser failure reporting. This also serves to help "blur" the line between server and client-side code ala GWT.

Finally, we create the "Proxies" component, passing the server-side function names that we want to be able call from the client. My implementation uses JQuery and JSON to stringify objects, but those details are irrelevant here. The point is we are able to call "saveComment()" on the client-side as if it was on the server-side, with all the json parsing and construction happening behind the scenes. Since both sides are JavaScript, you don't have the immedience mismatch you do in other languages.

saveComment

The "saveComment()" function is a remotely executable function, meant to receive and return JSON, although you aren't limited to it. JSON in the request body is generally a good idea since it limits your vulnerability to cross-domain request forgery. Of course, this technique also means your form only works with JavaScript turned on, which may not be an option. The "comment" argument is the serialized object passed from the client, and we return a serialized instance of our controller, which is why we set the result by setting the instance variable.

This basically completes the tutorial. One other thing to note is the components are also written in JavaScript, and since that means Rhino, you get all the E4X niceities in constructing HTML. This means even the HTML is syntaxally processed when the script is loaded.

Next steps

My next step is to build a real application using this little framework and see how it scales as the feature demands pile on. Thanks to Rhino, I can keep developing the backend of this application in Java with all the libraries and frameworks I depend on. The consistent use of JavaScript for the presentation layer hopefully means less code, more reuse, and more productivity.

8 comments:

  1. "For far too long, we Java developers have treated HTML as just text to output, which is like treating programming as a series of ones and zeros - surely we can work at a higher level than that."

    I'd say "for far too long, most Java developers have been wilfully ignoring frameworks which allow them work with HTML at a higher level"

    Presumably if there was no input with a jsid attribute of "title" in the template, then you would get a runtime error?

    If you could also ask the TextField instance for the correct id to use in 'onsubmit', that would be a plus -- but the TextField instance can't really be available when onsubmit is run, I suppose?

    ReplyDelete
  2. Hi..

    For starters, I love the exploration of new ideas in JS so great stuff.

    I was looking at the server side js thing about a year ago and found a wealth of info in places like Helma (Helma.org) and Persevere (http://sitepen.com/labs/persevere.php) for storage. Sitepen also have things like Reinhardt (http://www.sitepen.com/blog/2008/10/09/reinhardt-a-client-side-web-framework/) which may have some thoughts.

    I recognise people have a lot of experience with JQuery, but for what you're trying here, frameworks like Dojo might make it a little easier in some places. I'm not trying to start a library war, it's just for applications I've found so many good ideas already present in the dojo space and their build system is built entirely in JS using rhino. May be a place for inspiration in the least.

    Good luck with the idea.

    ReplyDelete
  3. @Tom, good point. Wicket, Tapestry, JSF, etc. have been around for a long time, however, I've never felt comfortable with their desire to create stateful components, usually resulting on poor urls and large session state. (yes, I know there are workarounds). This was necessary w/o ajax, but now you can treat the server as a service provider and the client can be responsible for taking the form fields and creating a data model out of them.

    Yes, you would get a runtime error w/ o 'title' component, but not sure what you mean in the next sentence... onsubmit is ran on the client so no, it doesn't have access to the TextField instance that was created on the server.

    @Tony, Dojo might indeed be a better fit. jQuery really is irrelevent in this example, since it is only used to make the XHR call, which could be any library or hand-rolled code. While Helma and other pure SSJS projects are cool, I'm needing something that integrates smoothly into a regular J2EE app, something like Grails.

    ReplyDelete
  4. When I bought my computer and I didn´t know how to use java graphics, so I decided looking for information in a webside and I found an useful information that helped me a lot.. Now I am interested in to do the best investment and I found a webside very useful and interesting called costa rica investment opportunities , I think it´s a very wonderful site.

    ReplyDelete
  5. JavaScript is a good program and very easy to use. I don´t like a complex program. I prefer javascript because i consider it like a device very eficient and it have a good quality.
    I always looking for the quality that is why i prefer to buy viagra because i always have a great result in my sexual life.

    ReplyDelete
  6. Nice information.. JavaScript is user friendly..and easy to go through this.
    web designing company

    ReplyDelete
  7. Thank you so much, nice job! oakley

    sunglasses sale
    was the thing people needed to get.You guys should think of arranging

    some gallery to exhibit them out there!

    ReplyDelete
  8. Being able to use the logo in a much cheaper price was an alternative chosen by a lot of customers.How to Discern Genuine from Fake Oakley Sunglasses:The O Logo: In fake ones, the logo is usually foakley sunglasses of screen printing or plastic that is painted. This paint is easily scratched, unlike the genuine ones wherein the material used for the logo is still an obvious Oakley logo even if it has been scratched for a couple of times.The X-metal Line: This metal line is quite hard to check, but some do have obvious indications of fake Oakley sunglasses. The genuine x-metal line is only made of plain metallic colors with rivets and screws tightly attached. Being able to use the logo in a much cheaper price was an alternative chosen by a lot of customers.How to Discern Genuine from Fake Oakley Sunglasses:The O Logo: In fake ones, the logo is usually foakley sunglasses of screen printing or plastic that is painted. This paint is easily scratched, unlike the genuine ones wherein the material used for the logo is still an obvious Oakley logo even if it has been scratched for a couple of times.The X-metal Line: This metal line is quite hard to check, but some do have obvious indications of fake Oakley sunglasses. The genuine x-metal line is only made of plain metallic colors with rivets and screws tightly attached.

    ReplyDelete