jq79
A independent reactive component library that ships as a single file. Svelte-style reactive scripts, fine-grained DOM updates via proxy-based dependency tracking
no compiler required, no virtual DOM, no dependencies.
Take the tutorial → — a handful of exercises you edit in the browser, with a live preview. Because there's no compiler, the tutorial runs the real library: the component you write is the component that mounts.
Installation
npm
npm install jq79
import { Component79, $, $$ } from "jq79"
Vite
With the bundled plugin, .html component files import as modules — no
runtime fetch, with HMR in dev:
// vite.config.js
import { jq79 } from "jq79/vite"
export default { plugins: [jq79()] }
import UserCard from "./UserCard.html"
UserCard.mount("#app")
The plugin is a pure loader (nothing inside the component is transformed), so
the same file keeps working from public/ via Component79.fetch — see
the Vite plugin docs.
CDN
Once published to npm, the package is automatically served by every major CDN — no separate publishing step:
<!-- as an ES module -->
<script type="module">
import { Component79 } from "https://esm.sh/jq79"
// or: https://cdn.jsdelivr.net/npm/jq79/+esm
// or: https://unpkg.com/jq79?module
// or, straight from this repo's GitHub Pages (latest release):
// https://jgermade.github.io/jq79/jq79.js
</script>
<!-- or as a classic script exposing window.jq79 -->
<script src="https://cdn.jsdelivr.net/npm/jq79/dist/jq79.global.js"></script>
<!-- or: <script src="https://jgermade.github.io/jq79/jq79.global.js"></script> -->
<script>
const { Component79 } = jq79
</script>
Pin a version in production: https://cdn.jsdelivr.net/npm/jq79@0.1.0/... (the GitHub Pages copy always tracks the latest release).
The source is small enough to read in a sitting: the core (parsing, rendering, components) lives in src/jq79.ts, with three leaf helpers — dom.ts, reactive.ts and transform.ts. The published build is a single dependency-free file.
Quick start
import { Component79 } from "jq79"
const jq79 = new Component79(html`
<script :setup>
let firstName = null
let lastName = null
$: fullName = firstName && lastName ? \`\${firstName} \${lastName}\` : ""
API.fetch("/me").then(user => {
firstName = user.firstName
lastName = user.lastName
})
</script>
<div :if="fullName" class="user-info">
<span>{{ fullName }}</span>
</div>
<style>
.user-info { color: rebeccapurple; }
</style>
`)
jq79.mount("#app")
When the fetch resolves, the assignments to firstName/lastName re-run the $: declaration, which flips the :if and renders the span — no manual wiring.
Documentation
- Tutorial — learn it by doing, in the browser.
- Components — lifecycle (
mount,mountShadow,detach,destroy), instance events (on/off),<style scoped>, loading remote components withComponent79.fetch. - Template syntax —
{{ }}interpolation,:attrs,:text/:html,:if/:elseif/:else,:each/:key,:with,@eventlisteners and modifiers, nested components. - Setup scripts —
<script :setup>reactive scripts,$:declarations,$emit,await $mounted(),$self/$$self, andexport defaultfactory scripts (plain-JS alternative). - Reactive data — the standalone
$reactivestore:$on,$onAny,$effect. - DOM helpers —
$,$$and$create. - Vite plugin — importing
.htmlcomponents as bundled modules, HMR, options. - Dev server —
npx jq79 dev: serve and hot-reload components with no build step. - Development — running tests, building, publishing releases.
License
ISC