November 7th, 2008 Posted in english | 7 Comments »
Aptana is a Canada based company who is known for their integrated development environment and some weeks ago they released a new product which is called Jaxer, the Ajax Server that enables you to write serverside and clientside javascript at the same time and being able to write serverside javascript gives you a lot of new opportunities regarding flexibility, simplicity and speed. I could be a marketing guy, eh? :) But no…that’s just the impression when you read Aptanas’ website carefully. At least they got my attention and so I tried it out…
So what exactly is Jaxer?
It’s…
- both client-side and server-side code can be written in JavaScript
- server-side engine is based on Mozilla Gecko, the same browser engine that’s in the Firefox browser
- server-side DOM manipulation
- database access
- file system access
- network communications
- user sessions
- …
Jaxer in fact is an apache module that wraps the gecko javascript engine used in firefox 3 to parse and execute javascript code at the serverside if the programmer explicitly stated it with the “runat=server” property.
So if you e.g implement the following javascript into your “index.html” which is served by the jaxer module, it will be executed only on the server which also means that the client doesn’t see this code:
<script type="text/javascript" runat="server">
pageId = Jaxer.request.parsedUrl.queryParts.id;
switch(pageId) {
case "index":
loadScript("scripts/index.js");
break;
case "about":
loadScript("scripts/about.js");
break;
default:
loadScript("scripts/index.js");
}
</script>
If the client now requests your “index.html” it doesn’t see this javascript code because it’s executed and evaluated before it’s being send to the client. If you would write “runat=client” instead, this code would be executed at the client which would result to a problem because my defined “function” “loadScript” uses methods from the Jaxer framework to include javascript files but still we can workaround it because Jaxer adds the “proxy” property which you can apply to every function you define and it’s really useful because the “Jaxer-Framework” contains a lot of methods that are only available at the serverside. So imagine we wanted to execute “loadScript” at the clientside (”runat=client) then we had to provide the proxy property…
Then you could use this function from the clientside. Even if it uses serverside functions. This is beside the ability to modify dom elements from the server side the most valuable feature. If you want to dig in to this topic a little deeper, check out Aptanas’ guide on this: http://www.aptana.com/jaxer/guide/develop_proxies.html
BUT…Javascript and the whole concept of all this has several big drawbacks which kick this whole concept to the ground where it belongs to. I’m really sorry that I even spent my free time on this because I was tricked and I really believed this _thing_ could make my life as a web developer more enjoyable but it didn’t and it won’t.
The first thing that bugged me was the documentation which really looked promising at first but there are several methods with the wrong case…there is simply no Jaxer.Response e.g. as written in the documentation…hell, I tried to simply redirect to google.com with “Jaxer.Response.redirect(’http://www.google.com’);” but I simply got “Jaxer.Response.redirect is not a function” in the error log which absolutely made no sense at that time but after I hit google I found out that the “object” is called “response” and not “Response”…ok, so “Jaxer.response.redirect(’http://www.google.com’);” worked, yay…I only lost a couple of minutes ;). But why didn’t they simply had an alias for it if they can’t remember it when writing documentation? I wanted to submit a ticket so they can fix it but I had to register for it and that was beyond my motivation, really…this is disgusting.
The second problem is to write proper xhtml because Jaxer modifies every html file, so e.g. the following conversion happens:
_original_
<img src="foobar.png" alt="foo bar" />
_rendered_
<img src="foobar.png" alt="foo bar">
And your html file will probably start like this:
<html><head>
<script src="/jaxer/framework/clientFramework_compressed.js?version=1.0.0.4147"></script>
So if that’s not what you want, you don’t want Jaxer at all, because it limits you here. You are punked again, haha.
The next problem is to structure your project with Jaxer because you have to start with an html file where you probably have some javascript but how do you go on?
Let’s face a typical tiny example: a website that has an index and about page, both with the same header and footer.
So we create the directory “templates” for the “header.html” and “footer.html” template files. Then we create the “scripts” directory where we store the so called “controller” files which we name the same as the page: index.js and about.js. Cool, we are starting to get a usable structure which we could hand over to other programmers or developers but wait! Jaxer doesn’t supply a template engine at all so what are we doing now? Nothing except finding a javascript template engine which in my case is “jsRepeater” from http://jsrepeater.devprog.com which works really nice with jaxer/server-side. It’s based on jquery which you also have to download. I put all my serverside assets into a folder called “assets_server”.
My structure looks like this:
- assets_server
- scripts
- templates
- footer.html
- header.html
- blogroll.html
- index.html
Now my “index.html” looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| <script type="text/javascript" src="assets_server/jquery/jquery.js" runat="server"></script>
<script type="text/javascript" src="assets_server/jquery/jsrepeater.js" runat="server"></script>
<script type="text/javascript" runat="server">
pageId = Jaxer.request.parsedUrl.queryParts.id;
switch(pageId) {
case "index":
loadScript("scripts/index.js");
break;
case "about":
loadScript("scripts/about.js");
break;
default:
loadScript("scripts/index.js");
}
function loadScript(scriptFile) {
absolute = Jaxer.Dir.resolve(scriptFile, Jaxer.request.currentFolder);
if (Jaxer.File.exists(absolute)) {
Jaxer.load("file://"+absolute);
}
}
function file_get_contents(theFile) {
var p=Jaxer.Dir.resolve(theFile, Jaxer.request.currentFolder);
var f=new Jaxer.File(p);
f.open();
myContent = f.read();
f.close();
return myContent;
}
</script> |
This script is simple. It just decided when to load what script file. So far this is acceptable and it really just works fine, so no complaint at this point. Keep an eye on “runat=server” because here we also run jquery and jsrepeater serverside which will make it invisible to the client.
The following file is my “index.js” which controls what is being displayed when you request ?id=index:
1
2
3
4
5
| document.write(file_get_contents("templates/header.html"));
$("title").html("this is my frecking title");
document.write(file_get_contents("templates/index/blogroll.html"));
$("#blogroll").fillTemplate({"blogname":"blog.as.tl", "blogurl":"http://blog.as.tl"});
document.write(file_get_contents("templates/footer.html")); |
file_get_contents is a function I defined in “index.html” which is globally available as we load all scripts through “index.html”. Sounds strange, but that’s it.
In line 1 the script simply reads and displays the header template file.
In line 2 the title will be changed. Remember that all this happens serverside. Keep in mind that this is functionality from jquery, not from jaxer.
In line 3 we print out another template which really contains “template tags” for “jsrepeater”. The template itself is simple and looks like this:
<h2>This is my blogroll</h2>
<div id="blogroll">
<div class="blogname">${blogname}</div>
<div class="blogurl">${blogurl}</div>
</div>
The method “fillTemplate” simply eats some JSON and if you want more documentation for this template library, please visit: http://jsrepeater.devprog.com/introduction.html. JsRepeater is meant to be run on the clientside but with Jaxer jsRepeater really turns out to be very useful.
This is all very easy and it simply works as expected but what really bugs me is that you can code as sluggish as you want and it seems that the whole “framework” which is Jaxer in this case fosters this behaviour, especially when you take a look at their examples. Sure, they all work fine but I promise you when your project starts to become complex your progress will slow down as you have to cope with the mess you produced with Jaxer.
Another thing that just caught my attention is that scripts that you include via…
<script type="text/javascript" src="scripts/bla.js" runat="server"></script>
…are still accessible from outside the server (worldwide access). I’m not the security guy but what if I put my mysql connection information into such a javascript file? Ya, the whole world could read that file just by knowing its location.
Perhaps I’m digging into how to work with Jaxer and databases but I don’t think that Jaxer has such a great future for me personally. It’s just ugly, messy, find a word for yourself.
I hope you enjoyed my little journey to World-Jaxney.
Kind regards,
Andreas Schipplock.