pudui
v0.0.14
Published
A tiny JSX UI runtime built from the ground up.
Readme
pudui
A tiny JSX UI runtime built from the ground up. The model is intentionally
small: functional component factories return Component instances, and
component state lives in ordinary closures.
Getting Started
npx giget@latest gh:jacob-ebey/pudui-template my-pudui-app
cd my-pudui-app
vp install
vp devConstraints
- No runtime dependencies.
- No hooks.
- No class components as a user-facing component model.
- Functional components only.
- Stateful behavior is explicit: mutate closure data and call
component.update().
MVP API
Component<Props>stores a render function and exposesupdate(callback?)andmount(callback).component.update(callback?)requests an update. When a callback is passed, it runs after the update has committed to the DOM.Component<Props>accepts an optionalerror(props, reason)function that renders fallback output when that component or one of its children throws.render(child, container)mounts JSX or a component into a DOM container and returns a root withrerender(child)andunmount().hydrate(root, options)hydrates server-rendered boundaries and returns the same root API synchronously.renderToString(child, props?)frompudui/serverrenders JSX or a component to escaped HTML.createElement,jsx,jsxs, andjsxDEVprovide classic and automatic JSX runtimes.refaccepts one callback or nested arrays of callbacks. Each callback receives the element after insertion and may return a cleanup function that runs before removal. Known JSX tag names infer the matching DOM element type.component.mount(callback)registers callbacks that run once, after the component first enters the DOM and after ref callbacks for that commit.event(type, handler)returns a ref callback that adds an event listener and removes it during cleanup. Known DOM event names infer the matching event object type.Fragmentrenders children without adding an extra element.
JSX Setup
Use the automatic runtime in applications:
{
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "pudui"
}
}Stateless Component
import { Component } from "pudui";
import { renderToString } from "pudui/server";
type Props = {
name: string;
};
function HelloWorld(_initialProps: Props) {
return new Component<Props>({
render({ name }) {
return <div>Hello, {name}!</div>;
},
});
}
renderToString(<HelloWorld name="Ada" />);Error Handling
import { type Child, Component } from "pudui";
type Props = {
children?: Child;
};
function Boundary(_initialProps: Props) {
return new Component<Props>({
error(_props, reason) {
return <p>Something went wrong: {String(reason)}</p>;
},
render({ children }) {
return <section>{children}</section>;
},
});
}Stateful Component
import { Component, event } from "pudui";
type Props = {
initialCount?: number;
};
function Counter(initialProps: Props) {
let count = initialProps.initialCount ?? 0;
const increment = event("click", () => {
count++;
component.update();
});
const component = new Component<Props>({
render() {
return (
<div>
<p>Count: {count}</p>
<button
type="button"
ref={increment}
>
Increment
</button>
</div>
);
},
});
return component;
}Development
vp check
vp dev