Getting started with Hyperapp

July 22, 2018 0 Comments

Getting started with Hyperapp



Hyperapp is described as a functional alternative to React thats very small in size. It takes ideas from Elm and React, so if you are familiar with those libraries than Hyperapp will be easier to understand. The library weighs in at a wopping 1kb which lends to speed of your app and readability of its code. The code is about 300 lines long and can easily be read and understood in a short amount of time. In this article I'm going to show you how to get started using Hyperapp using an asset bundler called Parcel.js. Let's dive in!

Some setup

We'll start by using npm to build out an infrasturcture for the app.

mkdir hyperapp-start && cd hyperapp-start

Next we will npm init while inside /hyperapp-start. From there we can then install some of our dependencies. Parcel.js is a very simple module bundler that allows you to use es6/sass/postcss...etc, without much configuration if any.

npm i hyperapp && npm i -D parcel

Let's also create a little structure for our Hyperapp app (or is it just 'hyperapp' from here on out...?). I like to use the following structure:

src/ index.html index.js

Parcel requires an entry point so I use an index.html with a script pointing to the index.js

<!DOCTYPE html>
<html lang="en">
<head> <meta charset="UTF-8"> <title>Hyperapp & Parcel sitting in a tree</title>
<body> <script src="./index.js"></script>

This allows parcel to do its magic and create a static index to distribute.

With parcel installed in your project you can use Parcel's CLI in your package.json scripts.

"start": "parcel ./src/index.html --out-dir ./dist"

This will run parcels server and output a directory at the root of your project in ./dist

You can also build a project using the following script.

"start": "parcel build ./src/index.html --out-dir ./dist"

Hyperapp... finally!

With some structure out of the way and our build system in place lets dig in to Hyperapp.

Heres an example of a counter app created using Hyperapp. This code should exist in the index.js.

import { h, app } from 'hyperapp'; const state = { count: 0,
}; const actions = { down: value => state => { return {count: state.count - value}; }, up: value => state => { return {count: state.count + value}; },
}; const view = (state, actions) => ( <div class="wrap"> <h1>{state.count}</h1> <button onclick={() => actions.down(1)}>-</button> <button onclick={() => actions.up(1)}>+</button> </div>
); const main = app(state, actions, view, document.body);

Start the parcel dev server with npm start and open your browser to http://localhost:1234 to see the app working.

Some of this should look familiar if you are coming from React or Elm. Lets start at the top and work our way down.

First, import { h, app } from 'hyperapp';. These are the 2 functions that make up Hyperapp. h creates your virtual DOM and app ties the state, actions and view together to create the app and allow updates on state change.

Next, let's talk about the state and actions of the app.

const state = { count: 0,
}; const actions = { down: (value) => (state) => { return {count: state.count - value}; }, up: (value) => (state) => { return {count: state.count + value}; },

state is an object that contains the state of the entire app. actions is another object that contains all the actions for your app. Actions allow you to update the state. You cannot update state without an action. When updating state with an action you are effectivley creating a new state object without mutating the original state object.

This lends in keeping your code clean and less error prone as everything will come from one source, the action. This is very similar to Redux minus all the boilerplate you need to get it running in React. With Hyperapp you get it by default.

Let's take a look at one of the actions.

down: (value) => (state) => { return {count: state.count - value};

down is a curried function this allows for more modularity and immutabilty. Say you call down(1) from your view; the value 1 will get passed in and then passed to another function that contains the state. From there the function returns an object that represents the part of the state you wish to update. This in turn creates a new state object with the new value and triggers a redraw of the DOM and updates the view.

Moving on to the view. You can write this in either JSX or plain h function calls. I like JSX so thats what I've chosen to write my view with.

const view = (state, actions) => ( <div class="wrap"> <h1>{state.count}</h1> <button onclick={() => actions.down(1)}>-</button> <button onclick={() => actions.up(1)}>+</button> </div>

The view is passed both the actions and state to then be dispersed throughout the app. The view is then rendered as a virtual DOM.

Last but not least, the app needs to be mounted to the DOM using the app function.

const main = app(state, actions, view, document.body);

app takes the state, actions and views, and attaches it to the last argument which can be any valid DOM node that exists in your index.html.

What's next?

You should now be equipped to continue learning and working with Hyperapp. I highly reccomend reading Hyperapp's code and readme.

I really think that less is more when it comes to developer experience and Hyperapp is a shining example of that philosophy.

Tag cloud