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

rijs.minimal

v0.1.1

Published

Tiny (~4kB), super-fast, refined, reactive, fractal, unidirectional, isomorphic, pro-standards, declarative, Just Works™ framework for frontend development. There's only one API:

Downloads

8

Readme

Minimal

Tiny (~4kB), super-fast, refined, reactive, fractal, unidirectional, isomorphic, pro-standards, declarative, Just Works™ framework for frontend development. There's only one API:

import ripple from 'rijs.minimal'

ripple(name)       // getter
ripple(name, body) // setter
ripple.on('change', (name, change) => {})

Get and set things in single store. A change event is emitted when something is updated, enabling reactive updates.

Define a component:

ripple('my-component', () => {})

Use it on the page:

<my-component>

Ripple is agnostic to how you write your components, they should just be idempotent (a single render function). This is fine:

ripple('my-app', (node, data) => node.innerHTML = 'Hello World')

Or using some DOM-diff helper:

ripple('my-app', (node, data) => jsx(node)`<h1>Hello World</h1>`)

Or using once/D3 joins:

ripple('my-app', (node, data) => {

  once(node)
    ('h1', 1)
      .text('Hello World')

})

For more info about writing idempotent components, see this spec.

The first parameter of the component is the node to update.

The second parameter contains all the state and data the component needs to render:

export default function component(node, data){ ... }

You can pass down data by adding the name of the resources to the data attribute:

<my-shop data="stock">
export default function shop({ stock }){ ... }

Declaring the data needed on a component is used to reactively rerender it when the data changes.

The other option is to explicitly pass down data to the component using the (D3) data binding:

once(node)
  ('my-shop', { stock })

If you want to just use DOM, you can invoke .draw() on a custom element to redraw it:

const shop = document.createElement('my-shop')
document.body.appendChild(shop)
shop.state = { stock }
shop.draw()

You can set defaults using the ES6 syntax:

export default function shop({ stock = [] }){ ... }

If you need to persist defaults on the component's state object, you can use a small helper function:

export default function shop(state){ 
  const stock = defaults(state, 'stock', [])
}

Local state

Whenever you need to update local state, just change the state and invoke a redraw (like a game loop):

export default function shop(state, i, el){ 
  const o = once(el)
      , { counter = 0 } = state

  o('span', 1).text(counter)
  o('button', 1)
    .text('increment')
    .on('click' d => {
      state.counter++
      o.draw()
    })
}

Global state

Whenever you need to update global state, you can simply compute the new value and register it again which will trigger an update:

ripple('stock', {
  apples: 10
, oranges: 20
, pomegranates: 30
})

Or if you just want to change a part of the resource, use a functional operator to apply a finer-grained diff and trigger an update:

update('pomegranates', 20)(ripple('stock'))
// same as: set({ type: 'update', key: 'pomegranate', value: 20 })(ripple('stock'))

Using logs of atomic diffs combines the benefits of immutability with a saner way to synchronise state across a distributed environment.

You can also use the list of all relevant changes since the last render in your component via element.changes to make it more performant.

Dispatch an event on the root element to communicate changes to parents (node.dispatchEvent).

Just invoke a redraw of your application when the route has changed:

export function app(node, data){
  const o = once(node)

  o('h1', 1)
    .text('You are currently on: ' + location.pathname)

  window.on('change', d => node.draw())
}

Decouter emitterifies window to give you the change event, go(url) for navigating, and sets location.params with current route parameters.

Ripple does not care how you load/bundle your resources. You only just need to register them at some point. This means you are free to use whatever tool chain you like:

// index.js
ripple('my-app', require('./resources/my-app'))
ripple('my-app.css', file('./resources/my-app.css'))
ripple('somedata', require('./resources/data/some'))
$ browserify index.js > app.js
<script src="app.js"></script>
<my-app></my-app>

An application is just a component that composes other components, so you shouldn't need any other scripts.

I recommend using the folder convention: a resources directory, with a folder for each component, and a data folder for data resources.

resources
├── data
│   ├── stock.js
│   └── order.js
└── my-app
│   ├── my-app.js
│   ├── my-app.css
│   └── test.js
└── another-component
    ├── another-component.js
    ├── another-component.css
    └── test.js

You can then use a helper script to automatically generate a single requireable index.js from a directory of resources.

  • Check ripple.resources for a snapshot of your application. Resources are in the tuple format { name, body, headers }.

  • Check $0.state on an element to see the state object it was last rendered with or manipulate it.

By default the draw function just invokes the function on an element. You can extend this without any framework hooks using the explicit decorator pattern:

// in component
export default function component(node, data){
  middleware(d, i, el)
}

// around component
export default middleware(function component(node, data){
  
})

// for all components
ripple.draw = middleware(ripple.draw)

A couple of useful middleware included in this build are:

Needs

This middleware reads the needs header and applies the attributes onto the element. The component does not render until all dependencies are available. This is useful when a component needs to define its own dependencies.

export default {
  name: 'my-component'
, body: function(){}
, headers: { needs: '[css=..][data=..]' }
}

Helpers

This middleware makes the specified helper functions available from the resource (hidden properties). This is useful to co-locate all logic for each resource in one place.

export default {
  name: 'stock'
, body: {}
, headers: { helpers: { addNewStock, removeStock }}
} 

Styling

Stylesheet(s) can be modularly applied to an element: This middlware simply reads the css attribute and inserts them in the shadow root or scopes them and adds to head:

ripple('some.css', `:host { background: red }`)
<head>
  <style>my-shop { background: red }</style>
</head>
<my-shop css="some.css"> 

If you have a backend for your frontend, checkout rijs/fullstack which transparently adds a few more modules to synchronise state between client-server or for more docs.

You can also adjust your own framework by adding/removing modules.

dist/ripple.js provides ripple and also some small, useful, high power-to-weight ratio functions that enriches the language grammar. If you don't want the helper functions, use dist/ripple.pure.js. Add .min for prod. Minified and gzipped the sizes are ~12kB and ~4kB respectively.