DEV Community

Cover image for Give an eye to VanJS, it costs nothing and you could be surprised
artydev
artydev

Posted on

1

Give an eye to VanJS, it costs nothing and you could be surprised

VanJS (abbr. Vanilla JavaScript) is an ultra-lightweight, zero-dependency and unopinionated Reactive UI framework based on pure vanilla JavaScript and DOM. Programming with VanJS feels a lot like React

Sample

import van from "./van.js"

const {span, button} = van.tags

const Counter = () => {
  const counter = van.state(0)
  return span(
    "❤️ ", counter, " ",
    button({onclick: () => ++counter.val}, "👍"),
    button({onclick: () => --counter.val}, "👎"),
  )
}

van.add(document.getElementById("app"), Counter())
Enter fullscreen mode Exit fullscreen mode

AWS Q Developer image

Your AI Code Assistant

Ask anything about your entire project, code and get answers and even architecture diagrams. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Start free in your IDE

Top comments (4)

Collapse
 
efpage profile image
Eckehard • Edited

With some very small additions we can enable a simplified composition style in VanJS, which does not restrict any other options or styles. Included in VanJS this should give only very little additional code...


    /* ******************************************************
        Some additions to VanJS
       ****************************************************** */
    let _base;              // Global element stores current insert position. If empty, elements are added at the end of document.
    let _baseStack = [];    // Stack for storing _base positions
    let _level = 0;

    /*------------------------------------------------------
       Set a new basepoint, save return adress on baseStack
      ------------------------------------------------------ */
    function begin(ID) {
      // Save old base
      _baseStack.push(_base);
      if (_baseStack.length > 100) {
        alert("error: _baseStackOverflow in begin()");
        _baseStack = [];
      }
      // select new base, either ID or element
      if (typeof (ID) === 'string')
        _base = document.getElementById(ID)
      else
        _base = ID;
      return _base;
    };
    /*------------------------------------------------------
       restore last base from stack, returns _base.
       if cnt set, unselectBase is called cnt times
      ------------------------------------------------------ */
    function end(cnt = 1) {
      for (let i = 0; i < cnt; i++) {
        if (_baseStack.length == 0) {
          ("error: _baseStack empty in end()")
          break
        }
        else
          _base = _baseStack.pop()    // restore old stack
      }
      // if chk, check Stacklength after pop == chk
      return _base;
    }

    // Function wrapper (would be unnecessary if included)
    function f(tagFunction) {
      return (...args) => {
        _level++
        let ret = tagFunction(...args) // Call 
        if (--_level === 0)
          if (_base)
            van.add(_base, ret)
        return ret;
      }
    }

    // Tag definition
    var { button, div, br, pre } = van.tags

    // apply wrapper function for auto-append (unnecessary if included)
    div = f(div)
    button = f(button)
    br = f(br)


    /* ******************************************************
        End additions to VanJS
       ****************************************************** */

    // Example code from VanJS
    const sleep = ms => new Promise(resolve => setTimeout(resolve, ms))

    const Run = ({ sleepMs }) => {
      const headingSpaces = van.state(40), trailingUnderscores = van.state(0)
      const animate = async () => {
        while (headingSpaces.val > 0) {
          await sleep(sleepMs)
          --headingSpaces.val, ++trailingUnderscores.val
        }
      }
      animate()
      const helloText = van.bind(headingSpaces, trailingUnderscores,
        (h, t) => `${" ".repeat(h)}🚐💨Hello VanJS!${"_".repeat(t)}`)
      return div(pre(helloText))
    }

    // Start the document
    begin(document.body)
      begin(div({style: "border: 3px dashed blue; padding : 10px; border-radius: 10px; display: inline-block; min-width: 600px; "}))
        const dom = div({style: "border: 2px solid; padding : 10px;"})
        begin(div({style: "border: 2px solid; padding : 10px; display: inline-block;"}))
            button({ onclick: () => van.add(dom, Run({ sleepMs: 2000 })) }, "Hello 🐌")
            button({ onclick: () => van.add(dom, Run({ sleepMs: 500 })) }, "Hello 🐢")
            button({ onclick: () => van.add(dom, Run({ sleepMs: 100 })) }, "Hello 🚶‍♂️")
            button({ onclick: () => van.add(dom, Run({ sleepMs: 10 })) }, "Hello 🏎️")
            button({ onclick: () => van.add(dom, Run({ sleepMs: 2 })) }, "Hello 🚀")
        end()  
      end()
    end()
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

This is the working example

Collapse
 
artydev profile image
artydev • Edited

Thank you Eckehard :-)

Collapse
 
efpage profile image
Eckehard

There are different ways to add the "DML-Style" to VanJS, but the most convenient would be an extension of the VanJS-core. I made a pull-request to add this feature. Please check out!

Thread Thread
 
artydev profile image
artydev • Edited

Hy Eckehard,
For me that would be a very great addition :-),
You have reached what I have wanted to do with MVU :-)
Hope Tao will find this nice too :-)

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

👋 Kindness is contagious

Please show some love ❤️ or share a kind word in the comments if you found this useful!

Got it!