//puredom.js
//@flow
//@jsx domsx
//@jsxFrag 'fragment'
const handlers = (global.handlers = [])
initDOM()
const ClickMe = (props, childs) => (
<button onClick={e => console.log(e)}>click me</button>
)
render(
<div id="app">
{callsites().map(line => (
<p>{line.toString()}</p>
))}
<ClickMe />
</div>,
)
function render(app) {
appendChild(document.body, app)
}
//eslint-disable-next-line no-unused-vars
function domsx(tag, props, ...childrens) {
if (tag === 'fragment') return childrens
if (typeof tag === 'function') return tag(props, childrens)
const item: HTMLElement = document.createElement(tag)
if (props !== null) {
for (let key in props) {
let value = props[key]
if (key === 'key') continue
if (key === 'className') key = 'class'
if (key.startsWith('on') && typeof value === 'function') {
const index = handlers.push(value) - 1
value = `(0, handlers[${index}])(this)`
}
item.setAttribute(key, value)
}
}
for (const child of childrens) {
appendChild(item, child)
}
return item
}
function appendChild(item, child) {
invariant(item, 'no item')
if (Array.isArray(child)) {
for (const ch of child) {
appendChild(item, ch)
}
} else if (typeof child === 'string' || typeof child === 'number') {
const text = document.createTextNode(String(child))
item.appendChild(text)
} else {
item.appendChild(child)
}
}
function initDOM(id = 'app') {
const body = document.body
invariant(body, 'nobody')
const app = document.querySelector('#' + id)
if (app !== null) {
body.removeChild(app)
}
}
function callsites() {
let stack: Array<CallSite> = []
const _prepareStackTrace = Error.prepareStackTrace
Error.prepareStackTrace = (_, stackOrig) => {
stack = stackOrig.slice(4, -1)
return stackOrig
}
new Error().stack
Error.prepareStackTrace = _prepareStackTrace
return stack
}
function invariant(cond, message, ...args) {
if (cond) return
let argIndex = 0
const error = new Error(message.replace(/%s/g, () => args[argIndex++]))
error.name = 'Invariant Violation'
throw error
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Pure DOM example</title>
</head>
<body>
<script src="./puredom.js"></script>
</body>
</html>
start.sh
yarn init --yes
yarn add -D parcel-bundler
npx parcel index.html