Limitations

Azox is at v1.2.0. This page lists what it does not do, so you can decide whether it fits your project rather than finding out halfway through building one.

The index of a keyed row does not renumber

A keyed row is built once, so the index it was given is the position it was built at. Reordering the list moves the rows without renumbering them — the cost of keeping a row rather than rebuilding it.

Use the index for a list that grows and shrinks at the end. When a list reorders and the position matters, read it from your own data instead.

Lists rebuild unless you key them

A list without a key rebuilds its contents when the source changes, so anything a row was holding starts again. Adding key={item.id} keeps rows across reorders, removals and insertions.

The default is deliberate — a list of plain text gains nothing from being keyed — but it does mean the behaviour differs depending on whether you remembered to add one.

Routes are fixed at build time

Dynamic routes exist — a [slug].azox file builds one page per entry it declares — but the set of pages is decided when you build. There is no server rendering a URL on request, so a route that depends on something only known at request time is out of reach.

State does not survive navigation

Client-side routing exists, but each page starts fresh: navigating runs the new page's module from scratch, so its signals begin at their initial values. Nothing is carried across.

There are also no view transitions — the swap is immediate rather than animated.

Hydration replaces the markup

On a page that has something to hydrate, the client module clears the server-rendered root and rebuilds it rather than adopting the existing nodes. Content is present before JavaScript runs, which is what matters for search engines and slow connections, but this is not true hydration.

A page with no bindings and no listeners skips this entirely: it ships no JavaScript, so there is nothing to replace. That covers most pages of a content site — including nearly all of this one.

A layout is a component, not a route feature

A component can carry a <head> block, so one shared component holds the stylesheet, fonts and scripts every page needs — see Components. What there is no equivalent of is a layout that applies to a directory on its own: each page still imports the layout and wraps its content in it.

No CSS pipeline

A component's <style> block is scoped, but that is the only thing Azox does to your CSS. Files in public/ are copied as-is: nothing is bundled, minified or hashed, and there is no preprocessor.

Expressions are evaluated during the build

Server rendering runs a page's <script> block through new Function. That is fine for project source you wrote, which is the same assumption any template engine's server step makes — but never point a build at .azox content submitted by someone else.

What does work

The parts that exist are tested and behave predictably: signals, effects and computed values; components with props, slots and state of their own; loops and conditionals, nested to any depth; file-based routing; optional client-side navigation with prefetching; server rendering with escaping; the dev server with live reload; and a build that runs on any static host.

Every one of these gaps is a deliberate stopping point rather than an oversight. Follow the repository to see what lands next.