A no-VDOM, JSX framework for SSR
npm install --save stellis
yarn add stellis
pnpm add stellis
Automatic runtime
/* @jsxRuntime automatic */
/* @jsxImportSource stellis */
Classic runtime
/* @jsxRuntime classic */
/* @jsx h */
/* @jsxFrag Fragment */
import { h, Fragment } from 'stellis';
Reference: https://www.typescriptlang.org/docs/handbook/jsx.html#configuring-jsx
Automatic runtime
{
"compilerOptions": {
"jsx": "react-jsx", // or "react-jsxdev"
"jsxImportSource": "stellis",
}
}
Classic runtime
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
}
}
import { h, Fragment } from 'stellis';
Reference: https://esbuild.github.io/api/#transformation
Automatic runtime
CLI
esbuild --jsx=automatic --jsx-import-source="stellis" --jsx-dev
Options
const option = {
jsx: 'automatic',
jsxDev: true | false,
jsxImportSource: 'stellis',
};
Classic runtime (as options)
CLI
esbuild --jsx=transform --jsx-factory=h --jsx-fragment=Fragment
Options
const option = {
jsx: 'transform',
jsxFactory: 'h',
jsxFragment: 'Fragment',
};
Stellis uses Babel to transform your JSX and is provided in the form a plugin exported through stellis/babel
.
import { render } from 'stellis';
const result = await render(<h1>Hello World</h1>);
console.log(result); // <h1>Hello World</h1>
Stellis JSX is unlike your usual, React-like JSX:
className
, htmlFor
and readOnly
to be closer to DOM than HTML, which is the opposite of Stellis, where you can write class
, html
and readonly
.function Message({ greeting, receiver }) {
return <h1>{greeting}, {receiver}</h1>;
}
const result = await render(
<Message greeting="Hello" receiver="World" />
); // <h1>Hello World</h1>
async function Profile({ id }) {
const user = await getUser(id);
return <ProfileDetails user={user} />;
}
async function Profile({ id }) {
return <ProfileDetails user={await getUser(id)} />;
}
class
and class:<name>
directives<h1 class="example">Hello</h1>
<h1 class={["a", condB && b]}>Array</h1>
<h1 class={{ a: true, b: condB, c: condC }}>Object</h1>
<h1 class={["a", { b: condB }, [condC && "c"]]}>Nested</h1>
<h1 class:example>Hello</h1>
<h1 class:a class:b={cond}>Another Example</h1>
style
and style:<property>
directives<h1 style={{color: "red"}}>Red Heading</h1>
<h1 style:color="red">Red Heading 2</h1>
set:html
Sets the raw HTML content of the given element. Always takes priority over children
.
<div set:html="<script>Hello World</script>" />
ErrorBoundary
/<stellis:boundary>
Attempts to render children
. If it receives an error, fallback
is called with the received error and the result is rendered instead.
import { ErrorBoundary, render } from 'stellis';
function FailingComponent() {
throw new Error('Example');
}
const result = await render(
<ErrorBoundary
fallback={(error) => <>
<h1>Error: {error.name}</h1>
<p>Message: {error.message}</p>
</>}
>
<FailingComponent />
</ErrorBoundary>
);
console.log(result);
// Output: <h1>Error: Error</h1><p>Message: Example</p>
Fragment
/<stellis:fragment>
Same behavior as <></>
except this allows raw HTML output with set:html
<Fragment set:html="<script>Hello World</script>" />
<stellis:fragment set:html="<script>Hello World</script>" />
Comment
/<stellis:comment>
Allow inserting HTML comments
<stellis:comment value="This is a comment." />
// Output: <!--This is a comment.-->
Dynamic
import { Dynamic, render } from 'stellis';
function Example({ as, children }) {
return <Dynamic component={as}>{children}</Dynamic>;
}
const result = await render(
<Example as="h1">Hello World</Example>
);
console.log(result);
// Output: <h1>Hello World</h1>
import { createContext, setContext, getContext, render } from 'stellis';
const message = createContext('Hello World');
function Parent({ children }) {
setContext(message, 'Bonjour World');
return children;
}
function Child() {
return <h1>{getContext(message)}</h1>; // Hello World
}
const result = await render(
<>
<Parent>
<Child />
</Parent>
<Child />
</>
);
console.log(result);
// Output
// <h1>Bonjour World</h1><h1>Hello World</h1>
Built-in components that renders after the markup has resolved. Both <stellis:head>
and <stellis:body>
has the types "pre"
and "post"
which defines where the children are going to be injected.
Head
/<stellis:head>
<stellis:head type="pre">
<title>Hello World</title>
</stellis:head>
Body
/<stellis:body>
<stellis:body type="post">
<script src="./my-script.js" />
</stellis:body>
MIT lxsmnsyc