It has been well over a year since my last post. In 2011 I went to work for Overstock and moved to Utah. Life got busy and I worked during the day and when I had time I programmed on Sgine at night (http://www.sgine.org). In February of 2012 I left Overstock and moved back to Oklahoma to start my own company writing software for businesses around the world (http://www.outr.com). Life got busier. :) Now, here it is, 2013 and I've resolved to blog at least once a week on the many amazing things I get to do.
Today I want to introduce you to Hyperscala (https://github.com/darkfrog26/hyperscala). It's a web framework I've been working on for a few months in Scala to provide type-safe HTML, CSS, SVG, and JavaScript to developers. The first question out of my mouth when I hear another person talking about another web framework is, "Why another web framework?" and I've asked myself that question many times both before creating and since creating it. Each time I come up with the same answer, and one that by the end of this introduction I hope you all will agree: It was necessary.
First, as any good introduction should, I'll show you a little Hello World example:
Obviously this is a very simplistic example and simply sets the page title and adds a String to the body of the page. If you'd like a far more detailed example of the bare-metal type-safe HTML writing capabilities I would recommend looking at the TodoMVC example.
This is all well and good if there are no designers and you prefer working in Scala to HTML and CSS. Unfortunately, this is not always the case and the goal of Hyperscala is not to make presumptions on how it will be used, so we try to accommodate everyone.
So, what do you do when you have existing HTML that needs to be brought into your project?
The first option is to convert it into Scala using the handy-dandy code conversion utility in Hyperscala. The code in the TodoMVC above was generated using this neat little tool. This works great when you have a snippet or large amount of HTML that needs to be converted into code to work with. For more information about this tool take a look HTMLToScala.scala. You can run the main method to get a nice visual file selector and tell it where to output the resulting Scala source file. This route works great until you need a designer to make a change to your HTML and they are unwilling to edit your Scala source files. ;)
This brings us to the second option. This is sort of a hybrid approach and I believe really gives you the best of both worlds in the case that you have externally maintained HTML and CSS that needs dynamic content integration. I created the DynamicContent trait and utilization of this trait allows you to dynamically import HTML and load only the elements you want to work with. See the following HTML snippet:
In this example we care about the two inputs and the button but we don't care about the rest of the content. So, utilizing DynamicContent we create SimpleDynamicForm:
This is a bit more elaborate than is necessary, but shows some of the power of PowerScala Properties in the mix with Hyperscala. Look specifically at the line where the button is loaded:
DynamicContent finds the button by its id in the dynamic.html file and loads it as a Hyperscala tag.Button and any changes I make to the loaded button are reflected at render time. I could have simply loaded the name and age inputs as well, but using bind I cross-bind the value of the input to their reflected field names in the Person class. This means that when I change the value of the inputs it updates the 'person' Property to reflect the change. DynamicContent.bind introduces two other features of Hyperscala we need to briefly discuss: Modules and Realtime.
Modules provide the ability to define shared functionality between applications, components, features, etc. For example, a big problem in web site development is avoiding multiple includes of jQuery. In Hyperscala there is a built-in module for jQuery that any tag or page that needs to make use of can simply 'require' in their code. For example:
The above code requires jQuery be present by referencing the jQuery Interface and passing a default implementation of jQuery182. This will inject jQuery182 if no other implementation of jQuery is specifically provided before render of the page. The require method may be invoked with just an Interface (and an exception will be thrown at render time if no implementation has been provided), an Interface and a default Module (as seen above), or just a Module (at render time the module will be used if it is the highest version number provided for the same module name).
Modules are extremely easy to write. For example, the jQuery182 module looks like this:
Every Module needs a name and version. If they implement an Interface they can override the implements method to provide a list of those they implement (see we are implementing jQuery interface). The init method is invoked the very first time the module is used within a Website. This allows one-time actions to be taken like registering a JavaScript resource to a path as seen above. The load method is invoked at first render of every page that requires this module. This gives the module the ability to interact with the page prior to rendering to the client. As you can see in the jQuery182 module we simply add a tag.Script instance to the head of the page.
Realtime is actually a Module like we just discussed, but an extremely powerful one. This allows two-way communication between the client and server via WebSockets falling back to AJAX polling. It is incredibly easy to use as seen below:
That's all that's necessary in order to allow cross-communication to a loaded webpage. Now any changes to the HTML after page load will automatically synchronize to the browser. Further, you can begin listening to JavaScript events on the server by specifying what events you want to be sent down. For example:
This is an extremely simple example of hooking up a button that sends click events to the server. Notice on line 12 the use of "event.click". All HTML tags expose JavaScript events via the "event" object. In this case we are assigning the result of calling JavaScriptEvent() that interacts with Realtime to send the event down to the server. We could do something like this instead if we wanted just basic JavaScript:
Notice on line 14 we add a synchronous listener to handle a ClickEvent (the JavaScript event that is thrown when clicked). When clicked we simply log that the button has been clicked to the server-side console.
This has been a pretty long post, but barely scratches the surface of what Hyperscala can do. My goal is to spend the next few weeks blogging about the features and capabilities of Hyperscala and get into some even more powerful features of the framework. Again, the biggest advantage of Hyperscala is that at its core it is simply a webpage rendering framework. Everything else is just icing on the cake. This means anyone that has other needs for the features of Hyperscala can simply build their own abstraction layer on top to provide whatever they want.