Seriously great programmers

This is Part 2 of a series of articles on Reactive UI Programming with Knockout and Reactive Extensions for JavaScript.

Previous parts:

Recently I was working on a GUI that walked the user through a series of 5 steps in a Workflow. The user would spend most of their time on the 3rd step. As the user made edits, those edits would immediately be sent to the server for processing, and results from the server would show up in a different part of the GUI. There was a requirement that whenever the user left the 3rd step, we needed to send a message to the server to commit the changes they’d made.

So basically whenever the user was on the 3rd step, and then chose to move forward or backward in the workflow, we needed to send a command to the server.

As I started thinking about how to implement this, my first thought was to just subscribe to the currentStep ko.observable property on our view model and issue the command like so:

var previous = undefined;
self.currentStep.toRx(true)
    .where(function (newCurrentStep) {
        var prev = previous;
        previous = newCurrentStep;
        return prev === 3;
    })
    .selectMany(function () { return self.model().commitStep3ChangesRx().catchException(errorHandler); })
    .subscribe();

This sets up an Rx query which listens to changes in currentStep. It records the previous value in a temporary variable (previous). Whenever currentStep changes, it checks if the previous step was 3. If so, then it calls a function on our model to update the server, which returns an Rx.Observable which we can use to monitor the results of the command. We then subscribes to this Rx query, which activates it.

This code would certainly do what we want, but I wasn’t very happy with it for a couple of reasons.

First, the intent of the code is a little bit obfuscated by the way we track the previous step. If a developer goes to do some work on this view model, it will take them just a little bit longer to parse this code and understand what it is doing. So it is a little messy.

Second, it isn’t really re-usable. Tracking the previous value of a property seems like a pretty generic concept. It would be nice to capture this concept as a method so that it can be re-used the next time this comes up. This would also solve my first problem.

A word about our models

As you see in the code above, we use our models to communicate with the server. This keeps our view models focused on interacting with the user through the view. All of the commands and queries we send to the server result in an Rx.Observable. We subscribe to these observables so that we can be notified of the results of our call. This is similar in concept to the jQuery Deferred that is returned by jQuery.ajax. We prefer to use Rx.Observables instead of jQuery.Deferred because of the richer RxJs linq library and because we have a number of observable queries, which can return many results over time.

In many cases, our models actually expose queries and commands as simple ko.observable properties. The model listens to an observable query to the server to keep the property value up to date, and when a view model writes to the property, the model issues a command to the server to notify the server of the change. But some commands, like our commitStep3Changes are not really representable as a property. Such commands are exposed as methods on our models which return an Rx.Observable.

trailBy

Once I decided to write a general purpose method that could track prior values of a property, I just needed to decide whether it should be a knockout extension, or a Rx extension. Since I would ultimately be using it to launch an Rx query, and since the extensions syntax of Rx is a bit cleaner than Knockout, I decided to make it an Rx operator. I also decided to generalize it to support more than just the previous value. Like, what if I wanted to know the value 10 changes ago?

The result is the trailBy operator:

Rx.Observable.prototype.trailBy = function (n) {
    /// <summary>
    /// Converts the source stream into a new stream where the events are delayed by <c>n</c> events.
    /// For example, source.trailBy(10) will yield the first event when <c>source</c> produces the 11th event.
    /// </summary>
    /// <param name="n" type="Number">How many events to lag behind.  0 would produce the same stream as source.  Must not be negative</param>
    /// <returns type="Rx.Observable"></returns>

    var source = this;
    if (n < 0) { throw new Error("n must not be negative"); }
    if (n === 0) { return source; }
    return Rx.Observable.createWithDisposable(function (observer) {
        var ringBuffer = new Array(n),
            i = 0,
            ready;

        return source.subscribe(function (value) {
            if (ready) { observer.onNext(ringBuffer[i]); }
            ringBuffer[i++] = value;
            if (i === n) {
                ready = true;
                i = 0;
            }
        }, observer.onError.bind(observer), observer.onCompleted.bind(observer));
    });
};

After validating the n parameter and short-circuiting the n === 0 case, we return a new Rx.Observable, which when subscribed to will create a ring buffer that is just big enough to store n values. We then subscribe to source and start listening for results. When we have received n values and filled up our buffer, we are ready to start yielding results. Now, as each new item arrives, we send out the oldest item in our ring buffer before storing the new value at that location.

Notice that if source produces an error, we immediately send the error to our observer. This follows Rx Guidelines. Errors should be sent immediately and not held. Also notice we immediately send the completion event when source completes. Once source completes, anything left in our buffer is just thrown away. This is due to the semantics of our trailBy operator. If the resulting stream the “previous” value of source, and source has ended, then it stands to reason that the last value of source will never become the “previous” value.

Closing thoughts

With my new trailBy operator, I was able to satisfy the original requirements with this code in my view model:

self.currentStep.toRx(true)
    .trailBy(1)
    .where(function (previousStep) { return previousStep === 3; })
    .selectMany(function () { return self.model().commitStep3ChangesRx().catchException(errorHandler); })
    .subscribe();

This is about half as many lines of code as the original version which makes it much easier for a developer to look at and see what’s going on. We’ve also got a nice new operator in our toolbox ready to be used next time.

Here’s a jsFiddle with the code and a unit test.

This is Part 1 of a series of articles on Reactive UI Programming with Knockout and Reactive Extensions for JavaScript. You can read my introduction here.

When working with RxJs and Knockout, there will be times when you have an Rx Observable and need a Knockout observable so you can bind it to a view. And there will be times when you have a Knockout observable and need an Rx Observable so you can merge several event sources or some other type of logic that is more easily solved by the RxJs linq operators.

There’s a small project on GitHub called Knockout-Rx which is a quick example of how you can convert between RxJs and Knockout. This example solution isn’t quite sufficient for everyday use, especially in a complex application with many loosely couple components where a piece of code can’t be sure exactly where a given observable has come from.

In this post I’ll walk through the process of creating two methods to easily move back and forth between the 2 libraries. If you don’t want to read the explanations and just want the code, you can grab it, along with some unit tests from this jsFiddle.

Knockout.toRx

I’ll start with converting from a Knockout object to an Rx Observable since this is a simpler task. The basic idea is simple. Given a ko.subscribable, ko.observable, or ko.computed, I want to call a function to create an Rx.Observable which will signal anytime the ko object takes on a new value. I have found that, when I convert a ko.observable or ko.computed, sometimes I want the resulting Rx Observable sequence to start with the current value of the ko object–but only if the value is not undefined. Other times, I don’t want the current value. So I’d like this function to accommodate both behaviors.

So, we start by defining the function as a member of ko.subscribable.fn:

ko.subscribable.fn.toRx = function (startWithCurrentValue) {
    var source = this;
    return Rx.Observable.createWithDisposable(function (observer) { /* ... */ });
};

ko.subscribable.fn contains the set of functions that are available to all ko.subscribable instances. Since ko.observable is also a ko.subscribable and ko.computed is also a ko.observable, our toRx method will be available as a member method of every knockout object we create.

I could have declared toRx as a Knockout Extender, but I’m not terribly fond of the syntax. I much prefer var r = someKOObservable.toRx(); over var r = someKOObservable.extend({ toRx: false });. It just seems like a step removed from regular JavaScript. Generally speaking, Knockout was not written with JavaScript prototype inheritance in mind. It does not use prototypes to provide member methods to its objects, and instead copies the members from the ‘fn’ object to each new instance of a ko object. This leads to an n-squared problem – as the number of member methods grows, the time spent setting up the methods on each new ko observable instance grows. If you have several hundred methods on your “prototype” and are making 1000’s of instances of observables, then this can start to be a performance problem. The Knockout project implemented these extenders as a way to solve that problem. But it really feels like it is just working around the problem with the original decision to not leverage the JavaScript prototype. Thus I just added my method to the fn object.

When toRx is called, this will be the source ko object we want to turn into an Rx Observable. We store this in a source variable and then we use Rx.Observable.createWithDisposable() to construct and return an Rx Observable.

Within the subscribe function that Rx.Observable.createWithDisposable(), observer is the Rx.Observer that is subscribing to our observable. Whenever our source produces a new value, we want to call observer.onNext to notify the observer.

var onNext = observer.onNext.bind(observer),

I’m using Function.bind to define a function which takes a value and calls observer.onNext with that value.

subscription = source.subscribe(onNext),

I subscribe to our knockout source and pass our onNext function as the subscription callback. Now, whenever source gets a new value, our observer will get notified. I store the subscribe result in a subscription variable. We can call dispose on this when we want to unsubscribe fromr our source.

if (startWithCurrentValue && ko.isObservable(source)) {
    currentValue = source();

    if (currentValue !== undefined) {
        onNext(currentValue);
    }
}

I check if the caller has requested that the sequence start with the current value of the source object, and also check that the source object is a ko.observable (ko.subscribables do not have a current value and so the startWithCurrentValue option does not apply to them). If we should send the current value, I get the current value and, if it is not undefined, tell the observer about it.

return subscription;

Finally, I return our subscription variable. Rx.Observable.createWithDisposable() expects us to return a Disposable which it can dispose of when the observer unsubscribes from the Rx Observable. It turns out the subscribe call to our knockout source is exactly what we need.

Here’s the complete method:

ko.subscribable.fn.toRx = function (startWithCurrentValue) {
    /// <summary>Returns an Rx.Observable that signals whenever the underlying ko object changes</summary>
    /// <param name="startWithCurrentValue" type="Boolean">If true, the resulting observable sequence will start with the current value of the ko object at the time of subscription, unless the current value is 'undefined'.</param>
    /// <returns type="Rx.Observable"></returns>
    var source = this;

    return Rx.Observable.createWithDisposable(function (observer) {
        var onNext = observer.onNext.bind(observer),
            subscription = source.subscribe(onNext),
            currentValue;

        if (startWithCurrentValue && ko.isObservable(source)) {
            currentValue = source();

            if (currentValue !== undefined) {
                onNext(currentValue);
            }
        }

        return subscription;
    });
};

Rx.toKO

Now we will talk about a function which will create a Knockout object that updates in response to an Rx Observable. On the surface, this doesn’t sound any harder than going from KO to RX. But it turns out there are a number of subtleties that need to be considered.

What kind of KO object should be produce?

We only have 3 to choose from…

ko.subscribable

Well, technically, ko.subscribables are the objects which most closely map to an Rx.Observable and we could easily create one that signaled whenever our source Rx.Observable signaled. But should we? It turns out, this just isn’t very useful. The primary reason to turn an Rx Observable into a KO object is so that you can bind it to a view, or use it in a computed. ko.subscribables are not really useful for that.

ko.observable

This seems like it could certainly work. This is the target chosen by the Knockout-Rx project I mentioned earlier. Let’s see what toKO would look like if we chose ko.observable:

Rx.Observable.prototype.toKO = function () {
    var source = this,
        value = ko.observable(),
        subscription = source.subscribe(value);
    value.dispose = subscription.dispose.bind(subscription);
    return value;
}

So, this *could* work. But I have some issues with it:

  • It immediately subscribes to the Rx Observable. Generally speaking, most (but not all) Rx.Observables are cold, which is a fancy way of saying they are lazy and are inert until an observer subscribes to them. When an observer subscribes, they wire themselves up to their source and start producing values. What if the KO observable we produce is ignored by the view (because of an if statement or something)? We’ll have spun up the Rx Observable for no reason. That Rx Observable might be connected to some expensive and resource intensive processes and we wouldn’t want to consume those resources if we aren’t even viewing the results! It would be nice if our ko object didn’t subscribe to the Rx Observable unless something was actually interested in the answer.
  • The returned observable is writeable! This doesn’t make any sense. Rx Observables are one-way. What happens if someone writes to this observable? The value of the observable will not match the Rx sequence. If we bound this observable to a text field, that Knockout would, by default, make that text field editable. If we pass this observable to another part of the application, that part might not know that it really shouldn’t write to the observable. This is a deal breaker for me.

And so that leaves us with…

ko.computed

Computeds offer ways to solve my 2 complaints. We can use the deferEvaluation option to prevent our read function from being called until something actually reads us. And we can wait to subscribe to our source Observable until the read function is called the first time. We can also create the computed without a write function, which will make it a read only observable (ko.isWriteableObservable() will return false).

Function definition

Rx.Observable.prototype.toKO = function () {

Since RxJs embraces the JavaScript prototype, we can just add our method to Rx.Observable.prototype.

    var source = this,
        value = ko.observable(),

source is the Rx Observable instance which needs to be converted to KO.
value will be the ko.observable which will hold the most recent value seen by our source. This will be the value returned by our computed.

        subscription = new Rx.SingleAssignmentDisposable(),

This will eventually hold the disposable subscription to our source. We use this so that we can have something we can dispose of if the computed is disposed before we subscribe to source.

        computed = ko.computed({
            read: function () {
                if (!subscription.disposable()) {

This is the start of our read function of our computed. The first time this method is called, our subscription variable will not yet have had a disposable assigned to it, and so we know we have not yet subscribed to our source.

                    ko.computed(function () {
                        subscription.disposable(source.subscribe(value));
                    }).dispose();
                }

Here is where we actually subscribe to our source and assign the disposable subscription to our subscription disposable. We pass in our value ko.observable as the subscription callback. Rx Observables call this callback with a single parameters which is the value that was observed. This will effectively write the new value into our value observable.

Why do we wrap the entire call within a new ko.computed which we immediately dispose of? This is to prevent our computed from accidentally subscribing to any ko observables that happen to get evaluated during our call to source.subscribe. We have no idea our source observable is or how it has implemented its subscribe method. What if our source observable reads some ko observables when we subscribe to it? If it does, then through the magical knockout dependency detection mechanisms, our computed will detect those evaluations and take a dependency upon those observables. We don’t want that. By wrapping the call within a new computed, we cause the new computed to take the dependency instead of our computed. Once the call completes, we have what we want: a subscription to the source observable. We now dispose of the new computed we just made to release any dependencies it took.

                return value();
            },

Now that we’ve subscribed to the source, we just return our value observable. Knockout will setup a dependency so that everytime value changes our computed will produce the new value also. And we’ve subscribed our value to our source. So this means when our source produces a new value, our computed will produce that value also.

            deferEvaluation: true
        }),

Here we set the deferEvaluation option so that the read method is not called until someone actually tries to read our computed.

        dispose = computed.dispose;

    computed.dispose = function () {
        subscription.dispose();
        dispose.apply(this, arguments);
    };

Next we replaced the dispose method that our computed observable has with a new one that will dispose of the subscription to our source before calling the original dispose method. This way, when someone disposes of our computed, we will unsubscribe from the source observable.

    return computed;
};

We now have a read only computed that will not subscribe to the source until it is necessary.

Here’s the complete method:

Rx.Observable.prototype.toKO = function () {
    /// <summary>Returns a read-only ko.observable which will be subscribed to the source Rx.Observable and will always contain the most recent value received from source</summary>
    /// <returns type="ko.observable"></returns>
    var source = this,
        value = ko.observable(),
        subscription = new Rx.SingleAssignmentDisposable(),
        computed = ko.computed({
            read: function () {
                if (!subscription.disposable()) {
                    ko.computed(function () {
                        subscription.disposable(source.subscribe(value));
                    }).dispose();
                }

                return value();
            },
            deferEvaluation: true
        }),
        dispose = computed.dispose;

    computed.dispose = function () {
        subscription.dispose();
        dispose.apply(this, arguments);
    };

    return computed;
};

Conclusion

These two functions are all that is required to make Knockout and RxJs play nicely together. Now we can construct powerful observable chains that are composed of a mixture of Knockout observables and computeds and Rx observables. These functions are essential ingredients needed by my future code examples.

These functions, along with some unit tests, are available in this jsFiddle.

Next post I’ll start showing some actual usage examples.

When writing a complex single page web application, you find yourself dealing with ALOT of asynchronous activities. The user is busy clicking on UI elements and typing in text boxes. Asynchronous requests and responses are flitting back and forth between the server and client. Perhaps you’ve even got asynchronous messages coming from web workers.

Managing all of this asynchronous information and maintaining the correct state can be a real challenge. Luckily there are a number of libraries out there to simplify the task.

On the project I am working on, we are heavy users of KnockoutJs and Reactive Extensions (RxJs). These two libraries work so amazingly well together and once you learn how to use them effectively, building complex user interfaces becomes quite simple and straight forward.

What is Reactive Programming

When programming a UI, you are typically maintaining various pieces of state. You need to ensure that all of this state is updated correctly in response to various events.

In a traditional imperative programming style, you do this by writing an event handler for each event that one, by one, updates all of the state variables (including UI elements) that needs to be updated in response to the event. This includes state variables directly affected by the event, as well as those indirectly affected. This approach leads to a common type of bug that results from a developer forgetting that some state variable is indirectly impacted by an event and doesn’t update it. Or updates the state in the incorrect order.

In a reactive programming style, you define the relationships between the different state variables (including UI elements). Often you need not even write an event handler, but if you do need to write one, you only need to update the state directly affected by the event. You rely upon the framework to propagate the changes to any indirectly affected state variables by following the relationships you defined. This approach avoids the problem of not updating all of the state correctly. As long as you setup the relationships correctly, the infrastructure will ensure everything is updated.

Do I really need both Knockout and Rx?

At first glance, the 2 libraries seem similar. Both libraries implement the Observer pattern after all. But they have a different focus.

KnockoutJs focuses on two-way binding between UI elements and your view model properties. Thus it really focuses on observing values. Its ko.computed method provides a very simple and powerful way to derive values from each other. Because it is focused on two-way binding between an element and a view model property, Knockout observables are both readable and writeable. The UI’s read model is the write model. It is easy to use Knockout to write the “V” and “VM” portion of a MVVM UI.

RxJs is focused on receiving and managing streams of asynchronous information. It is really about observing sequences of values. Because of this focus, it comes with the full power of LINQ, with dozens of simple operators that can be applied to a stream of asynchronous data to transform, aggregate, join, filter the data as it arrives. Also, because of its focus on sequences of data, it can produce notifications when a particular sequence completes, or when an error occurs in the source. It does not really support bi-directional observations. If you want bi-directional communication, then you must setup a pair of observables, one for reading and one for writing. It is well suited to CQRS style of programming, where your read models are separate from your write models. It is well suited to writing the “M” portion of your MVVM UI because it provides a natural way to handle the success/failure of your various asynchronous requests to the server.

Tips & Tricks

Going forward, I’ll be writing a series of posts showing some useful techniques and examples of using RxJs and KnockoutJs together to write truly reactive code.

Up until recently, Firefox was the only Windows 7 browser which had support for multitouch. In a recent build, Chrome has also added experimental support. Unsurprisingly, they’ve used the same touch model used by mobile safari.

As of Chrome 21, the user is required to enable touch support. Within Chrome’s address bar, type about:flags. This will take you to a page which lets you enable/disable various features of Chrome. Near the bottom of the list you will find Enable touch events.

Once you’ve done this, Chrome will pass touch events to your web application. Here’s a boring jsFiddle I wrote to test whether or not I was receiving touch event data.

Note: Support is currently experimental, so expect bugs.

Here’s a few interesting observations I made while testing this functionality:

  1. Chrome actually reports the width/height of the contact. It is in the webkitRadiusX, webkitRadiusY properties. On my machine, it always reported circular contacts (radiusX===radiusY) and never elliptical contact, even though I know my hardware supports ellipse. I don’t know if this is a limitation of Chrome or Windows 7.
  2. The touch events also have a webkitRotationAngle. This is supposed to represent the rotation of the ellipse defined by webkitRadiusX & webkitRadiusY. You can monitor this property to detect when a finger is rotated on the surface. Since my touches were being reported as perfect circles, this property was always 0 in my tests.
  3. The touch events also have a webkitForce property, but it was always 0 in my tests. Again, my hardware reports touch pressure so I do not know if this is a limitation of Windows 7 or Chrome.
  4. Once you enable touch events, the browser itself will not respond in anyway to touches.
    • It does not produce pseudo mouse events so that older mouse-only web applications can be manipulated via touch.
    • You can’t use your fingers to scroll
    • Holding your finger down does not produce the context menu that you typically get if you have the default Windows gestures setup.
    • Pinching does not zoom the browser

    If you are writing a real multitouch application, all of the above are actually good things–the browser does not try to interfere and you have complete control over the events. But if you are a user then most websites you visit that were written for a mouse just won’t respond to your touches–you’d be forced to use your mouse. I imagine this will change in future Chrome versions and application writers will need to call ev.preventDefault() to actively prevent the browser’s default response to touch events.

  5. Because the user must actively enable touch support, expect it to be mostly off out there in the wild right now. Again, I suspect this will change once touch support leaves its experimental status.

I’m still waiting to get access to a Windows 8 machine. I can’t wait to test and compare the multi-touch support of Firefox, Chrome and IE10 on Windows 8.

In case you were wondering. I was. In case, say, you wanted to pool an expensive connection.

All self respecting developers now run virtual machines on their desktops. It seems, in particular, to be quite the fashion to own a Mac — which is lovely lovely hardware — but then run Windows or Linux in a virtual machine to do the work that pays the bills. Let’s assume for the sake of argument that this is a good thing to do, and not simply a time wasting diversion.

Eventually you’ll want to visit the virtual machine from the host machine. In a typical configuration, the virtual machine’s network is in “Bridged” mode, which means for all intents and purposes it’s a peer on the network to the host machine. They can talk however they want to each other, subject to firewalls, hostname resolution, and the like.

An interesting variation is to have a “Host Only” network set up as an additional interface between the two machines. This kind of network allows the host and virtual machines to talk to each other without the possibility of anyone else listening. By default, the virtualization software pretends to be a little network with a DHCP server on it, and the physical machine and virtual machines can all talk to each other.

You might one day find it useful to be able to sit on your host machine — the pretty mac — and route certain network traffic through the virtual machine. perhaps it’s actually connected somewhere useful like your favorite cloud provider.

The trick is to have the virtual machine be a NAT router for the connection it’s got that you’re interested in, and share it to the Host only network. This will effectively mean the virtual machine takes over the role of DHCP server and router, so you’ll have to configure the virtualization software to no longer do so. That is usually a matter of clicking some buttons, including potentially poking some firewall holes in that interface.

The more involved part is conjuring up a small set of scripts to route traffic properly from the shiny mac to the hard working virtual machine. The first trick is to write a script which updates your route table. Hopefully you know which routes are interesting to you. As an example, make a file called routes, which will contain the list of routes you want to send to the virtual machine. In this case, you’re connected to MIT, proud owner of every TCP address of the form 18.*.*.*, and the Ford motor corporation, owners of 19.*.*.*.

18.0.0.0/8
19.0.0.0/8

To set up the routing, make a little script like the following. ($target is the NAT address of the virtual machine on the host-only network, however you’ve set it up.)

#!/bin/bash
target=192.168.137.1  
usage="usage: $0 up|down"
operation=$1
operation=${operation:?$usage}
for r in $(cat routes) 
do
	case $operation in
		up   ) route add $r $target;;
		down ) route delete $r;;
		*    ) echo $usage; exit 1;;
 	esac
done

Now you can take the routes up and down as necessary.

If you want to send DNS queries down that pipe, too, you can take advantage of the fact that OS X still sort of clings to a Unix heritage and set up files in your /etc/resolver to do so. In this case you’d set up two files, one called ‘mit.edu’, and the other called ‘ford.com’, each of which would hold contents like the following

domain mit.edu
nameserver 18.72.0.3

To check that it was all kosher, use the scutil command, which should show something like the following, indicating that you are using Google’s lovely public DNS servers, unless you have a question for MIT, in which case you use the venerable bitsy.mit.edu. (OK, I made the ford.com up)

$ scutil --dns
resolver #1
  nameserver[0] : 8.8.8.8
  nameserver[1] : 8.8.4.4

... (several uninteresting resolvers) ...

resolver #8
  domain   : mit.edu
  nameserver[0] : 18.72.0.3
  port     : 53

resolver #9
  domain   : ford.com
  nameserver[0] : 19.1.2.3
  port     : 53

DNS configuration (for scoped queries)

resolver #1
  nameserver[0] : 8.8.8.8
  nameserver[1] : 8.8.4.4
  if_index : 5 (en0)
  flags    : Scoped

We don’t really do much with Flash, but it’s currently a necessary evil for viewing some real-time video feeds we generate. The flash widget — compiled as an swf — is really an artifact of the web GUI, and it ought to all be compiled at the same time. Fortunately you can compile flash swfs from mxml via the open source Flex SDK. This is how we made it a transparent and build-script safe part of the project.

  <Target Name="GetCompilableFlexFiles">
    <ItemGroup>
      <MxmlInput Include="@(None)" Condition="('%(Extension)' == '.mxml') and ('%(None.Compile)' != 'False')">
        <Swf>%(RootDir)%(Directory)%(Filename).swf</Swf>
      </MxmlInput>
      <ActionScriptInput Include="@(None)" Condition="('%(Extension)' == '.as') and ('%(None.Compile)' != 'False')" />
    </ItemGroup>
  </Target>
  <Target Name="CompileFlex" AfterTargets="AfterBuild" Inputs="@(MxmlInput);@(ActionScriptInput)" Outputs="%(MxmlInput.Swf)" DependsOnTargets="GetCompilableFlexFiles">
    <Exec Command="$(BuildTools)FlexSdk\bin\mxmlc -o %(MxmlInput.Swf) %(MxmlInput.RootDir)%(MxmlInput.Directory)%(MxmlInput.Filename).mxml" CustomErrorRegularExpression=".*(Warning|Error):.*" />
  </Target>
  <Target Name="FlexClean" AfterTargets="AfterClean" DependsOnTargets="GetCompilableFlexFiles">
    <Message Text="Cleaning swf files %(MxmlInput.Swf)" />
    <Delete Files="%(MxmlInput.Swf)" />
  </Target>

I learned a few things putting this one together, most particularly MSBuild batching. This code

  • Uses ItemGroup to gather a list of the input mxml files from the web project. The child tag introduces “Swf” as a piece of metadata for each MxmlInput which is the swf file that should be generated for that mxml. We also gather a list of all the ActionScript (*.as) files in the project. In theory, with sufficient intelligence we could be smart about which *.as files were used by which *.mxml files, but we have so few assets this wasn’t the primary problem for us.
  • Only compiles the mxml assets when any of them, or any of the ActionScript files are changed. We tell the CompileFlex task that its inputs are “@(MxmlInput);@(ActionScriptOutput)”. We tell it that its outputs will be “%(MxmlInput.Swf)” which is the precalculated list of SWF outputs from the ItemGroup above. The % introduces this as a batched output, on which more later. But the choices we made for Input and Output ensure that the (expensive) compiler will only be invoked if one of the inputs is newer than one of the outputs, i.e. only when you edit an *.mxml or *.as file.
  • Compiles mxml files one at a time, but uses only one task. By using the %(MxmlInput.Swf) syntax in the exec command line, MSBuild understands that it should reproduce the task once for each item in the %(MxmlInput.Swf) list. The compiler is found by looking for the MSBuild variable $(BuildTools). The FlexSDK is a java application, so you can just dump it somewhere well-known — programmers don’t have to install it.
  • Promotes compiler warnings to be errors by using a custom regular expression to parse the mxmlc tool’s output
  • Cleans resultant swf files when the project is cleaned.

Not rocket science, but it gets the job done and only does a compile when it’s necessary. Too often we view build tasks as a set of instructions, and then write tasks which always execute those instructions. It’s worth taking a few minutes to figure out how to make those tasks only execute when their inputs change, and making sure the tasks don’t have to be edited every time we add dependencies.

Follow

Get every new post delivered to your Inbox.