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

@madenowhere/phaze-astro

v0.0.9

Published

Astro renderer for Phaze. SSR + hydration for `.tsx` islands, all client:* directives, useAction() helper for Astro Actions.

Downloads

811

Readme

@madenowhere/phaze-astro

Astro renderer for Phaze — drop into any Astro project to render .tsx islands with Phaze's runtime.

Install

pnpm add @madenowhere/phaze-astro phaze
// astro.config.mjs
import { defineConfig } from 'astro/config'
import phaze from '@madenowhere/phaze-astro'

export default defineConfig({
  integrations: [phaze()],
})

That's the whole config. The integration registers Phaze's renderer, wires the @madenowhere/phaze-compile Vite plugin (so JSX gets compiled to template() + bindings), and configures TypeScript JSX import-source to resolve to phaze.

Client directives

Every Astro client directive works:

| directive | when it hydrates | |---|---| | client:only="phaze" | mounts in the browser only — no SSR HTML at all | | client:load | SSR'd HTML embedded in the page, hydrated as soon as the JS loads | | client:idle | SSR'd, hydrated when the main thread is idle | | client:visible | SSR'd, hydrated when scrolled into view | | client:media={"(min-width: 720px)"} | SSR'd, hydrated when the media query matches |

---
import Counter from '../components/Counter.tsx'
---
<Counter client:load start={42} />

The component runs once at hydration via Phaze's hydrate() (which adopts the SSR'd DOM rather than rebuilding it), or via render() for client:only.

useAction — Astro Actions as signal state

Astro Actions are end-to-end-typed RPC. @madenowhere/phaze-astro/actions wraps the action call shape in pending/error/data signals so islands don't have to roll the dance themselves:

import { signal } from 'phaze'
import { actions } from 'astro:actions'
import { useAction } from '@madenowhere/phaze-astro/actions'

export default function SaveButton({ scene }) {
  const save = useAction(actions.saveScene)

  return (
    <button
      disabled={save.pending}
      onClick={() => save.execute({ id: 'hero', data: scene() })}
    >
      {() => (save.pending() ? 'saving…' : save.error() ? 'retry' : 'save')}
    </button>
  )
}

useAction returns:

  • pendingSignal<boolean>. True while a call is in flight.
  • errorSignal<unknown>. Last error, or null. Cleared on the next successful call.
  • dataSignal<TData | undefined>. Last successful payload.
  • execute(input) — fires the action; returns the same { data, error } shape Astro returns directly, so callers can branch on the result inline.

Concurrent calls leave pending true until the last resolves; whichever resolves last wins for data.

Cross-island signal sharing

Astro renders each island into its own DOM tree, but the JS modules they import are shared by Vite's bundler — so a signal exported from a shared module is the same identity across islands on the same page:

// src/state.ts
import { signal } from 'phaze'

export const cartItems = signal<Item[]>([])
// src/components/CartIcon.tsx
import { cartItems } from '../state'
export default () => <span>{() => cartItems().length}</span>
// src/components/AddToCart.tsx
import { cartItems } from '../state'
export default ({ item }) => (
  <button onClick={() => cartItems.update((items) => [...items, item])}>
    add
  </button>
)

Drop both islands on a page; clicking AddToCart updates CartIcon reactively. No store library, no event bus — Phaze's runtime is shared between the islands.

This works because Vite dedupes the phaze package across island bundles. The framework instance is the same, so signal identity is preserved.

Limitations to know

  • Hydration is best-effort root adoption today. The root container is adopted but children are recreated as the JSX evaluates leaf-first. Full identity-preserving hydration ships with the M3 lazy-children compile pass. For most apps this is invisible; for apps with mid-flight CSS animations on hydrating elements, expect a brief reset.
  • Some dev-mode flicker on cold start. Vite's optimizer late-discovers astro/actions/runtime/entrypoints/client.js and emits a one-time reload. astro preview is unaffected. See GAPS.md §0 for the full diagnosis and the workaround we don't apply (because the canonical workflow is dev for editing, preview for verifying).
  • No streaming SSR for slow island loaders yet. Resolve loader data in the page frontmatter before render, or defer to a client:load island that fetches client-side.

See GAPS.md for a running list of issues that would be cleaner if fixed upstream in Astro / @astrojs/cloudflare rather than worked around in this layer.

Example

examples/astro-cloudflare/ — a KV-backed todo app showing all of the above end-to-end (Astro Actions + useAction + Cloudflare KV + Tailwind).