1. 30

I wrote innerself because I needed to make sense of the UI for a game I’m writing for the js13kGames jam. The whole game has to fit into 13KB. I needed something extremely small which would not make me lose sanity. innerself clocks in at under 50 lines of code. That’s around 600 bytes minified, ~350 gzipped.

innerself is inspired by React and Redux. It offers the following familiar concepts:

  • composable components,
  • a single store,
  • a dispatch function,
  • reducers,
  • and even an optional logging middleware for debugging!

It does all of this by serializing the component tree to a string and assigning it to innerHTML of a root element. It even imitates Virtual DOM diffing by comparing last known output of components with the new one :) I may sound like crazy but it actually works quite nice for small and simple UIs.

If you don’t care about size constraints, innerself might not be for you. Real frameworks like React have much more to offer, don’t sacrifice safety, ease of use nor performance, and you probably won’t notice their size footprint. In particular, innerself requires explicit sanitization of user input. It also isn’t a good choice for complex form-based UI when one part of the UI updates onkeyup (e.g. character counter or toggling the enabled/disabled state of a button).

innerself was a fun and less-than-serious weekend project for me. Let me know what you think!

  1.  

  2. 5

    this is cool! for those interested, this article is another interesting exploration of the tradeoffs of a super simple react (not redux) clone: http://uniphil.github.io/virtual-dom/

    previous discussion: https://lobste.rs/s/pzjlrd/virtual_dom_is_not_feature

    1. 3

      Thanks for the links; they’re very helpful! The limitation described in the article you linked to is the same that I ran into: just replacing the whole DOM tree on each update, as fast or slow as innerHTML may make it, makes it impossible to create viable interfaces which update every time the user types a character into the UI. It also hurts accessibility.

      For a moment I was tempted to try and somehow mark DOM elements which should update on key press events etc. I would then need to also prevent re-renders… which essentially puts us back to square one: two-way bindings. In the end I decided to make this a known limitation of innerself. It’s probably fine to say that you can’t create every imaginable interface in it. I’m less happy about how inaccessible it ends up being.

      It makes me wish for a Virtual DOM diffing done natively by the browser.

    2. 2

      Heh, I was going to comment “what’s the point, innerHTML is slow and dangerous and the virtual DOM is what makes react fast and secure in the first place”, but it makes much more sense in the js23kGames jam context. Using template strings over JSX is also pretty nifty. Looking forward to seeing your game, stas!

      1. 2

        Thanks, freddyb! I realize that using innerHTML has its issues and I hope I managed to convey it in the project’s README. The whole thing is a pet project, a what-if experiment and an excuse for learning more about one-way bindings and the Virtual DOM (by show-casing what happens when it’s not there).

        To make innerself slightly more serious, I’ve recently added a rudimentary sanitization function :)

        1. 1

          A week has passed and the game is now ready to play at http://js13kgames.com/entries/a-moment-lost-in-time.

          Initially I felt very productive using innerself and I was quickly able to add all the views and put the logic in the reducer. In the later stages of development we focused on UI polish and I set out to add transitions between views. As you can imagine, CSS didn’t appreciate the fact that innerself would re-render entire DOM trees when the state changed. I’m not very happy with the result: I ended up using setTimeouts timed precisely with animation events to work around those re-renders.

          I guess this counts yet another example of a use-case which innerself isn’t well suited for. Any time the DOM is stateful (forms, animations, transitions, video, audio), re-rendering by assigning to innerHTML is a bad idea.