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

@inglorious/vite-plugin-jsx

v1.1.0

Published

A Vite plugin that transforms JSX into lit-html syntax.

Readme

🩸 @inglorious/vite-plugin-jsx

JSX without React. Deterministic UI for Inglorious Web.

@inglorious/vite-plugin-jsx is a Vite plugin that compiles standard JSX / TSX into highly-optimized lit-html templates for @inglorious/web.

It gives you React-familiar syntax without React's runtime, hooks, lifecycle, or reactivity model.

New to Inglorious Web? Check out the main documentation first.


✨ Features

  • Standard JSX & TSX syntax
  • Zero runtime overhead
  • Compiles directly to lit-html
  • Deterministic rendering model
  • No hooks, no effects, no lifecycles
  • First-class SVG support
  • Automatic optimization of:
    • conditionals → when()
    • lists → repeat()
  • Smart attribute & property binding
  • Full TypeScript support

📦 Installation

npm install -D @inglorious/vite-plugin-jsx

⚡ Usage

vite.config.ts

import { defineConfig } from "vite"
import { jsx } from "@inglorious/vite-plugin-jsx"

export default defineConfig({
  plugins: [jsx()],
})

That’s it.

You can now write JSX/TSX in your Inglorious project.


🧬 What It Compiles To

JSX Input

function render(entity, api) {
  return (
    <div className="card">
      {entity.visible && <h2>{entity.title}</h2>}

      {entity.items.map((item) => (
        <p key={item.id} onClick={() => api.select(item)}>
          {item.name}
        </p>
      ))}
    </div>
  )
}

Compiled Output

function render(entity, api) {
  return html`
    <div class="card">
      ${when(entity.visible, () => html`<h2>${entity.title}</h2>`)}
      ${repeat(
        entity.items,
        (item) => item.id,
        (item) => html`<p @click=${() => api.select(item)}>${item.name}</p>`,
      )}
    </div>
  `
}

📚 Common Patterns

Handling Events

export const button = {
  render(entity, api) {
    return (
      <button onClick={() => api.notify(`#${entity.id}:click`)}>
        {entity.label}
      </button>
    )
  },
}

Conditional Rendering

export const panel = {
  render(entity, api) {
    return (
      <div>
        {entity.isLoading && <Spinner />}
        {entity.error ? (
          <ErrorMessage text={entity.error} />
        ) : (
          <Content data={entity.data} />
        )}
      </div>
    )
  },
}

Lists with Keys

export const todoList = {
  render(entity, api) {
    return (
      <ul>
        {entity.todos.map((todo) => (
          <TodoItem key={todo.id} {...todo} />
        ))}
      </ul>
    )
  },
}

📘 TypeScript Support

The plugin works with .tsx files out of the box. For proper type checking:

// tsconfig.json
{
  "compilerOptions": {
    "jsx": "preserve",           // Let Vite handle JSX transformation
    "jsxImportSource": undefined // Prevent automatic React imports
  }
}

For entity types with JSX renders:

import { html } from "@inglorious/web"

type CounterEntity = {
  type: "counter"
  value: number
}

export const counter = {
  render(entity: CounterEntity, api) {
    return (
      <div className="counter">
        <span>Count: {entity.value}</span>
      </div>
    )
  }
}

🧠 Design Philosophy

This plugin is purely compile-time.

It does not introduce:

  • state
  • hooks
  • lifecycles
  • effects
  • subscriptions
  • partial reactivity

JSX is treated as syntax, not as a runtime system.

The execution model of @inglorious/web remains untouched:

store change → full deterministic render → diff → commit


🔁 JSX Rules & Semantics

Event handlers

<button onClick={save} />

<button @click="${save}"></button>

Property vs Attribute Binding

// Properties (use . prefix for custom elements and form controls)
<input value={x} />       // → .value=${x}
<my-element data={x} />   // → .data=${x}

// Attributes (standard HTML, kebab-case, or specific attributes)
<input id={x} />          // → id=${x}
<div data-id={x} />       // → data-id=${x}
<div class={x} />         // → class=${x}

Conditionals

{
  cond && <A />
}
{
  cond ? <A /> : <B />
}

→ compiled to when()


Lists

items.map((i) => <Row key={i.id} />)

→ compiled to repeat()

Keys are extracted automatically.


Fragments

<>
  <A />
  <B />
</>

Fully supported.


SVG

Nested SVG trees are handled correctly, including foreignObject.


Engine Components

Capitalized tags are treated as Engine Components and compiled to api.render() calls.

export const app = {
  render() {
    // ☝️ Plugin auto-injects 'api' if you use components!
    return <Form id="f1" />
  },
}

api.render("form", { id: "f1" })

💡 Smart injection: The plugin automatically adds the api parameter to your render function when you use Engine Components in JSX. You don't need to add it manually!

⚠️ Important Constraint

These engine components must:

  • not contain children
  • not represent DOM
  • not try to be React

They are render boundaries for your engine.

// ❌ DON'T DO THIS - Engine components don't support children
export const form = {
  render(entity, api) {
    return (
      <Form id="f1">
        <Field />
      </Form>
    )
  },
}

// ✅ DO THIS - Compose at the entity level instead
export const form = {
  render(entity, api) {
    return html`<form>${api.render("field", { formId: entity.id })}</form>`
  },
}

🧪 Why This Exists

React's runtime model is heavy, implicit, and hard to reason about at scale.

Inglorious Web is built on different principles:

  • Explicit data flow - All state lives in the store
  • Deterministic rendering - Same state always produces same output
  • Full-tree updates - No dependency tracking, no hidden subscriptions
  • Predictable performance - lit-html diffs everything, every time

This plugin lets you keep the ergonomics of JSX without compromising the architecture.


🧯 What This Plugin Does NOT Support (by design)

This plugin intentionally does not support:

  • React hooks (useState, useEffect, etc.)
  • Component-local state
  • Lifecycle methods
  • Context API
  • Portals
  • Fine-grained reactivity

Why? These features conflict with Inglorious Web's deterministic rendering model.

If you need these patterns, consider whether your state should live in the store instead, or use React directly.


License

MIT License - Free and open source

Created by Matteo Antony Mistretta

You're free to use, modify, and distribute this software. See LICENSE for details.