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

hyop

v0.3.15

Published

Hypermedia Operation. Tiny library (starting at 61 B) to hydrate operations as the hyop attribute. Use standalone or with other Hypermedia libraries like HTMX...Hydration as Hypermedia

Downloads

32

Readme

hyop

Hypermedia Operation or Hydration Operation. Tiny library (starting at 61 B) to hydrate operations in the hyop attribute. Remove bloat from hydration & JS payloads. Use standalone or with other Hypermedia libraries like HTMX...Hydration as Hypermedia.

hyop supports usage in a build environment or in a <script> tag as an ESM. For smaller JS payloads, use a build environment.

Custom hyop functions hydrate server rendered html & isomorphic components. Release general purpose hyop functions as npm packages. General purpose hyops support a foundation for minimal-bloat tree-shakable Hypermedia libraries.

| use case | size | imports | |-------------------|:-----:|--------------------------------------------| | hyop | 61 B | import { hyop } from 'hyop' | | multi_hyop | 81 B | import { multi_hyop } from 'hyop' | | verify_hyop | 148 B | import { verify_hyop } from 'hyop' | | verify_multi_hyop | 165 B | import { verify_multi_hyop } from 'hyop' |

Install using NPM

npm i hyop

Browser logic in a JS/TS build environment

<!DOCTYPE html>
<html>
  <head></head>
  <body>
    <div id="content"></div>
    <input type="text" hyop="input__hyop">
  </body>
</html>
import { hyop } from 'hyop'
window.addEventListener('load', ()=>{
  hyop(document, {
    input__hyop: input=>{
      const content = document.querySelector('#content')
      input.addEventListener(
        'input',
        evt=>content.innerText = evt.target.value ?? '')
    }
  })
})

Use as a Script Tag

<!DOCTYPE html>
<html>
  <head>
    <script type="module">
      import { hyop } from 'https://esm.run/hyop/hyop'
      window.addEventListener('load', ()=>{
        hyop(document, {
          input__hyop: input=>{
            const content = document.querySelector('#content')
            input.addEventListener(
              'input',
              evt=>content.innerText = evt.target.value ?? '')
          }
        })
      })
    </script>
  </head>
  <body>
    <div id="content"></div>
    <input type="text" hyop="input__hyop">
  </body>
</html>

multi_hyop

Using multi_hyop instead of hyop allows calling many hyops in a hyop attribute. The standalone size is 81 B instead of 61 B. For the extra bytes, you gain the ability to compose hyops.

Development & Debugging

By themselves, hyop & multi_hyop have a minimal payload size impact. If a hyop is missing, a non-obvious error will occur. Unused hyops will be dead code bloat.

verify_hyop & verify_multi_hyop throw a friendly error message for missing hyops. These functions warn about unused hyops. This facilitates debugging & removing dead code bloat.

When building the javascript payload. You can use @ctx-core/preprocess with the DEBUG env. This preprocesses hyop to run verify_hyop & multi_hyop run verify_multi_hyop. Useful for development enivornments.

@ctx-core/preprosess with DEBUG env as an esbuild plugin

import { preprocess } from '@ctx-core/preprocess'
import { import_meta_env_ } from 'ctx-core/env'
import { type Plugin } from 'esbuild'
import { readFile } from 'node:fs/promises'
function hyop_plugin_():Plugin {
  return {
    name: 'hyop',
    setup(build) {
      if (import_meta_env_().NODE_ENV !== 'production') {
        build.onLoad({ filter: /hyop\/?.*$/ }, async ({ path })=>{
          const source = await readFile(path).then(buf=>'' + buf)
          return {
            contents: preprocess(
              source,
              { DEBUG: '1' },
              { type: 'js' }),
            loader: 'ts'
          }
        })
      }
    }
  }
}

How does hyop compare with other Hypermedia libraries such as HTMX?

Hyop supports the programmer to create hypermedia operations as javascript functions. The hyop attribute maps to the hyop function. The programmer defines & implements the hyop. With full access to the Web APIs. Small builds with minimal bloat are possible. Starting at 61 B with hyop, you only need to bundle the code that you actually use.

Other hypermedia libraries are impressive. Yet they have to support a full api. Some of these libraries have taken steps to support tree-shaking. Yet even with treeshaking, a minimal core has to support the hypermedia api. These core libraries add > 1 kb of browser bundle. HTMX adds > 13 kb. These hypermedia apis support a subset of Javascript + the Web APIs.

Hyop gives the programmer full access to Javascript & the Web APIs. And binds SSR HTML with the hydrated hypermedia operation (hyop) at a much smaller size (~200x).

How does hyop fit into a reactive stack?

Hyop is useful with reactive libraries. Including rmemo (reactive memo) & relementjs (html builder). rmemo by itself adds ~358 B to ~559 B[1] to payload. hyop + relementjs + rmemo adds ~796 B[1] to the payload.

What about Locality of Behavior?

Carson Gross, creator of HTMX, points out that Locality of Behavior (LoB) makes a codebase more maintainable. LoB is a valid trade-off with Separation of Concerns & Don't Repeat Yourself.

Hyop has 1 level of indirection. To the hyop implementation function. Compared to embedding the hypermedia steps in HTMX. What is the impact & can we mitigate the loss of LoB?

It turns out that keeping LoB with Separation of Concerns is possible! A multi-pane editor can load the hyop function a separate pane beside the server render logic. JSDOC's @see, can link the SSR hyop attribute to the hyop browser function.

In this relementjs example:

import { div_ } from 'relementjs/html'
export function my_content_() {
  return (
    div_({
      /** @see {import('my-browser-code/my_content').my_content__hyop} */
      hyop: 'my_content__hyop'
    })
  )
}
export function my_content__hyop(my_content:HTMLDivElement) {
  // Do some DOM manipulation on my_content
}

Modern code editors will allow the programmer to jump to the my_content__hyop link. A keyboard shortcut moves my_content__hyop into another pane. There is an extra step with the hotkey. Yet most developers can do this in < 1s...< 200ms if the hotkey is in muscle memory.

Pro Tip

Create a hyop for each dynamic element in the browser. One hyop assigns an HTMLElement to a variable for another HTMLElement's hyop to use.

let text_content:HTMLElement
export function text_content__hyop(_text_content:HTMLElement) {
  text_content = _text_content
}
export function input__hyop(input:HTMLInputElement) {
  input.addEventListener('input', evt=>
    text_content.innerText = evt.target.value)
}

A module dedicated to hyop exports allows import * as some_hyops. Allowing passing all the hyop exports to the hyop function.

index.browser.ts

import { hyop } from 'hyop'
import * as some_hyops from './some_hyops'
window.addEventListener('load', ()=>{
  hyop(document, {
    ...some_hyops
  })
})

Real World Examples

Hyop assigns behavior to complex browser side interactions from a MPA. I'll show a couple of examples pages with code from a recent project. Both examples are from the same project. These examples use following tech:

The project uses the following tech for it's build:

Point being, hyop can fit in a custom stack or within a more established framework stack.

YouTube Video Player, minor web animations

https://brookebrodack.net/content

This page shows videos from Brooke Brodack's YouTube channel. The embebbed YouTube video player with the play/pause video state being in sync with the feed link.

Timeline with Animations, YouTube Video Player + Internet Archive Video Player

https://brookebrodack.net/brookers

This page is a partial timeline of the deleted Brookers YouTube channel. It integrates some web animations, YouTube player, & the Internet Archive video player.

Name Convention

I use the tag vector name system, a variant of snake_case, for my development. The majority of javascript developers use camelCase. So I aliased all functions & types as camelCase.

Note on App Payload Size vs Standalone Library Payload Size