npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

weld.js

v2.0.1

Published

declarative dom bindings

Downloads

3

Readme

weld.js

Build Status npm Version npm License npm Downloads

Declarative DOM bindings for great good. And it only costs you 998 bytes.

Don't select it. Weld it.

Getting Started

One of the first things you learn after spending some time with JavaScript is that DOM selectors are tricky. We often rely on classes and sometimes id's for this. Creating this invisible association between your CSS and JavaScript, which becomes a maintenance nightmare. Especially troublesome for teams, and onboarding new developers.

We essentially ask CSS selectors to also become "JavaScript hooks", which violates one of the core tenants of software developent, single-responsibility principle.

CDN

<script src="https://unpkg.com/weld.js/weld.js"></script>

npm

npm install weld.js --save

Usage

Attaching functionality to DOM elements is achieved using the custom attribute data-weld="binderName: ...", where "binderName" is the identifer for a binder defined using weld.addBinder().

<!-- rest of DOM -->
<body>
  <div data-weld="hello: 'pim'"></div>
  <div data-weld="hello: 'jim'"></div>

  <!-- And how about passing additional parameters? -->
  
  <!-- using object literals -->
  <div data-weld="helloObj: { name: 'pim', greeting: 'hello' }"></div>
  
  <!-- using functions --> 
  <div data-weld="helloFunc: function() { return 'hello pim' }"></div>

  <!-- multi-paramter -->
  <div data-weld="helloMulti: 'pim', greeting: 'goodbye'"></div>

  <script src="weld.js"></script>

  <!-- define our binders -->
  <script>
    // a simple gretting binder
    weld.addBinder('hello', function (el, msg) {
      el.innerText = 'hello ' + msg;
    });

    weld.addBinder('helloObj', function (el, obj) {
      el.innerText = (obj.greeting || 'hello') + ' ' + obj.name;
    });

    weld.addBinder('helloFunc', function (el, fn) {
      el.innerText = fn();
    });

    weld.addBinder('helloMulti', function(el, name, values) {
      el.innerText = (values.greeting || 'hello') + ' ' + name;
    });

    weld.applyBindings(); //activate weld
  </script>
</body>
<!-- rest of DOM -->

Usage with modern JavaScript Frameworks

Many of the modern JavaScript frameworks, which typically angle their value proposition toward single-page application (SPA) development. But many of them are actually extremely viable options for multi-page application (MPA) development as well. Think of these as server-side application with ~sprinklings~ of JavaScript enhancements.

When building a SPA we create a root element, <div id="root"></div>, pass it to our framework of choice and it takes over from there. Effectively eliminating the brittle CSS<->JS relationship. But in MPA development, there isn't a clean entry-point like this, since the markup is primarily generated server-side. Thus, we often turn to using existing (or creating new) classes to begin attaching our JavaScript logic.

Instead, using weld.js we can declaratively inject our components removing any reliance on selectors for activation.

An example using mithril.js:

<div data-weld="hello: 'pim'"></div>

<script src="weld.js"></script>
<script src="mithril.js"></script>
<script>
  // A mithril component
  function HelloWorld() {
    return {
      view: function (vnode) {			
        var msg = 'hello ' + vnode.attrs.name;		
        return m('div', msg);
      }
    }
  }
  
  weld.addBinder('hello', function (el, name) {
    // We encapsulate in a closure so we can pass arguemtns
    m.mount(el, {
      view: function () {					
        return m(HelloWorld, { name: name });
      }
    })
  });

  weld.applyBindings();
</script>

Why?

Take the trivial example of a client-side hello world greeter, which receives it's data (i.e. name) from the server.

Using DOM selectors

<!-- rest of DOM -->
<body>
  <script>var msg = 'pim';</script>
  <div id="hello-greeter"></div>

  <script>
    var greeter = document.getElementById('hello-greeter');
    if(greeter)
      greeter.innerText = 'hello ' + msg;
  </script>
</body>
<!-- rest of DOM -->

Notice how we're forced to create CSS taxonomy in order to facilitate discovery, and create a globally scoped ad hoc script tags to associate data from our server.

Now imagine we wanted multiple greeter elements. In order to do this, we need to update not only the JavaScript, but also the CSS. This could be a complete nightmare and it's often safer to create new classes and functionality altogether just to avoid breaking anything that might also be reliant on these.

<!-- rest of DOM -->
<body>
  <script>var msg = 'pim';</script>
  <div class="hello-greeter"></div>

  <script>msg = 'jim';</script>
  <div class="hello-greeter"></div>

  <script>
    var greeters = document.getElementsByClassName('hello-greeter');
    if (greeters) {
      for (var i = 0; i < greeters.length; i++) {
        greeters[i].innerText = 'hello ' + msg;
      }
    }
  </script>
</body>
<!-- rest of DOM -->

That's not so bad. It's slightly more code, still reasonable though. But hang on... does this work? It looks accurate, but will it output what we think? The answer is no! If you attempt to run this sample, you'll see "hello jim" printed twice. This happens because second assignment to msg occurs before the JavaScript is executed.

We can solve this though, using data-* attributes.

<!-- rest of DOM -->
<body>
  <div class="hello-greeter" data-msg="pim"></div>

  <div class="hello-greeter" data-msg="jim"></div>

  <script>
    var greeters = document.getElementsByClassName('hello-greeter');
    if (greeters) {
      for (var i = 0; i < greeters.length; i++) {
        
        var msg = 
          greeters[i].hasAttribute('data-msg') ? 
            greeters[i].getAttribute('data-msg') :
            'world';
            
        greeters[i].innerText = 'hello ' + msg;
      }
    }
  </script>
</body>
<!-- rest of DOM -->

Again, slightly more code than before. But still reasonable. Where this approach begins to fall apart though is when we need to start passing in more parameters, or more complex parameters. Imagine trying to pass in an entire object this way?

This is where weld.js comes to the rescue

<!-- rest of DOM -->
<body>
  <div data-weld="hello: 'pim'"></div>
  <div data-weld="hello: 'jim'"></div>

  <!-- And how about passing additional parameters? -->
  
  <!-- using object literals -->
  <div data-weld="helloObj: { name: 'pim', greeting: 'hello' }"></div>
  
  <!-- using functions --> 
  <div data-weld="helloFunc: function() { return 'hello pim' }"></div>

  <!-- multi-paramter -->
  <div data-weld="helloMulti: 'pim', greeting: 'goodbye'"></div>

  <script src="weld.js"></script>
  <script>
    weld.addBinder('hello', function (el, msg) {
      el.innerText = 'hello ' + msg;
    });

    weld.addBinder('helloObj', function (el, obj) {
      el.innerText = (obj.greeting || 'hello') + ' ' + obj.name;
    });

    weld.addBinder('helloFunc', function (el, fn) {
      el.innerText = fn();
    });

    weld.addBinder('helloMulti', function(el, name, values) {
      el.innerText = (values.greeting || 'hello') + ' ' + name;
    });

    weld.applyBindings(); //activate weld
  </script>
</body>
<!-- rest of DOM -->

By using weld.js we've created a declarative way to associate JavaScript code to our DOM. The hello binding will only ever be one thing, a hook between our DOM and our JS. We've also now sandboxed our code within a closure, which is key to preventing leaky state.

So next time you think of reaching for a DOM selector... "weld it, don't select it!".

Find a bug?

There's an issue for that.

License

Licensed under Apache License 2.0.