a JavaScript library for building browser-hosted user interfaces

class HelloWorld extends Component {
	get elements(){
		return e("h1", "Hello, world!");
	}
}
render(HelloWorld, document.getElementById('root'));

Does it look familiar? But Backdraft is dramatically different:

Small

~10x smaller than competing frameworks

Fast

faster than competing frameworks

Easy to Use

no compilation step required

Easy to Understand

zero dependencies

Declarative Composition

Backdraft's API includes declarative composition, and has since it's first public introduction in 2009. In the last several years, libraries based on declarative composition have gained mind share.

But, a declarative, compositional API does not require a virtual DOM. This is one of the key differentiators of Backdraft.

Backdraft does not employ a virtual DOM. This design decision results in several significant advantages. Teams are right to ask the question: is the cost in space, performance, and complexity of a virtual dom design justified?

class ProductCategoryRow extends Component {
	get elements(){
		return e("tr",
			e("th", {colSpan: 2}, this.kwargs.category)
		);
	}
}

class ProductRow extends Component {
	get elements(){
		let product = this.kwargs.product;
		return e("tr",
			e("td", product.stocked ?
				product.name :
				e("span", {style: {color: "red"}}, product.name)
			),
			e("td", product.price),
		);
	}
}

class ProductTable extends Component {
	get elements(){
		let lastCategory = null;
		return e("table",
			e("thead",
				e("tr",
					e("th", "Name"),
					e("th", "Price")
				),
			),
			e("tbody",
				this.kwargs.products.map((product) => ([
					product.category !== lastCategory &&
					e(ProductCategoryRow, {category: (lastCategory = product.category)}),

					e(ProductRow, {product: product})
				]))
			)
		);
	}
}

            

This code demonstrates dividing a table of data into three components: the header rows, the data rows, and the table that manages both the header and data rows. For a full explanation of this code, see Thinking in Backdraft.

Small Code Stack

Backdraft's code stack is about 1000 lines of pure, modern JavaScript with no dependencies. Backdraft is not new. It's been used in various incarnations in private, for-profit projects for over a decade. And during that time, Occam's razor has been continually applied. Backdraft is order(s) of magnitude smaller than competing solutions. And the cost of size is pervasive:

Big libraries cost more for engineers to understand--both the API, and, perhaps even more important, the side effects of using that API.

Big libraries increase debugging cost. Groking a couple hundred lines of library code to understand a defect is doable. Groking thousands of lines under the pressure of a delivery schedule is a completely different matter.

Big libraries cost more to download. This is particularly important--perhaps in terms of keeping customers--when targeting mobile platforms.

Big libraries are often computationally expensive. Once again, this is particularly important when targeting mobile platforms.

Backdraft is order(s) of magnitude smaller than the competition...

Backdraft
42 KB
Angular
1100 KB
Backbone
400 KB
React
1200 KB

Approximate kilobytes of downloaded code (application + library) for a small "todo" application. See the Backdraft example for details.

Backdraft applications never require more code and often requires less...

Backdraft
280 lines
Angular
280 lines
Backbone
300 lines
React
400 lines

Approximate lines of client code for a small "todo" application. Note that the Backdraft example is not as small as possible, but rather was built to demonstrate Backdraft's abstraction mechanisms and includes serveral, generic, reusable components built from scratch. These kinds of comparisons can be rigged: our point isn't that the competing frameworks are bad in this respect, but rather to demonstrate decreasing library complexity does not, ipso facto, result in increased program complexity.

Minimal Computational Complexity

Backdraft minimizes computational complexity and Backdraft's API design makes it hard to use incorrectly. Assuming no library design or library usage errors, it's hard to imagine any user interface library implying such computational complexity that the computational resources of an average computer would be stressed.

But there are three assumptions in that statement:

Libraries implementations are often overly complex and then used improperly because the complex implementation causes severe side-effects if used wrong. Paradoxically, libraries that employ complex designs to "simplify" usage are often the same libraries that are easy to misuse, resulting in new problems.

There is an obvious approach to controlling these risks:

Define an API that is hard to misuse; design and implement with simple algorithms.

For example, many modern JavaScript libraries rely on a virtual dom. Why? What, precisely, are the benefits of such designs? Is the computational complexity implied by a virtual dom design justified by its benefits? We think not.

And if virtual dom is great and the computational complexity insignificant, then why did the number one product in this space recently decide that it needed to replace it's implementation and provide proof that the new solution was, at least, better?

Backdraft applications are fast...

Backdraft

append
update
reorder
260ms
6ms
300ms

Angular

append
update
reorder
373ms
101ms
462ms

React

append
update
reorder
400ms
149ms
300ms

Approximate times for tests described in a simple benchmark for several javascript frameworks. The Backdraft example tested can be found here. These times show order of magnitude comparisons; they are not intended to show high-precision times.

All the Normal Requirements

Baseline requirements aren't particularly interesting. But, they are requirements nevertheless. Backdraft fulfills them.