Add-on Builder 1.0 →
Add-on Builder, the product I’ve been working on for the past year, has just hit 1.0 It’s a web-based IDE that let’s people create add-ons for Firefox using JavaScript and HTML.
Add-on Builder, the product I’ve been working on for the past year, has just hit 1.0 It’s a web-based IDE that let’s people create add-ons for Firefox using JavaScript and HTML.
I’ve been working quite a bit on this little JavaScript MVC framework called Shipyard. Those who know me may recall that I used to write a lot about MooTools, and may wonder why I’ve moved off it and am writing my own framework instead. I figured I’d take the time to explain why I felt the need existed for Shipyard, and the goals it tries to accomplish:
Let’s get to it.
JavaScript has a tendency to turn into spaghetti pretty quickly, what with the callback parties and people saying it’s “just a scripting language”, applications tend to lack structure. MooTools has had a modular design from the beginning, by separating pieces of functionality into individual Classes. This concept has carried over into Shipyard, but Shipyard does so much more.
With other frameworks, such as MooTools or YUI, developers are asked to pick the components that they want to use when downloading the library. The goal is that people only ever download the JavaScript they need for their application. Unfortunately, people usually just download the full “default” build, that contains everything, because they don’t know what they want yet. It’s certainly a pain to try to be smart about your selections at first, and then later realize you need to download a couple more modules (plus all their dependencies) mid-development. So most people download the entire thing, and never chop out the unneeded afterwards.
Shipyard says that you should download the entire thing from the start. Download the entire repo, all the modules. As you write your application, you specify your dependencies naturally in each module (using require), and so you never need to look at a list and pick what you think you might one day sort of use. It’s all there on your computer, and you just use it naturally. When it comes time to ship to production, the build step (you’re already minimizing anways, right?) that comes with Shipyard only bundles the dependencies you specifically used. Shipyard takes an active stance in reducing the amount of wasted bytes that your users will have to download.
Testing is great. It’s the law. It’d be a good idea. Something like that, right? In many other frameworks, it’s very easy to write test suites for your applications, but JavaScript applications are strikingly absent of tests. Part of the reason is that many test frameworks make it difficult to test. I need to be able to test with the simplest of commands. Even have the possibility to test on a pre-commit hook, or even per save. That means testing needs to be easy, and fast. If it’s not, it just won’t happen.
Automatic tests run after each save in JavaScript, you say? But it’s hard to test JavaScript from a command line, because you need to test in browsers, right? Well, yes, you should do that too, but so much of our JavaScript applications nowadays is code that has nothing to do with the browser. So much of it can be isolated and tested in units. And while you should browser test your application as well, if a test breaks on the command-line, you know it will break in the browser before even having to load the test page. Fail faster.
Shipyard helps do this by makng it’s test runner run with nodejs. With the strict usage of the dom module whenever touching anything global and DOM related, the test runner is able to make the dom module work in nodejs with the help of jsdom. So you can actually test expected DOM behavior from the command line, each time you save your file.
You could even put your JavaScript test suite on CI, similar to how Shipyard’s own test suite runs on travis-ci with every commit.
Getting into the more MVC part of Shipyard, I had explored this idea of various sync locations with Models before. The idea is that applications have data, and we structure it with Models. The data comes from somewhere, and while it used to only ever come from the host server, increasingly it is coming from various sources. A common example that would benefit from this is an application with offline mode. You need the data of your models to sync with the server, but if the user is offline, you want the data to save locally, perhaps in localStorage or IndexedDB, and then be able to send the data to the server at a later point. Perhaps you want to cache the data in localStorage, and so when the user comes back to your site, you first look there, and then fall back to asking the server for the data.
It should be as simple as:
Recipe.find().addListener('complete', function(recipes) {
if (recipes.length === 0) {
Recipe.find({ using: 'server' }).addListener('complete', listRecipes);
} else {
listRecipes(recipes);
}
});
Shipyard makes it so.
The DOM sucks. It’s powerful, but it’s complicated, and has inconcistencies. I don’t think developers should have to touch the DOM, in most cases. Instead, Shipyard exposes Views. They’re kind of like Elements, but far more powerful. Specifically, Views can be made up of several elements, and not bother you about it. As well, you don’t have to fret over which of those elements needs event handlers, you just listen to events from the View itself.
Even cooler is the idea of binding data to Views. My first foray in JavaScript MVC had me re-rendering entire sections of the DOM when things had changed. Not only is that weak, performance-wise, but it’s boiler-plate that I had to worry about. You can end up with several places in your UI that reflect the same data, shown in slightly different ways, and then you’re left with remembering each place when you offer a new way to alter the data. Of course the UI should update when the data changes, I just shouldn’t have to remember that myself. I am only human, after all. Other frameworks have this (I met it when using Adobe’s Flex Builder), and so does Shipyard.
If you were nodding when reading the above, then get on the Shipyard train. Development continues strongly, it already powers a big application, and I hope it works out for you.
Exciting news for Android. It’s always been a wonder why the stock Browser wasn’t Chrome, and now it is. And it really rocks. The tab interface is fun to use.
However, since it uses an updated version of the webkit rendering engine, it should need to load that library upon initialization. The standard engine is always in memory, something that’s held back Firefox for Android. Yet, Chrome doesn’t seem to suffer from this.
Perhaps the mobile Firefox engineers already know, but I can think of 3 possibilities:
Whichever it is, hopefully mobile Firefox can find a way to improve their loading to be close to equivalent to Chrome’s loading.
As I said last night, I don’t see how nodejs is the solution, by itself, for a web application that talks to many services. I’d still say that MVC is the best solution we have seen so far. Python has great support for long-running async tasks, talking to various databases, and the like.
That said, I love my JavaScript. Here’s where I see nodejs being a win: writing JavaScript on both sides of the stack feels great, and it gains small amounts of CPU time by making file I/O asynchronous. For other long-lasting tasks, such as resizing an image, you still need to set up a task in a queue for other CPUs to crunch.
Tom Dale, reiterating why AMD is the wrong solution for JavaScript applications:
In my opinion, having to write this out for every file sucks.
And:
If build tools are required anyway, a much simpler solution should fit most developers’ needs.
Last month I got to start working on Shipyard almost full-time, as I need it to make Add-on Builder work by the end of the quarter. I’m not ready to call Shipyard 1.0 until I’m confident with the API for Models, Controllers, and Views. Models are largely done, Views need some work, and Controllers need a start. Besides that, though, what has happened to Shipyard in the past month?
Here follows a changelog-ish list.
addListener returns a Listener object with attach and detach methods.onceaddListener, removeListener, and emitbrowser and platformIf commit lists are more your thing, you can look to GitHub. The next month should see event delegation, and more work on the View/template system.
When people ask me why they should use Chrome or Firefox, I tell them that feature-wise they’re pretty competitive. This sums up the difference greatly:
This is a Google product and it has to benefit Google. It isn’t merely about making the web better, it is also about promoting Google products and giving them an advantage over competing services. […] Even if it requires violating your privacy.
Firefox wants the web to be better, and Chrome wants Google to be better.
I used to think say you should use that in the question “What variable should I name this for closures?” This was because self is already a variable that points to window. However, I’ve since revised my opinion on what is a good variable name in this case.
I now find that and self to be too vague.
Instead, I think the variable should be named after the Class that you are currently coding in. As always, it’s easier to explain with code:
var PackageController = new Class({
doSomething: function() {
var controller = this;
someEl.addEvent('click', function(e) {
controller.react();
});
}
});
The reason is because once you start delving a couple nested functions deep1, I find myself sometimes wondering if I bound that to the value I wanted. This way leaves little to wonder about. And since you read code far more than you write it, best to write the most readable code you can.
I know, some of that can be solved by moving the functions to named methods on other objects, but you’d be lying if you said you never happened to have a function for a .forEach loop, and then another inside for an .addEvent, or something similar. ↩
Excellent analysis of current module patterns by fellow MooTooler Sebastian Markbåge.
His conclusions match mine, and I used them in Shipyard profusely.
In a production environment, you will always want to minify and concatenate your scripts. Since there is always a “build” step, all syntaxes are equal in production.
In development, what matters most is a syntax that gets out of the way of programming, and more importantly, testing your code. That means that AMD is out. CommonJS modules have less boilerplate, and work immediately in other environments, like nodejs. This means you can very easily drop into a terminal, run nodejs, and import your module without a hitch.
This week, at our Mozilla All Hands, I shared some slides about Shipyard, a JavaScript MVC framework that is making it’s way into Add-on Builder. It’s not finished, but since I shared it there, it felt appropriate to share what there currently is here.
An application framework that covers all the common things any JavaScript application would need to deal with: interacting with a server, storing data, rendering said data in the browser, and responding to user actions. An application built on Shipyard should only have to write the parts to pull all those things together.
If you’re application is going to have 1000 lines of JavaScript, would you rather write all those yourself, or have 900 of them be in a framework that is tested and used by others?
When starting a web application, you would reach for Django, or CakePHP, or Rails; never would you decide to use just the language itself. Why shouldn’t you do the same when the target language is JavaScript?
It’s heavily influenced by MooTools, since they have an excellent modular design, but turned into modules while Moo 2.0 figures itself out. There’s slides, and the repository, again.