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

horseless

v0.5.3

Published

a framework?

Downloads

48

Readme

horseless

HTML-like markup. Auto-updating elements.

Paste your html into a template and use functions of your model for the arguments. When you update your model the DOM updates itself. No compiling and nothing is virtual.

tests coverage

Three main parts: h, proxy, render

Part 1: h, a template tag

h turns XML with interspersed arguments into a simple object based description of DOM objects.

It's an XML parser with the additional feature that it operates on string literals so that arguments can be copied into the DOM description (where appropriate). This allows render to expand any functions copied into the description itself and allows any web-components to receive real objects as properties.

see it working

h is broken out into it's own repo

Part 2: proxy your model

proxy creates a proxy of whatever object you give it. The proxy keeps track of which values were read during renders. If any of those values are changed later the corresponding child node or attribute are updated.

proxy is broken out into it's own repo

Part 3: render it onto the page

render takes a DOM element and an array of descriptions (generated by h). The descriptions are turned into actual DOM elements and set as children of the passed in element.

import { h, render } from 'horseless'

function fourFiveSix () {
  return h`<div>4</div><div>5</div><div>6</div>`
}

render(document.querySelector('.count'), h`
  <div>0</div>
  <>
    <div>1</div>
    <div>2</div>
    <div>3</div>
  </>
  ${fourFiveSix}
  ${[7, 8, 9].map(v => h`<div>${v}</div>`)}
`)

see it working

Functions used as arguments (fourFiveSix) are evaluated at render time. Arrays are expanded recursively. So if your argument is a function that returns an array of functions that return arrays themselves you still get a flat DOM.

And use it with proxy!

import { h, render, proxy } from 'horseless'

const model = proxy({seconds: 0})
setInterval(() => model.seconds++, 1000)

render(document.body, h`
  <span>hello world! seconds running: ${() => model.seconds.toString()}</span>
`)

see it working

more complete example

There's a todomvc example in the docs folder. You can see it running at https://horseless.info/todomvc/

things to know

  • Because functions are used to generate dynamic values, they are always expanded. It's likely that on- handler functions starting with need to be "escaped"
// this works as you'd expect it to
h`<span class=${functionThatReturnsClasses}> click me </span>`

// this logs something like 'click <span>click me</span>' when it's parsed but doesn't do anything when clicked
h`<span onclick=${el => console.log('click', el)}> click me </span>`

// this is probably what you want
h`<span onclick=${el => e => console.log('click', e)}> click me </span>`
  • Put quotes around embedded expression attributes to combine them
h`<span class="${returnsClasses} a-class ${returnsAnotherClass}">
    click me
</span>` // this works now
  • Attributes are built once before the node exists. (This might be my least favorite compromise in this whole project)

If you come across more things that may be confusing, please file an issue

Ugh! not another bloated framework!

The first iteration of this project did "just one thing" and that was the template literal xhtml parsing. The model stuff was for demos... but it was so cool (imho) it got moved into the project proper. That said, the goal of this project is to enable transformations from models to views. Having the view update as the model updates seemed to be in line with that goal. So... it's still kind of doing "just one thing" (but even if you don't buy that the two features are deeply integrated and it's still a long way from bloated)

There's around 400 code-golf-free lines with no external dependencies. you can read through all the code and understand every subtle nuance in an hour

The gzipped minified version is 2k

todo

  • documentation...
  • less adding and removing when splicing child nodes lists