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

rheo

v2.2.0

Published

Templateing lib inspierd by tumpet and hyperstream.

Downloads

28

Readme

Rheo

Goddes Rhea probably from the word rheo

Rheo is a template library built on top of html-tokenize and html-select it is heavily inspired by hyperstream and hyperspace.

Usage

Rheo uses streams everywhere, and where it can't use streams it uses callbacks that recieves and returns streams, with few exceptions.

Simple example

The simplest and not very interesting you can do is to just parse and then render html, like so:

rheo('<h1>Hello Rheo!</h1>').render().pipe(req)

\\ or

html_stream.pipe(rheo()).render().pipe(req)

Using CSS selectors

That was not really exciting, right? Let's do something more fun and change the message from the last "exercise".

html_stream.pipe(rheo())
  .inner('h1', function (inner_template) {
    return rheo('Hello Template')
  })
  .render()
  .pipe(req)

or the short hand:

html_stream.pipe(rheo())
  .inner('h1', rheo('Hello Template'))
  .render()
  .pipe(req)

Outer and inner both return a new rheo stream and you could chain multiple of these calls and shape your template.

Changing attributes

A lot of the things that happen in a webpage are defined by attributes. This is the only place where the stream/callback pattern breaks in Rheo. But don't worry it's still not complicated. And in theory we are only a pull request away from unifying the interface.

html_stream.pipe(rheo())
  .attribute('h1', 'class', function (old_value) {
    return old_value + ' rainbow'
  })
  .render()
  .pipe(req)

Or shorthand if there is no other classes.

html_stream.pipe(rheo())
  .attribute('h1', 'class', 'rainbow')
  .render()
  .pipe(req)

A little rainbow in your headings could never hurt, could it?

If you would like to change multiple attributes on the same element there is a shorthand for that to.

html_stream.pipe(rheo())
  .attributes('a', {
    'class': 'rainbow',
    'href': '#rainbow_power'
  })
  .render()
  .pipe(req)

Design by Example

Sometimes hardcoded is just plain better then handcrafting a machinery that does the same thing. Therefore its easy to pick one of many options when replacing a content with one of its elements.

<div class="fortune">
  <span class="fortune-good">Your code will read like well writen prose.</span>
  <span class="fortune-bad">You will be stuck in the debugger all day.</span>
</div>
html_stream.pipe(rheo())
  .inner('fortune', function (fortunes) {
    return fortunes.find('.fortuen-good')
  })
  .render()
  .pipe(req)

Iteration, map

HTML is a tree structure writen in a serial format. Sooner or later we want map some stream of data into a stream of html.

Take a look at this view controller.

function render_pet(template, data) {
  return template
    .inner('pet-name', function () {return rheo(data.name)})
    .inner('pet-age', function () {return rheo(data.age.toString())})
    .inner('pet-type', function () {return rheo(data.type)})
}

This function binds data to one pet template. This could be used for a pet profile, with the correct HTML. But it can also be reused for building list of pets.

It works fine now to render one, but how do we render all list items?

html_stream.pipe(rheo())
  .inner('.pet-list', function (pet_template) {
    var pet_template_stream = pet_template.map(render_pet)
    return pet_data_stream.pipe(pet_template_stream)
  })
  .render()
  .pipe(req)

Assuming that pet_data_stream is a stream of pet data objects and that html_stream is a text stream of html with a list with the class pet-list and that that list contains one example of a pet list item, then this will render a list of pets in that list.

Super Modularity

As you can see there is enormus potential to decouple your layout and templating from logic. And that is both good and dangerous so please be careful! But one more neat trick needs to be shared.

How many times have a templating librarie let you down when doing something as trivial as setting the title of your page. I have seen realy nasty ways to deal with that and selecting the current page in a menu.

Changing things that have already been renderd in a layout template is normaly frustrating and hackish. With Rheo? No, it's simple!

Rheo templates can be piped together like so:

function select_menu(menu_name) {
  var selector = '.menu .menu-item.' + menu_name
  return rheo.template(function (stream) {
    return stream
      .attribute(selector, 'class', function (classes) {
        return classes + ' selected'
      })
      .attribute(selector + ' a', 'href', function () {
        return '#'
      })
  })
}

function set_title(title) {
  return rheo.template(function (s) {
    return s.inner('title', rheo(title))
  })
}

page_template
  .pipe(select_menu('profile'))
  .pipe(set_title('My fluffy dog'))
  .render()
  .pipe(req)

As long as the element with the selector that you want to alter is put into the stream it doesn't matter when you add the menu or change the title, except for performence. Neat huh!?

Advanced example

<html>
  <head></head>
  <body>
    <h1>Todo</h1>
    <ul class="things">
      <li class="done">
        <img src="smily.png">
        <span class="title"></span>
      </li>
      <li class="pending">
        <img src="sadface.png">
        <span class="title"></span>
      </li>
    </uĺ>
  </body>
<html>
var rheo = require('rheo')
html_stream.pipe(rheo())
  .inner('.things', function (items) {
    var item_template_stream = items.map(function (template, data) {
      return template
        .find(data.done? ".done": ".pending")
        .inner(".title", function () {
          return rheo(data,title)
        })
    })
    return item_stream.pipe(item_template_stream)
  })
  .render()
  .pipe(process.stdout)