seanmonstar

Aug 23 2012
Jun 1 2012

Shipyard 0.2

The 0.2 version of Shipyard is out and about. Besides the usual minor bug clean-up, I wanted to share all the brand new toys it’s got.

  1. ObservableArrays
  2. CollectionView and SelectView
  3. Model Relationships
  4. Logging

If you’re like, “Show me naow!”, you can play over on jsFiddle. Or maybe you like changelogs.

ObservableArrays

The major players in Shipyard (Models, Views, and Controllers) are all Observables, which is what makes live-data-binding to Views available. However, binding to data wouldn’t work well if that piece of data was an array (like an array of Models). The ObservableArray mimics an Array, but extends from Observable. So, you can observe any index on the array, or the length.

The most useful part is that you can observe the array property of the ObservableArray. This property event will always emit the index of the change, an array of the removed elements, and an array of the added elements.

var arr = new ObservableArray('Foo', 'Bar');
arr.observe('array', function(index, removed, added) {
    console.log(index, removed, added);
});

arr.shift(); // log: 0, ['Foo'], []
arr.push('Baz', 'Quux'); // log: 1, [], ['Baz', 'Quux']

CollectionView and SelectView

With the use of the ObservableArray, CollectionViews are a whole lot better. You no longer need to manually manage them by with addItem. If you create an ObservableArray, and pass it as content to the CollectionView, it will update it’s childViews whenever you modify the ObservableArray instance. You can also pass a regular array, and later on .get('content').push(myModel), and the CollectionView will update automatically.

var arr = new ObservableArray('Foo', 'Quux');
var list = new ListView({ content: arr });

arr.splice(1, 0, 'Bar', 'Baz');
// list view now has child views in order of
// 'Foo', 'Bar', 'Baz', 'Quux'

SelectView is a new CollectionView available, with an additional computed property, selected, to observe which value on the content array is selected.

Model Relationships

Two new Fields are available, ForeignKey and ManyToManyField, that allow you define relationships between models. ManyToManyFields also take advantage of ObservableArrays, letting you know when a Model’s list of related models change.

var tags = task.get('tags');
var tagsView = new TagList({ 
    content: tags,
    // TagList is fictional, so is onTagSelect
    onTagSelect: function(tag) {
        var index = tags.indexOf(tag);
        if (index >= 0) {
            tags.splice(index, 1);
            // Task.tags has this tag removed
            // and also automatically updates this ListView
        }
    }
});

Logging

The tiny logging utility has morphed into a serious logging module very similar to Python’s own logging module. It’s still very easy to use quickly:

require('shipyard/logging').info('an info message');

However, it also comes ready to customize completely. You can specify different formats, different log levels, and different handlers for various loggers. Specifically, you might only care about shipyard internal logging that is of level WARN and above, but want DEBUG and above from your own app. In addition, you might want to pass any and all ERROR logs to your server, so you can see whenever your JavaScript is causing errors on other computers.

It would all be something like this:

var config = require('shipyard/logging/config');
config({
    handlers: {
        'console': {
            'class': ConsoleHandler
        },
        'xhr': {
            'class': XHRHandler,
            'level': 'ERROR',
            'url': '/api/log'
        }
    },
    loggers: {
        'shipyard': {
            'handlers': ['console', 'xhr'],
            'level': 'WARN',
            'propagate': false
        },
        'myapp': {
            'handlers': ['console', 'xhr'],
            'level': 'DEBUG',
            'propagate': false
        }
    }
});

Get it

It’s on GitHub, as always. It’s also available from npm. And it’s in the dropdown on jsFiddle. So yea.

Mar 21 2012

Shipyard 0.1

I’ve been working on a JavaScript MVC framework for past several months called Shipyard. It’s an incredibly modular framework, with ease of testing, and all that other kool-aid. What’s important now is that this is the first release point for Shipyard. Here’s what it comes packed with:

  • Models
    • Syncs to various locations
    • Fields to serialize data easily
  • Views
    • Automatic updates using Bindings
    • Uses EJS templates underneath
    • Templates get pre-compiled for production, so templating engine isn’t needed in final file.

There are plenty of other modules included, but not all have public docs currently as many of them aren’t needed specifically by app developers, only by the internals of Models and Views.

It’s already powering Mozilla’s Add-on Builder.

Start Playing

You can read more about Shipyard at the docs page, play with the obligatory example to-do app, or the brave can start at the source.

Or, you can grab your require and try it out in jsFiddle right now.

To use it locally, you could check it out with git, but it’s also available on npm, via npm install shipyard.

What’s Next

With this release, work begins on version 0.2, which will bring about Model Relationships, QuerySets, some Controllers, and a configurable logger.

Feb 21 2012

The Shipyard Mindset

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:

  • Being truly modular
  • Command line tests run after each save
  • Easy access to data from various sources
  • Auto-updating views

Let’s get to it.

Modularity

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

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.

Model Syncs

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.

Automatic Views

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.

Choo-choo

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.

Nov 21 2011

Past Month of Shipyard

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.

  • Animations
    • A merge between MooTools’ Fx.Tween and Fx.Morph classes
  • Events
    • addListener returns a Listener object with attach and detach methods.
    • support for once
    • legacy API
      • official API for EventEmitters is addListener, removeListener, and emit
      • previous methods will soon log a DeprecationWarning, before being removed by 1.0
  • New utils
    • Logger
      • Makes the console more familiar for Python users
      • Doesn’t error if there is no console available
    • Cookie
      • Thanks to MooTools
    • Color
      • Thanks to MooTools
  • DOMEvent
    • Thanks to MooTools
  • Env
    • provides browser and platform
  • A briefer test runner
    • Only prints dots for successes, F for failures, and prints errors at the end

If 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.

Oct 19 2011
Sep 19 2011