Celebrating over a year of @FlightJS

Friday, 19 September 2014

Over a year ago, we open-sourced FlightJS, a lightweight JavaScript framework for structuring web applications which was designed based on our experience scaling Twitter front-end projects.

Since then, we have seen an independent community grow with over 45 contributors who created new projects like a Yeoman generator and an easier way to find new components. FlightJS was also adopted by other companies like @Airbnb and @gumroad.

Easier to get started

Over the pear year, we made it easier to get started with FlightJS due to the generator. Assuming you have NPM installed, simply start with this command to install the generator:

npm install -g generator-flight

Once that is done, you can bootstrap your FlightJS application using Yeoman and a variety of generator commands:

yo flight hello-world-flight
yo flight:component hello-word

This will scaffold your application file structure, install the necessary library code and configure your test setup. It’s as simple as that.

The withChildComponents mixin

Grown out of TweetDeck’s codebase, withChildComponents is a mixin for FlightJS that we recently open sourced. It offers a way to nest components, automatically managing component lifecycles to avoid memory leaks and hard-to-maintain code. The mixin binds two or more components’ lifecycles in a parent-child relationship using events, matching the FlightJS philosophy that no component should ever have a reference to any other. A child component’s lifecycle is bound to its parent’s, and a series of child components can be joined in this way to form a tree.

To host children, a component should use the attachChild method exposed by this mixin. The attachChild method, using the FlightJS late-binding mixin method, initializes the child up so that it will teardown when the parent tears down. An event, signifying that the parent is tearing down, is is passed by attachChild to the child component as its teardownOn attribute. By default, this childTeardownEvent is unique to the parent but can be overwritten to group components or define other teardown behaviors.

Before the parent tears down, the childTeardownEvent is triggered. Child components, listening for this event, will teardown.

If a child is hosting its own children, it will then trigger its own childTeardownEvent so that any children it attached will teardown. The teardown order is therefore equivalent to depth first traversal of the component tree.

For example, a Tweet composition pane might be structured like this:

Celebrating over a year of @FlightJS

The darker blue components mix-in withChildComponents, and use attachChild to attach a new component and bind the child’s lifecycle to their own using their childTeardownEvent.

The Compose component might look something like this. It attaches the ComposeBox when it initializes, and invokes teardown when it detects a Tweet being sent.

function Compose() {
    this.after('initialize', function () {
        this.attachChild(ComposeBox, '.compose-box', {
            initialText: 'Some initial text...'
        });

        this.on('sendTweet', this.teardown);
    });
}

The ComposeBox also attaches its children during initialization, as well as attaching some behaviour to its own teardown using advice.

function ComposeBox() {
    this.after('initialize', function () {
        this.attachChild(TweetButton, ...);
        this.attachChild(CharacterCount, ...);
    });

    this.before('teardown', function () {
        this.select('composeTextareaSelector')
            .attr('disabled', true);
    });
}

If the Compose pane were torn down – perhaps because a Tweet was sent – the first event to fire would be childTeardownEvent-1, which would cause the ComposeBox and AccountPicker components to teardown. The ComposeBox would fire childTeardownEvent-2, causing the TweetButton and CharacterCount to teardown.

Of course, if the ComposeBox was torn down on its own, only the TweetButton and the CharacterCount components would teardown with it – you can teardown only part of a component tree if you need to.

TweetDeck and the withChildComponents mixin

TweetDeck uses withChildComponents to tie logical groups of UI components together into pages or screens. For example, our login UI has a top level component named Startflow that nests components to look after the login form. When a user successfully logs in, the Startflow component tears down, and that brings the login forms with it.

This centralises the logic for a successful login, and changes to this flow can be made without looking at all files concerned with login. We also don’t have to worry about removing DOM nodes and forgetting to rip out the component too!

The withChildComponents mixin helps TweetDeck manage nested components in a simple way, abstracting away memory management and a good deal of complexity.

Feedback encouraged

FlightJS is an ongoing and evolving project. We’re planning to make more of the utilities and mixins used on the Twitter website and in TweetDeck available over time and look forward to your contributions and comments. If you’re interested in learning more, check out the FlightJS mailing list, #flightjs on Freenode and follow @flightjs for updates.