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 🙏

© 2026 – Pkg Stats / Ryan Hefner

solid-html-cachable

v0.0.2

Published

Patched Solid HTML package with portable normalized built-template cache hooks.

Readme

solid-html-cachable

Patched Solid HTML package that exposes a cacheable built-template boundary validated by the solid-html-cache cache-boundary experiments. The current source snapshot is based on @solidjs/[email protected]; that upstream base is provenance, not a requirement that applications pin every Solid runtime package to rc.13.

Status

Pre-1.0 package. The serialized cache format is explicitly versioned and compiler-fingerprinted; incompatible engine revisions are cache misses, not migrations.

Upstream base:

  • package: @solidjs/[email protected]
  • Solid commit: 5efaf260becb32293f2bcb4d32f8be72be6de674
  • license: MIT

Runtime peer compatibility is declared as a range (@solidjs/web >=2.0.0-rc.13 <3.0.0). The dev/test matrix remains pinned to a known Solid revision for reproducibility.

The normal tagged-template API is preserved:

import html from "solid-html-cachable";

const view = html`<div class="card">Hello ${name}</div>`;

html.define(...), html.jsx, and html.components continue to work like upstream.

What this package changes

Upstream @solidjs/html keeps parse(), buildTemplate(), the built root, and instantiation private inside createHtml(). This package adds two things:

  1. createHtml({ resolveRoot }) — an optional external root-cache hook.
  2. html.compiler — low-level compile / normalize / rehydrate / instantiate operations.

No storage policy is built into this package. A cache library decides keys, localStorage/IndexedDB usage, eviction, and invalidation.

Why normalized built templates

A raw built root contains live HTMLTemplateElement instances owned by the current browser document, so it cannot cross a page refresh directly.

This package normalizes the built root into:

post-build AST
+
template.innerHTML for every document-owned HTMLTemplateElement

On a later document it recreates fresh <template> elements with innerHTML and reattaches them to the post-build AST. That preserves build-time mutations (claim, static-prop filtering, normalized text) while avoiding a second buildTemplate() call.

The research suite proved restoration for static DOM, reactive values, spread ordering, component boundaries, and multiple top-level templates, with zero buildTemplate() calls during restore.

API

createHtml(options?)

import { createHtml } from "solid-html-cachable";

const memory = new Map<string, unknown>();

const html = createHtml({
  resolveRoot(strings, compiler) {
    const key = JSON.stringify(Array.from(strings));

    const memoryHit = memory.get(key);
    if (memoryHit) return memoryHit as any;

    const serialized = localStorage.getItem(`solid-html:${key}`);
    if (serialized) {
      const root = compiler.deserialize(serialized);
      memory.set(key, root);
      return root;
    }

    const root = compiler.compile(strings);
    localStorage.setItem(`solid-html:${key}`, compiler.serialize(root));
    memory.set(key, root);
    return root;
  }
});

The normal tagged-template invocation still owns the current expression values:

const view = html`<div>${() => signal()}</div>`;

The cache contains no old expression closures, component instances, or reactive owners.

html.compiler

const root = html.compiler.compile(strings);
const portable = html.compiler.toPortable(root);
const serialized = html.compiler.serialize(root);

// after refresh / in a new document
const restored = html.compiler.deserialize(serialized);
const view = html.compiler.instantiate(restored, values, components);

The intended integration for solid-html-cache is the resolveRoot hook, not direct calls to instantiate().

Portable format

Every payload includes a format version and exact upstream engine identity. This is intentional cache invalidation metadata, not an npm dependency lock:

{
  format: 1,
  engine: {
    package: "@solidjs/html",
    version: "2.0.0-rc.13",
    commit: "5efaf260becb32293f2bcb4d32f8be72be6de674"
  },
  root: { /* post-build AST, no DOM objects */ },
  templates: [
    { path: [0], html: "<div class=\"card\">...</div>" }
  ]
}

deserialize() rejects a payload from another format or engine version. See docs/CACHE_FORMAT.md.

Build and publish the package

bun install
bun run build
bunx playwright install chromium
bun run test
npm pack --dry-run
npm publish

Files relevant to an upstream proposal

  • UPSTREAM_PROPOSAL.md — rationale and suggested upstream scope.
  • docs/UPSTREAM_DELTA.md — exact conceptual changes relative to upstream.
  • patches/upstream-minimal.patch — proposal-oriented patch sketch against the pinned rc.13 implementation.
  • docs/CACHE_FORMAT.md — portable representation and invalidation rules.
  • docs/SOLID_HTML_CACHE_INTEGRATION_PLAN.md — plan for supporting this package and stock @solidjs/html from solid-html-cache.

Important limitations

  • Each published solid-html-cachable build is based on a specific upstream Solid HTML revision, and compiled payloads are intentionally fingerprinted to that build. The runtime peer range can be broader than that upstream source snapshot.
  • The format is synchronous because tagged-template rendering is synchronous. localStorage is the simplest synchronous backend; IndexedDB needs prewarming or an async preparation phase.
  • Rehydration uses template.innerHTML. Persist only templates produced by your application/compiler cache; do not treat arbitrary untrusted payloads as templates.
  • This package does not claim server-side or hydration compatibility beyond the tested client DOM path.

Maintaining this fork sustainably

The preferred long-term workflow is upstream source + a small patch, not a manually diverging copy and not a wrapper that tries to import private symbols from the published @solidjs/html bundle. The published package does not expose parse, buildTemplate, the built root, or instantiation as public subpaths, so a wrapper cannot simply re-export those private closure-local operations.

For each upstream update:

  1. fetch the chosen Solid source tag/commit;
  2. copy/build packages/html from that revision;
  3. apply the small cache-hook patch (createHtml({ resolveRoot }), compiler normalize/rehydrate/instantiate API);
  4. update the upstream provenance/fingerprint;
  5. run the cross-document correctness and refresh benchmarks;
  6. publish a new solid-html-cachable version.

This keeps the maintained delta small and makes an eventual upstream merge straightforward.