miqro · @miqro/core · @miqro/parser · @miqro/query · @miqro/jsx · @miqro/jsx-dom · @miqro/jsx-node · @miqro/request · @miqro/runner · @miqro/test · @miqro/test-http

@miqro/jsx

JSX vDOM with hooks. runs server-side and in the browser via runtime adapters.

runtimes: browser → @miqro/jsx-dom · server → @miqro/jsx-node

tsconfig.json

{
  "compilerOptions": {
    "jsx": "react",
    "jsxFactory": "JSX.createElement",
    "jsxFragmentFactory": "JSX.Fragment"
  }
}

usage

import JSX in every .tsx file:

import JSX from "@miqro/jsx";

function Hello() {
  return <p>Hello</p>;
}

hooks

useState

import JSX, { useState } from "@miqro/jsx";

function Counter() {
  const [n, setN] = useState(0);
  return <button onClick={() => setN(n + 1)}>{n}</button>;
}

useEffect

import JSX, { useState, useEffect } from "@miqro/jsx";

function Timer() {
  const [n, setN] = useState(0);

  useEffect(() => {
    const t = setTimeout(() => setN(n + 1), 1000);
    return () => clearTimeout(t);
  }, [n]);

  return <p>{n}</p>;
}

effects are disabled during SSR by default. but you can enable them with runtime options.

useContext

import JSX, { createContext, useContext } from "@miqro/jsx";

const ThemeContext = createContext();

function App() {
  return <ThemeContext.provider value="dark">
    <Child />
  </ThemeContext.provider>;
}

function Child() {
  const theme = useContext(ThemeContext);
  return <p>{theme}</p>;
}

useQuery

syncs state with URL query string.

import JSX, { useQuery } from "@miqro/jsx";

function Page() {
  const [page, setPage] = useQuery("page", 1);
  return <button onClick={() => setPage(page + 1)}>page {page}</button>;
}

usePathname

import JSX, { usePathname } from "@miqro/jsx";

function Nav() {
  const path = usePathname();
  return <p>current: {path}</p>;
}

useRef

import JSX, { useRef, useEffect } from "@miqro/jsx";

function Input() {
  const ref = useRef(null);
  useEffect(() => {
    if (ref.current) ref.current.focus();
  }, []);
  return <input ref={ref} />;
}

useElement

access the underlying DOM element the component renders into.

import JSX, { useElement } from "@miqro/jsx";

function Component() {
  const el = useElement();
  // el is the RuntimeHTMLElement
}

useRefresh

force re-render.

import JSX, { useRefresh } from "@miqro/jsx";

function Component() {
  const refresh = useRefresh();
  // refresh() forces re-render
}

useRuntime

import JSX, { useRuntime } from "@miqro/jsx";

function Component() {
  const runtime = useRuntime();
  // runtime.name === "dom" | "node"
}

client-side routing.

import JSX, { Router, Link, Route } from "@miqro/jsx";

function App() {
  return <Router>
    <nav>
      <Link href="/home">Home</Link>
      <Link href="/about">About</Link>
    </nav>
    <Route path="/home"><Home /></Route>
    <Route path="/about"><About /></Route>
  </Router>;
}

runtimes

same component code runs on both runtimes.

server (Node.js)

import { createNodeRuntime } from "@miqro/jsx-node";
import { createContainer, createElement } from "@miqro/jsx";
import { MyComponent } from "./component.js";

const runtime = createNodeRuntime({ url: { pathname: "/", searchParams: new URLSearchParams(), toString: () => "/" } });
const root = runtime.createElement("div");
const container = runtime.createContainer(root);
container.render(createElement(MyComponent, { title: "hello" }));
console.log(root.toString()); // <div><p>hello</p></div>
container.disconnect();

browser

import { createDOMContainer } from "@miqro/jsx-dom";
import { createElement } from "@miqro/jsx";
import { MyComponent } from "./component.js";

const root = document.getElementById("root");
const container = createDOMContainer(root);
container.render(createElement(MyComponent, { title: "hello" }));

component options

shadowInit

function MyComponent() { ... }
MyComponent.shadowInit = false;                  // no shadow DOM
MyComponent.shadowInit = { mode: "open" };       // open shadow root
// default: { mode: "closed" }

asFragment

render without wrapper element.

function MyComponent() { ... }
MyComponent.asFragment = true;

debug

import { enableDebugLog } from "@miqro/jsx";
enableDebugLog();