wapp combines a Node.js server and a build system to help you develop single page applications with ease and control, providing a thin layer of abstraction above the HTML5 History API and the XMLHttpRequest object and letting you fill remaining gaps with whatever technology you may like.
Web applications developed with wapp have a file structure similar to the following:
- myApp - build - assets - static server.js client.js
You can see here a server, a client and several folders. The server is in charge of interacting with databases, third party services and all those things only servers can do, and sending resulting data to the client, which will show it to the user in a way (s)he understands.
Both are written the Node.js way, and wapp will make sure that its module system and all its ECMAScript capabilities function equally well at both sides, despite being executed in different environments, i.e the Node.js platform and the browser.
That being said, wapp is centered around one single thing: the URL. Each time it changes, the client requests some data to the server, and when it arrives it is in charge of updating what is shown to the user. As a result of the user's actions, the client may decide to change the URL, triggering the whole process again.
Applications developed with wapp may be configured by placing an
app.json file at the project root, e.g:
Above shown are wapp's defaults.
scripts are those scripts that you want to make available to the client. The
main script will be executed as soon as the client loads, and it's in charge of loading the rest of them at its discretion.
var Wapp =server =app = server__dirname;app;
The server decides which data corresponds to each URL. The
Wapp - a subclass of UrlRewriter - constructor can have the following arguments, in order:
If you choose a prefix other than the empty string, your app will be served at
http://yourhost.com <prefix> /. Please note that '/.assets/' and '/.scripts/' are reserved folders for internal wapp usage. CORS and host options refer to their Hsm counterparts.
These are replaced with some methods that allow you to specify which data to send in each case:
event.use(). The first one,
event.answer(), directly sends some dynamic data to the client, serialized, encoded and compressed on the fly, as seen on our first server example.
The second one,
event.throw(), allows you to maintain your error logic clean and tidy. It will delegate the current event to handlers of the
e/<code> path event, as seen on the following example:
var Wapp =server =app = server__dirname;app;app;app;
Note that the event queue still applies, you can listen for the
e/* event to answer errors with some data by default. Only one method is left:
event.use(). Until now, we've been preparing our data on the fly, but wouldn't it be more efficient to prepare static data ahead of time? That's what
event.use() and the
static folder are for.
Let's suppose our static folder looks like this:
- myApp - static - animals dog.json root.json default.json
For the next step, we'll have to install
sudo npm install -g wapp
cd myApp wapp build
You can also use
wapp watch to keep listening for changes. This command will also prepare your client files, which we will discuss later. Now it's time to see
event.use() in action:
var Wapp =server =app = server__dirname;app;app;app;
As you may imagine,
event.use() will send the already prepared data contained in the JSON files stored under the
var app =container = document;documentbody;app;app;
A wapp client looks a lot like a wapp server, with only one difference: instead of sending data, it receives it. Fired events are exactly the same except for
throw: those are replaced with a property called
data, which contains the data sent from the server. Error handling mirrors that of the server:
var app =container = document;documentbody;app;app;app;
Unlike the server, the client doesn't throw errors, it only reacts to those sent from it. You may have noticed a new thing:
app.trigger(). This is a client only method which processes the current URL and fires events accordingly. You should call it once you're done with listeners and want to populate your GUI for the first time or repaint it.
One thing remains: how do we navigate to another URL? In a wapp client you should do it through
event.redirect(). These calls will request the relevant data to the server and, when it reaches the client, update the URL and fire appropriate events. Note that you can use relative URLs:
var app =up = document;uptype = 'button';upvalue = 'click me to go up';documentbody;app;app;up;app;
Both calls accept three arguments:
fragment. Query properties starting with an underscore (
_) are sent in a
Query header and thus cannot be seen on the navigation bar. They will be lost when reloading or navigating back or forward, and they won't be accessible at the client in any case, only at the server.
The client can be in one of two states:
ready, depending on whether there is an HTTP request in progress or not. You can also use the History API, but please do not mess with states, only navigate through the history and leave
replaceState for the internal usage of wapp, otherwise errors will surely happen.
By now you've got almost everything you need to build your web application using wapp. We'll discuss two more concepts: assets and dynamic script loading. You'll most probably need to use things like images, videos and the like: those are called assets. Place them at your
assets folder, and get their URL using
app.asset() like this:
var app =a = appassetimg = document;imgsrc = ;documentbody;
You can also use relative URLs. Now it's dynamic script loading's turn. Your client is bundled ahead of time into a single script, but you may want to load some parts of it dynamically. Previously you've seen how you can define your scripts in your
app.json, but until now you've only been able to use your
main script. Well, you're about to know how to load the rest of them. Suppose you have the following
exportsfoo = 'bar';
That's a pretty simple script, right? You can make it as much complicated as you want, but for this example it'll be enough. Now it's time to use
app.load() in your main script:
var app = ;app;
I'm sure you can see what
app.load() does, think of it as an asynchronous version of
require(). With this you're ready to go. Only one more thing: you need to build the client and the static data for your web application to work. As seen before:
sudo npm install -g wapp cd myApp wapp watch
That'll keep your build updated. For not so modern browsers, several polyfills are included in generated bundles, see them at server/shims. If you want a specific shim feel free to open an issue, it won't take long for it to be included. You can also run the build process using the API:
var Wapp = ;Wapp;Wapp;
And that's it for now, happy coding!