Introduction
JSlop is a fullstack TypeScript framework. You write components in .jslop files that look like ordinary code, and the compiler turns them into resumable, fine-grained, server-rendered web apps.
Svelte-like authoring, Solid-like reactivity, Qwik-like resumability, Next-like fullstack — without the mental tax.
No useEffect. No dependency arrays. No use client / use server boundaries to keep in your head. No loader/action files. State is just variables; the compiler turns them into reactive cells.
Warning
PLAN.md / TODO.md — they are not documented here yet because they don’t exist yet.A 60-second tour
Here is a complete JSlop component:
component Counter {
state count = 0
function inc() {
count++
}
view {
<button onclick={inc}>clicked {count} times</button>
}
}
Five things to notice:
state count = 0declares a reactive variable. Whencountchanges anywhere, every place that reads it updates.count++is a plain expression. The compiler rewrites it into the appropriate reactive read+write — you never typecount.valueorsetCount(c + 1).function inc()is a plain JavaScript function. NouseCallback, no closure traps.view { ... }holds HTML-like markup.{count}is an interpolation that re-evaluates fine-grained whencountchanges — only that text node updates.- No imports.
state,view,componentare language constructs the compiler understands. The runtime is wired up for you.
What you get
| Feature | Status |
|---|---|
state / prop / let reactivity |
done |
{#if} / {#each} (with keyed reconciliation) |
done |
bind:value / bind:checked |
done |
| Multiple components per file | done |
File-system routing with [param] segments |
done |
Layouts (_layout.jslop) and _404.jslop |
done |
| SSR with state capsule + client resume | done |
| Production build + Node adapter | done |
| Tailwind v4 out of the box | done |
| Server functions, schema forms, local-first | planned (roadmap) |
The mental model
Three kinds of variables, picked by what reads them:
component Search {
prop query = "" // input from a parent — reactive
state results = [] // the view reads it — reactive, serialized to the client
let cache = new Map() // bookkeeping the view never reads — plain JS
function run() {
if (cache.has(query)) { results = cache.get(query); return }
// ...
}
view {
<ul>{#each results as r (r.id)}<li>{r.label}</li>{/each}</ul>
}
}
One way to update: assign. count = count + 1, count++, todos = [...todos, t]. There is no setter function and no .value accessor.
One way to react: read. If count appears inside a view {...} expression or inside a function, that location depends on it. Update the cell and only that location re-runs.
That’s the whole model. The rest of the docs are details.
How to read the docs
If you’ve never used JSlop:
- Getting started — install, run the example apps, see code change live.
- Components — the four declaration keywords (
prop,state,let,function). - Template syntax — what goes inside
view { ... }. - Logic blocks —
{#if}and{#each}. - Bindings —
bind:valuefor forms. - Routing — file-system routes, layouts, 404.
Then dip into the reference pages as you need them:
- Reactivity — the
cell/derived/effectprimitives the compiler uses. - SSR & resumability — how state survives the network.
- Styling — Tailwind, plain CSS,
class={...}. - Building & deploying — production build,
@jslop/node-adapter. - Architecture — what each package does, end-to-end request flow. (For contributors / curious readers — not required to ship apps.)
If you’re comparing JSlop against the framework you already use, jump to the FAQ.