prax.mjs provides a very simple and performant system for rendering DOM/XML/HTML. It was originally React-inspired, but semantics are much simpler and more universally useful.
Isomorphic SSR is supported via lightweight and performant dom_shim
. Pairing these modules together, and using custom DOM elements, provides a good foundation for hybrid SSR/SPA.
Short overview of features:
- Directly create DOM nodes.
- No string templates.
- No VDOM.
- Can instantiate with
new
.
- Convenient syntax. Nice-to-use in plain JS.
- No templates.
- No string parsing.
- No need for JSX.
- No need for a build system.
- Render only once. Use native custom elements for state.
- Use
dom_reg
for more convenient element registration.
- Use
- Good for SSR/SPA hybrids.
Complemented by:
dom_shim
for SSR.dom_reg
for registering custom elements in SSR.obs_dom
for making custom elements automatically react to observables.
Rendering is done via Ren
. You must create an instance, which should be a singleton. You can also subclass Ren
and override individual methods to customize its behavior.
Browser example:
import * as p from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/prax.mjs'
import {A} from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/prax.mjs'
const ren = new p.Ren()
const E = ren.elemHtml.bind(ren)
const elem = E(`div`, {id: `main`, class: `outer`},
E(`p`, {class: `inner`},
`hello `,
`world!`,
),
)
document.body.append(elem)
/*
The following elements (not strings) have been appended:
<div id="main" class="outer"><p class="inner">hello world!</p></div>
*/
For rendering to string, use .outerHTML
:
console.log(elem.outerHTML)
/*
<div id="main" class="outer"><p class="inner">hello world!</p></div>
*/
Usage with custom elements:
import * as p from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/prax.mjs'
import * as dr from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/dom_reg.mjs'
const ren = new p.Ren()
const E = ren.elemHtml.bind(ren)
class SomeLink extends dr.MixReg(HTMLAnchorElement) {
init(href, text) {
return E(this, {href, class: `link`}, text)
}
}
document.body.append(
new SomeLink().init(`/some-path`, `click me!`),
)
For SSR (server-side rendering), Prax needs our lightweight DOM shim:
import * as p from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/prax.mjs'
import * as dg from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/dom_global_shim.mjs'
const ren = new p.Ren(dg.global.document)
const E = ren.elemHtml.bind(ren)
const elem = E(`div`, {id: `main`, class: `outer`},
E(`p`, {class: `inner`}, `hello world!`),
)
console.log(elem.outerHTML)
/*
<div id="main" class="outer"><p class="inner">hello world!</p></div>
*/
For SSR/SPA hybrids, configure an importmap or bundler to choose the right global document
and pass it to Ren
. The rest will just work.
import * as p from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/prax.mjs'
// Your bundler or importmap should choose the right one.
import * as dg from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/dom_global_shim.mjs'
import * as dg from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/dom_global_native.mjs'
const ren = new p.Ren(dg.global.document)
const E = ren.elemHtml.bind(ren)
// In both environments, this will be a DOM element.
// In SSR, it will be shimmed.
const elem = E(`div`, {id: `main`, class: `outer`},
E(`p`, {class: `inner`}, `hello world!`),
)
Rendering a complete document with doctype:
import * as p from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/prax.mjs'
import * as dg from 'https://cdn.jsdelivr.net/npm/@mitranim/[email protected]/dom_global_shim.mjs'
const ren = new p.Ren(dg.global.document)
const E = ren.elemHtml.bind(ren)
const elem = E(`html`, {lang: `en`},
E(`head`, null,
E(`link`, {rel: `stylesheet`, href: `/styles/main.css`}),
E(`title`, null, `page title`),
),
E(`body`, null,
E(`main`, {class: `main`}, `hello world!`),
),
)
console.log(p.DOCTYPE_HTML + elem.outerHTML)
/*
Formatted here for viewing convenience:
<!doctype html>
<html lang="en">
<head>
<link rel="stylesheet" href="/styles/main.css" />
<title>page title</title>
</head>
<body>
<main class="main">hello world!</main>
</body>
</html>
*/
The following APIs are exported but undocumented. Check prax.mjs.
const nsHtml
const nsSvg
const nsMathMl
const BOOL
const VOID
class Ren
class Raw
class PropBui
const DOCTYPE_HTML
function isSeq
function isNodable
function reqNodable
function isRaw
function reqRaw
function isNode
function reqNode
function isDocument
function optDocument
function reqDocument
function isNamespaced
function deref