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

@sigil-dev/compiler

v0.9.2

Published

Compiler for the Sigil framework

Downloads

3,245

Readme

@sigil-dev/compiler

Compile-time JSX transform for Sigil.
Turns reactive macros and JSX into direct DOM operations with a tiny runtime overhead.

bun add -d @sigil-dev/compiler

What it does

The compiler runs at build time and does two things:

1. Transforms reactive macros into signal primitives
This helps you avoid footguns ~~which should hardly be possible, we're not react~~

// you write:
let count = $state(0);
let doubled = $derived(count * 2);

$effect(() => {
  console.log(doubled);
});

// compiler outputs:
const count = createSignal(0);
const doubled = createMemo(() => count() * 2);

createEffect(() => {
  console.log(doubled());
});

2. Transforms JSX into imperative DOM

// you write:
const el = <div class="box">{count}</div>;

// compiler outputs (dom mode):
const el = document.createElement("div");
el.className = "box";
const t = document.createTextNode("");
createEffect(() => { t.data = String(count()); });
el.appendChild(t);

There's no virtual DOM involved, and none of the nonsense involved with it. Output is either a string or DOM manipulation. You won't fight with the runtime over what actually changed and what didn't

Modes

Three output modes for the full SSR lifecycle:

| Mode | Use | Output | |------|-----|--------| | dom | Client SPA navigation | Imperative DOM calls | | ssr | Server render | HTML string concatenation | | hydrate | Initial client load | Claims existing SSR nodes |

The same source file compiles to different output depending on mode. In ssr mode, $effect is dropped entirely (effects don't make sense on the server). In hydrate mode, claim() calls replace createElement to reuse server-rendered nodes.

Macros

$state

Declares a reactive variable. Primitive values use subscription sets. Objects and arrays use Proxy for deep reactivity.

let count = $state(0);
count++;           // compiled to count.set(count.peek() + 1)
count = 10;        // compiled to count.set(10)

let user = $state({ name: "Rei" });
user.name = "Asuka"; // proxy handles this — no rewrite needed

$derived

A memoized value derived from other reactive state. Cached until dependencies change.

let doubled = $derived(count * 2);
// compiled to: const doubled = createMemo(() => count() * 2)
// which is another tiny shim over createEffect()

$effect

Runs a side effect that re-runs when its reactive dependencies change.

$effect(() => {
  document.title = `Count: ${count}`;
});
// compiled to: createEffect(() => { document.title = `Count: ${count()}`; })

Keyed lists

.map() with a key prop compiles to a reconciled list that surgically updates only changed items:

const items = $state([{ id: 1, name: "Rei" }, { id: 2, name: "Asuka" }]);

<ul>
  {items.map(item => (
    <li key={item.id}>{item.name}</li>
  ))}
</ul>

Compiled to reconcile() — moves, inserts, and removes DOM nodes by key without recreating unchanged elements.

Scoped CSS

CSS defined in a component file is automatically scoped with a deterministic hash:

// styles in your component file get a unique hash prefix
// .box → .box.s-a3f9b2c1
// :global(.reset) escapes scoping

Setup

Vite

// vite.config.ts
import { sigil } from "@sigil-dev/compiler/vite";

export default {
  plugins: [sigil()]
};

Bun (reccommended)

// build script
import { sigil } from "@sigil-dev/compiler/bun";

await Bun.build({
  entrypoints: ["src/index.tsx"],
  plugins: [sigil({ mode: "dom" })],
});

Babel

// babel.config.ts
import { sigilBabelPlugin } from "@sigil-dev/compiler/babel";

export default {
  plugins: [sigilBabelPlugin({ mode: "dom" })]
};

Used by

@sigil-dev/grimoire uses this compiler internally to process route files in three passes (ssr, hydrate, dom) during the build step. You can use it standalone for SPA projects via Vite, or wire it into any Babel-compatible build pipeline.