bitty installation snippets examples documentation q&a

questions and answers

What is bitty's goal?

To make it easier to make things on the web.

What's the main idea?

Common things should be easy, uncommon things should be possible.

This is Lea Verou's quote paraphrasing Alan Key's "Simple things should be easy, complex things should be possible."

What approaches support the goal?

  1. Use native HTML and JavaScript.
  2. Don't require dependencies.
  3. Don't require build tools.

Why no JSX?

JSX increases the barrier to entry for getting started. You have to pick up a third thing beyond HTML and JavaScript.

Sure, there are a few things you have to learn about bitty to use it, but they are all vanilla JS.

What about progressive enhancement?

bitty was designed specifically to support progressive enhancement. That's part of the reason it relies on native HTML and JavaScript. You can have 100% of your content in HTML with bitty only providing nice-to-have features.

Of course, you can also start with nothing but a single <div> on the page and build everything with bitty too.

Why put templates in script tags instead of template tags?

Two reasons:

  1. <template> tags get parsed as HTML when they are ingested.

    This means trying to do something like this won't work:

    <img IMG_SRC alt="ALT_TEXT" />
    

    Depending on the browser the SRC string gets turned into img_src="" which breaks the find/replace functionality.

  2. Browsers may try to load <img> tags found inside templates. Doing something like this causes 404 errors as a result:

    <img src="IMG_SRC" alt="ALT_TEXT" />
    

Using the <script> tags eliminates those issues. The content is simply treated as a block of data with no further processing by the browser.

How fast is bitty?

bitty's primary functionality breaks down to:

bitty's performance is based largely on how well browsers are optimized for those functions.

To provide a concrete number, here's an example:

  1. Renders 1,000 text/button pairs from a template where each render contains both a sender and a receiver.
  2. Clicks a button to determine how long it takes to process a signal across all the items.

waiting

Benchmark code
<button data-s="run">Run Benchmark</button>
<div class="example-block-2">
  <div data-r="run">waiting</div>
</div>
<div data-r="report"></div>

<script type="text/html" data-template="benchItem">
  <div data-key="key-__NUM__">
    <div data-r="benchmark">_</div>
    <button data-s="benchmark" id="button-__NUM__">ping</button>
  </div>
</script>

<script type="text/html" data-template="report">
  <div>Time to create elements: __CREATE__</div>
  <div>Time to process signal: __BENCH__</div>
</script>
export const b = {};

let count = 1000;

export function run(_, __, el) {
  b.mark("create");
  el.replaceChildren(
    ...Array.from({ length: count }, (_, index) => {
      return b.render("benchItem", { __NUM__: index + 1 });
    }),
  );
  b.mark("create");
  b.trigger("clickBenchmark");
}

export function clickBenchmark() {
  b.mark("bench");
  b.qs(`#button-${count}`).click();
}

export function benchmark(_, sender, el) {
  if (sender.prop("key") === el.prop("key")) {
    el.innerHTML = "ping";
    b.mark("bench");
    b.trigger("report");
  }
}

export function report(_, __, el) {
  const creationTime = b.getMarks("create")[1] - b.getMarks("create")[0];
  const benchTime = b.getMarks("bench")[1] - b.getMarks("bench")[0];
  const subs = {
    __CREATE__: `${creationTime}ms`,
    __BENCH__: `${benchTime}ms`,
  };
  el.replaceChildren(b.render("report", subs));
}