The JetShake philosophy.
TL;DR: React won as a language and lost as a runtime. JetShake is an optimizing compiler for the React dialect: standard JSX and hooks in, signals and direct DOM out, HTML first, and a runtime that scales down to what your app actually uses instead of up to what the framework might need.
React is a language now
At some point in the last decade, React stopped being a library and became a dialect. Millions of developers think in JSX and hooks. Every design system that matters ships in it. Every AI model writes it by default when you ask for UI. It's the most widely known way of describing an interface, for people and for models, and along the way it picked up the largest component ecosystem ever built.
And all of it is tied to one delivery mechanism. Using any of it means shipping the React runtime: tens of kilobytes of reconciler before your first component renders, and a virtual DOM that spends the app's whole life working out, at runtime, things that were obvious in the source code. <h1>{count}</h1> doesn't need a diffing engine to discover that only a text node changes - that was knowable at build time. React ships the machinery to rediscover it on every update anyway.
That's the tax JetShake exists to remove.
What Svelte and Solid proved
Svelte showed that a framework can be a compiler. Solid showed that fine-grained signals make the virtual DOM optional. JetShake is built directly on those models - a compiler that emits signals. Between them they settled the technical argument years ago: compile ahead of time, update only what changed, ship less. JetShake doesn't reopen that argument. It agrees with it completely.
The one thing left unsolved was reach. Both ask you to switch: a new dialect, a new ecosystem, a team that has to relearn its tools, and today, AI models that write React whatever you ask for. For a greenfield project that's often a fair trade, and plenty of teams make it happily. But for the millions already fluent in React, the cost of leaving has kept a settled idea from ever reaching them.
JetShake's bet is that you shouldn't have to give up React to get it.
Write the same React code. Compile it to something better.
What the compiler does
You write an ordinary React component - useState, props, JSX, nothing annotated, nothing renamed:
function Counter() { const [count, setCount] = useState(0); return <button onClick={() => setCount(count + 1)}>{count}</button>; }
JetShake compiles it the way Solid or Svelte would have you author it: useState lowers to a signal, the JSX lowers to real DOM construction, and the {count} binding becomes a targeted text-node update subscribed to exactly one signal. No virtual DOM is created, diffed, or shipped. There's no React runtime in the output - the emitted contract is just Component(props) -> Node.
Because it's a compiler with whole-program visibility, it doesn't stop at one component. It sees your app, your imported libraries, the interaction patterns between them - context, keyed lists, refs, portals, transitions - and lowers what it can prove.
What you don't use, you don't pay for
A framework is a fixed cost: every feature any app might ever need, shipped to every visitor, mostly unused. C++ has had a rule against this since the eighties - Stroustrup's zero-overhead principle, in two halves: what you don't use, you don't pay for, and what you do use, you couldn't hand-code better. Somewhere along the way, UI frameworks dropped both halves.
Our internal doctrine restates the rule for UI delivery: app mode must not pull features the app does not use. createRoot is a boot, not permission to ship the reconciler monolith.
So the JetShake runtime is a set of small modules - signal core, keyed-list diffing, style application, ref plumbing, context, transitions - and each one is emitted only when the compiled output actually references it. No keyed .map() in your app, no list differ in your bundle.
The runtime, as shipped for a counter
The result scales down - with what's actually built:
And the top row is the principle's second half at work: compiled output converging on what you'd write by hand. The same code through the standard toolchain would start at React's fixed floor and go up. That scaling is the real product: you pay for what you built, not for what the framework is.
There's a falsifiable version of the rule we test against: a whole app should weigh about the same as its pieces exported one by one. If splitting your app into islands by hand saves bytes, app mode has a bug.
A compiler you don't have to trust blindly
Compiling a language you don't control means running into code you can't fully lower. Every compiler for an existing language faces this, and there are two honest responses: restrict the input ("our subset of React"), or guarantee the fallback. Restricting the input silently recreates the trade we refused - you end up in a dialect again, just an undocumented one.
So JetShake carries its correctness guarantee inside the engine: the compiler never breaks your component. Anything it can't fully optimize still runs correctly - just bigger. When a component defeats analysis, that component - not your app - falls back to a React-compatible rendering path, bundled when it's reachable and tree-shaken to zero when it isn't.
One tree, per-component guarantee
None of this runs on the honour system. React's own unit-test suite runs against the engine's compatibility surface. Hundreds of differential browser cases render every scenario twice - real React beside compiled output - and assert observable equivalence: DOM, event behaviour, effect timing. The rule for the test suite fits in a sentence: a test may only fail when a real React app would behave differently. Per-library suites (Radix, BaseUI, react-hook-form, TanStack Query, Zustand, react-select) run the same way. Ecosystem support is something you demonstrate, one library at a time.
HTML is the best delivery format
A compiler that lowers JSX to DOM instructions knows, at build time, what the page looks like. It would be negligent not to write that down.
So the default delivery for a JetShake app is HTML first: the build prerenders each route to a static HTML file and ships the interactive remainder in a few kilobytes of client JavaScript. First paint is a file on a CDN. Search engines and link-unfurlers read real markup. The JavaScript comes after, and there's only a few kilobytes of it - not a platform the page has to boot before it can exist.
Where the first content appears
This is static generation, not server-side rendering - there's no server on the hot path and nothing re-renders per request. For the large class of pages whose HTML doesn't depend on the request, doing the work once at build time beats redoing it on every request: one artifact, cacheable anywhere, no server to keep alive. Request-time SSR remains the right tool when HTML genuinely varies per request, and it composes with the same engine.
If this sounds like islands architecture: it is, with one structural difference. Islands frameworks make separate roots that can't share context, state or a tree, and make you leave the React dialect (or pay React per island) to get them. A JetShake app stays one React program - one tree, context and composition intact - and the compiler does the splitting, by reachability, including per-route chunks it prerenders and preloads.
The locked ecosystem, unlocked
The strangest consequence of treating React as a language is that the output doesn't need React on the page - so it doesn't need a React app around it either.
jetshake export compiles a component into a self-contained HTML tag. A Laravel, Rails, Django or plain-HTML page includes one script and writes <jet-dialog> - data in through attributes, events out as native DOM events, no npm, no build step, no runtime dependency on the React project the component came from.
$ npx jetshake export dialog.tsx ✓ jet-dialog.js 4.9 KB gz - self-contained, no react-dom <!-- any page, any stack --> <script type="module" src="/js/jet-dialog.js"></script> <jet-dialog title="Delete project?"></jet-dialog>
In real numbers: a pure-CSS-and-hooks component exports at a few KB; heavier, logic-dense components cost more; and a library that's deeply coupled to React's runtime lifecycle (animation runtimes, notably) falls back to the compatibility path - correct, but not small, so we don't market it small.
React built the largest UI ecosystem in history and locked it inside one runtime. Compile that ecosystem's unmodified source to framework-free output, and it opens up to every stack that could never justify shipping React - which is most of the web.
The best build is the default
Most tools make you earn good output. You learn the right flags, the right config, the right plugin order, and you're rewarded with a smaller bundle - miss one and you quietly ship the slow version. JetShake turns that around: the best build is the one you get by typing nothing. Flags exist only to make the output worse - to override the engine on the rare occasion you know something it doesn't.
You should never have to become a packaging architect. Whether your code is one app, a group of components sharing a store, or a single exported tag - and whether it prerenders, splits, or inlines - the engine decides from the shape of your code, and tells you what it chose on stdout. The whole workflow is: run the build, read what it did, ship. If you ever go hunting for a flag to get the good output, that's a bug in the defaults, not a lesson you should have learned.
This page's build, as reported on stdout
[jetshake] Build report packaging shape : app delivery intent : html-first leanBoot : ON 33 compiled, 0 bailed to compat ★ fully compiled - zero bailouts compat renderer : 0.0 KB none
vite build prints what the engine decided and what it cost, so the claims on this page are checkable.
Trust is the product
A compiler that rewrites other people's components lives or dies on trust, so the strategy is deliberately unexciting: verify against React itself, publish numbers that reproduce, and don't claim more than the current tier can prove. There's a dogfooding rule too: any page that says "no React runtime" has to be compiled by JetShake, and this one is - you can check the network tab. A project like this doesn't get to fake a demo.
The endgame isn't a framework with a logo and a conference. It's quieter than that: you keep writing the React you already write, and the delivery layer - runtime, reconciler, hydration waterfall, the fixed tax on every visitor - just stops being something anyone thinks about.
Write React.
Ship the Web.
Want to get notified when JetShake launches?
Zero spam. Unsubscribe in one click.