Hyperapp
Hyperapp is an ultra-lightweight JavaScript framework for building single-page applications, emphasizing minimalism and performance. It integrates state management and a Virtual DOM engine, all within a small footprint (around 1 KB gzipped) and without external dependencies. The current stable version is 2.0.22, with major versions introducing significant feature enhancements and API refinements, though a strict release cadence isn't explicitly stated beyond regular updates. Its key differentiators include its small bundle size, a declarative and purely functional API, and a focus on minimizing the concepts developers need to learn, encompassing views, actions, effects, and subscriptions. It offers a streamlined approach to building performant web applications with an optimized diffing algorithm for efficient DOM updates.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use CommonJS `require()` syntax to import Hyperapp in an ES Module context (e.g., modern browser, Node.js with `"type": "module"`).fixUse ES Module `import` syntax: `import { app, h, text } from 'hyperapp'`. Ensure your project's `package.json` has `"type": "module"` or your build setup correctly handles ESM. -
Property 'name' does not exist on type 'VNode' or 'Property 'props' does not exist on type 'VNode'
cause Accessing deprecated VNode property names (`name`, `props`) from Hyperapp v1.0.0 or earlier after upgrading to Hyperapp v1.1.0 or later.fixUpdate VNode property accessors in your code from `vnode.name` to `vnode.nodeName` and from `vnode.props` to `vnode.attributes`. -
TypeError: app expects a function as the first argument, not an object
cause Attempting to initialize the `app` function with an outdated signature, specifically prior to v0.15.0 which introduced the single configuration object, or if providing arguments in the v1.x `app(state, actions, view, node)` style to v2.x.fixEnsure the `app` function is called with a single configuration object containing `init`, `view`, and `node` properties, as required since Hyperapp v0.15.0 and refined in v2.0.0. Example: `app({ init: {}, view: () => h('div'), node: document.body })`.
Warnings
- breaking Hyperapp v1.1.0 introduced a breaking change to the internal VNode schema, renaming `name` to `nodeName` and `props` to `attributes` to align with Preact's virtual nodes. Direct access to these properties in custom VNode processing or component libraries will break.
- breaking Hyperapp v0.15.0 introduced the `init(state, actions)` function, which significantly changed how applications are initialized and how global events or subscriptions are handled, replacing older patterns.
- breaking Hyperapp v0.14.0 brought substantial breaking changes, including simplified state management with 'state slices', replaced events with direct DOM event handling, and removed mixins for code clarity. Code relying on previous event systems or mixins will cease to function.
- breaking Hyperapp v2.0.0 introduced new core features like Effects and Subscriptions, and an enhanced Dispatch mechanism. While adding capabilities, the overall architecture and how state/actions/effects interact became more structured, potentially requiring refactoring for existing v1.x applications.
- gotcha Modern Hyperapp (v2.0.0 and above) is primarily designed for ES Module (ESM) environments, as indicated by its documentation and examples using `import` statements. Attempting to use CommonJS `require()` syntax directly in a browser or non-transpiled Node.js environment will result in module resolution errors.
Install
-
npm install hyperapp -
yarn add hyperapp -
pnpm add hyperapp
Imports
- app
const { app } = require('hyperapp')import { app } from 'hyperapp' - h
import h from 'hyperapp'
import { h } from 'hyperapp' - text
import { Text } from 'hyperapp'import { text } from 'hyperapp'
Quickstart
import { h, text, app } from "hyperapp";
interface State {
todos: string[];
value: string;
}
const AddTodo = (state: State): State => ({
...state,
value: "",
todos: state.todos.concat(state.value),
});
const NewValue = (state: State, event: Event & { target: HTMLInputElement }): State => ({
...state,
value: event.target.value,
});
// Ensure a root element exists in the DOM
const root = document.getElementById("app") || document.createElement("main");
if (!document.getElementById("app")) {
root.id = "app";
document.body.appendChild(root);
}
app<State>({
init: { todos: [], value: "" },
view: ({ todos, value }) =>
h("main", {}, [
h("h1", {}, text("To do list")),
h("input", { type: "text", oninput: NewValue, value }),
h(
"ul",
{},
todos.map((todo) => h("li", {}, text(todo)))
),
h("button", { onclick: AddTodo }, text("New!")),
]),
node: root,
});