npm:npm i sinuous
cdn:https://cdn.jsdelivr.net/npm/sinuous/+esm
- Small.hello world at
~1.4kB
gzip. - Fast.top rankedof 80+ UI libs.
- Truly reactive.automatically derived from the app state.
- DevEx.no compile step needed, choose yourview syntax.
Size | Name | Description |
---|---|---|
sinuous/observable |
Tiny observable(included by default) | |
sinuous/map |
Fast list renderer | |
sinuous/hydrate |
Hydrate static HTML | |
sinuous/template |
Pre-rendered Template |
- sinuous-context(@theSherwood): A light-weight, fast, and easy to use context api for Sinuous.
- memo(@luwes): Memoize components and functions.
- disco(@luwes): Universal
connected
anddisconnected
lifecycle events. - sinuous-style(@theSherwood): Scoped styles for Sinuous à la styled-jsx.
- sinuous-lifecycle(@heyheyhello): onAttach/onDetach DOM lifecycles.
- sinuous-trace(@heyheyhello): Traces the internal API to record component creation, adoption, and removal.
- Counter(@ CodeSandbox)
- Analog SVG Clock⏰
- Classic TodoMVC(GitHub Project)
- JS Framework Benchmark(@ GitHub)
- Sierpinski Triangle
- Three.js Boxes📦
- JSX(GitHub Project @heyheyhello)
- TSX(GitHub Project @heyheyhello)
- Simple routing(@mindplay-dk) 🌏
- Datepicker(@mindplay-dk)
- Hacker News(@mindplay-dk)
- 7 GUIs(@theSherwood)
- Plain SPA(@johannschopplich)
Seecomplete docs,or in a nutshell...
A goal Sinuous strives for is to have good interoperability. Sinuous creates DOM elements viahyperscripth
calls. This allows the developer more freedom in the choice of the view syntax.
Hyperscriptdirectly callh(type: string, props: object,...children)
.
Tagged templatestransform the HTML toh
calls at runtime w/ thehtml``
tag or,
at build time withsinuous/babel-plugin-htm
.
JSXneeds to be transformed at build time first withbabel-plugin-transform-jsx-to-htm
and after withsinuous/babel-plugin-htm
.
Counter Example (1.4kB gzip) (Codesandbox)
import{observable,html}from'sinuous';
constcounter=observable(0);
constview=()=>html`<div>Counter${counter}</div>`;
document.body.append(view());
setInterval(()=>counter(counter()+1),1000);
import{h,observable}from'sinuous';
constcounter=observable(0);
constview=()=><div>Counter{counter}</div>;
document.body.append(view());
setInterval(()=>counter(counter()+1),1000);
import{h,observable}from'sinuous';
constcounter=observable(0);
constview=()=>h('div','Counter ',counter);
document.body.append(view());
setInterval(()=>counter(counter()+1),1000);
The Sinuousobservable
module provides a mechanism to store and update the application state in a reactive way. If you're familiar withS.jsorMobxsome functions will look very familiar, in under1kB
Sinuous observable is not as extensive but offers a distilled version of the same functionality. It works under this philosophy:
Anything that can be derived from the application state, should be derived. Automatically.
import{observable,computed,subscribe}from'sinuous/observable';
constlength=observable(0);
constsquared=computed(()=>Math.pow(length(),2));
subscribe(()=>console.log(squared()));
length(4);// => logs 16
Sinuous can work with different observable libraries; S.js, MobX, hyperactiv. See thewiki for more info.
Sinuoushydrate
is a small add-on that provides fast hydration of static HTML. It's used for adding event listeners, adding dynamic attributes or content to existing DOM elements.
In terms of performance nothing beats statically generated HTML, both in serving and rendering on the client.
You could say using hydrate is a bit like usingjQuery,you'll definitely write less JavaScript and do more. Additional benefits with Sinuous is that the syntax will be moredeclarativeandreactivityis built-in.
import{observable}from'sinuous';
import{hydrate,dhtml}from'sinuous/hydrate';
constisActive=observable('');
hydrate(
dhtml`<a class= "navbar-burger burger${isActive}"
onclick=${()=>isActive(isActive()?'':' is-active')}/>`
);
hydrate(dhtml`<a class= "navbar-menu${isActive}"/>`);
Sinuous exposes an internal API which can be overridden for fun and profit. For examplesinuous-contextuses it to implement a React like context API.
As of0.27.4
the internal API should be used to make Sinuous work with a 3rd party reactive library likeMobx.This can be done by overridingsubscribe
,root
,sample
andcleanup
.
import{api}from'sinuous';
constoldH=api.h;
api.h=(...args)=>{
console.log(args);
returnoldH(...args);
};
These are defined insinuous/srcandsinuous/h.
h(type: string, props: object,...children)
hs(type: string, props: object,...children)
insert<T>(el: Node, value: T, endMark?: Node, current?: T | Frag, startNode?: Node): T | Frag;
property(el: Node, value: unknown, name: string, isAttr?: boolean, isCss?: boolean): void;
add(parent: Node, value: Value | Value[], endMark?: Node): Node | Frag;
rm(parent: Node, startNode: Node, endMark: Node): void;
subscribe<T>(observer: () => T): () => void;
root<T>(fn: () => T): T;
sample<T>(fn: () => T): T;
cleanup<T extends () => unknown>(fn: T): T;
Note thatsomeobservable methods are imported into the internal API fromsinuous-observable
because they're used in Sinuous' core. To access all observable methods, import fromsinuous/observable
directly.
Sinuous started as a little experiment to get similar behavior asSurplusbut with template literals instead of JSX.
HTMcompiles to anh
tag. Adapted code fromRyan Solid's dom expressions + a Reactive library provides the reactivity.
Sinuous returns ahyperscriptfunction which is armed to handle the callback functions from the reactive library and updates the DOM accordingly.
This project exists thanks to all the people who contribute. [Contribute].
Become a financial contributor and help us sustain our community. [Contribute]
Support this project with your organization. Your logo will show up here with a link to your website. [Contribute]