Hyperapp + Parcel = 😎

Adam Boro
Daftcode Blog
Published in
7 min readFeb 5, 2018

--

Simple & nimble frontend duo that kills the JavaScript fatigue

Illustration by Magdalena Tomczyk

In this post, we’ll have a closer look at two new tools in the front-end world. They are both developed with simplicity and ease of use in mind. First one is a tiny frontend framework called Hyperapp, the second is an asset bundler by the name of Parcel. Together they might be the best way to quickly and pleasantly build a decent lightweight webapp, as of the beginning of 2018.

My go-to tools for developing interactive frontends are React & Webpack. But oftentimes the latter proves tedious to set up and the former too big for a simple interaction on a regular website. Like when I just need a little tabbable and searchable widget on a pricing page — throwing in React seems like a bit of an overkill.

Or in the words of Jorge Bucaran, the author of Hyperapp:

I needed to build a web client for a project at work. My first choice was React and Redux […], but I wanted something lightweight and without the frameworkyness of React.

Hyperapp

The main selling point of Hyperapp is its size — about 1kb. Users of React & Redux will feel right at home with Hyperapp, as it’s kind of a tiny React.

Hyperapp is like a tiny Rick version of React

Like React, Hyperapp uses a Virtual DOM to compute necessary DOM updates and follows the familiar Components & Elements abstraction over the HTML elements. You can even use JSX with Hyperapp to make it feel even more homey. The key difference is that the components have no state — there is only one global state per app and all components are stateless.

Hyperapp’s state management is inspired by The Elm Architecture, which was also the main inspiration behind Redux. The concepts of immutable state and actions returning new state objects will be familiar for Redux users. However, there are no reducers, just actions, which take some arguments and return a new state (ok, they can be asynchronous and return promises, but that’s the gist of it).

Recently the v1 was released, so it’s a great time to confidently try it out and build something useful!

Parcel

Parcel is a new kid on the block of front-end assets bundling. Or in other words, a kind of faster and preconfigured webpack. I’m a big fan of webpack, but even so, I have to admit that the setup is a bit tedious. It’s non-opinionatedness makes for a transparent but at the same time a bit bloated configuration.

Parcel boasts a huge speed increase over webpack and other bundlers, as well as such nice-to-haves as hot module replacement and code-splitting, all working out of the box, of course. To my amazement, after linking a .sass file after starting the parcel development server, it automatically installed the node-sass dependency and then transformed the file to CSS! Now that’s some great developer experience. Oh, and it’s really fast.

PS: Webpack team seems to have taken a hint from Parcel and version 4 will include some sensible defaults.

So how do I use it?

We’ll write a simple app using Hyperapp & Parcel — it’ll just fetch and display basic user data using GitHub API. Go ahead and look at the final and annotated code in the repo linked below 👇 or follow along in this paragraph.

The amazing app we’re gonna build:

Let’s start by creating a new directory and installing the necessary dependencies:

mkdir hyperparcel && cd $_ && npm init -y && npm i hyperapp parcel-bundler babel-plugin-transform-react-jsx babel-preset-env

Along with the main protagonists of this little project we’ve installed two babel presets in order to transform the code into something most browsers will understand. Protip: $_ means “the argument to the last command”.

Now go ahead and add index.html and index.js files:

// index.html
<html>
<body>
<script src="./index.js"></script>
</body>
</html>
// index.js
console.log('hello parcel')

Now let’s add parcel development and build scripts to package.json:

...
"start": "parcel index.html",
"build": "parcel build index.html --public-url ./"
...

Then start the development server with $ npm startand visit localhost:1234 in the browser. You should see the console log from index.js! 🎉

Ok, now the Hyperapp part. To make life easier we’ll use ES6 syntax and JSX — using babel compiler. Luckily, it’s already included in Parcel, we just need to give babel a hint that we’ll need the env preset and, more importantly, to compile JSX for Hyperapp, not for React. That is to say, instead of React.createElementfunction, we want h function. Create the following .babelrc file in project root:

{
"presets": ["env"],
"plugins": [
[
"transform-react-jsx",
{
"pragma": "h"
}
]
]
}

At this point, we’re done setting up and can finally get to writing the app. Let’s start with a simple Hyperapp view:

import { h, app } from 'hyperapp'const view = () =>
<div>
hello hyperapp
</div>
app({}, {}, view, document.body)

You should see the results right away, as parcel hot-reloads the app automatically. The code above should be pretty self-explanatory, save for the app function — the first two arguments are state and actions, which we do not use for now, third is obviously the view function, and the last is the DOM element to which we want to render the view (in real life, don’t render to body).

That’s basically all you need to start developing a webapp with Parcel & Hyperapp — pretty easy, right?

Now to the GitHub user fetching part. The first thing we need is some state to store the user input and fetched user data (Hyperapp does not have a concept of component state, there is just the app state):

const state = {
username: '',
userData: null,
}

And then we’re gonna need a way to change that state, right? Borrowing from Elm and Redux, state changes in Hyperapp are functions that receive state (and actions) and return the new state, like so:

const nameChangeAction = (name) => (state, actions) => ({...state, name})

That’s how actions in our app will look like:

const actions = {
updateUsername: (username) => (state, actions) => {
getUserData(username).then(actions.setUserData)
return { username }
},
setUserData: userData => state => ({ userData })
}

As you can see, aside from returning the username, the updateUsername action also perform the side effect of fetching and setting — via another action — the user data.

And of course we need that getUserData function. We’ll hit GitHub API when the user fills the input, but in order to be good Internet citizens, we’ll not do it on every keystroke. Let’s get a debouncer: $ npm i debounce-promise babel-preset-es2015, import it, and create the getUserData function:

const getUserDataFn = username => {
return fetch(`https://api.github.com/users/${username}`)
.then(res => res.json())
}
const getUserData = debounce(getUserDataFn, 700)

Add the stylesheet, import it in the index.js file, and update the view code and the app function arguments:

const view = (state, actions) =>
<main>
<div>Search github users:</div>
<input
type='text'
className='searchInput'
value={state.username}
oninput={e => actions.updateUsername(e.target.value)}
/>
<br/>
<div className='userCard'>
{state.userData ? (
<div>
<img class='userCard__img' src={state.userData.avatar_url} />
<div class='userCard__name'>{state.userData.name}</div>
<div class='userCard__location'>{state.userData.location}</div>
</div>
) : (
<div>👆 search 'em</div>
)}
</div>
</main>
app(state, actions, view, document.body)

That’s it! On filling the input, a request should be made and information displayed in the view.

In Conclusion

Hyperapp and Parcel are great examples of how software tools evolve. There are many ideas and patterns for creating a frontend interactive experience — some prove to be more resilient and useful, while others fade into history very quickly, especially in JavaScript land. The combination of React & Redux became very popular among frontend developers, and so their key ideas can be seen in Hyperapp. Webpack allowed for great flexibility in asset bundling and so there has developed a set of expectations for an asset bundler, which Parcel fulfills and may become the next “standard” tool for the job.

This evolution is also a reason why we should not commit to a single framework or toolset and keep an eye out on what’s being developed — because the worst that can happen to a programmer is stagnation.

If you enjoyed this post, please hit the clap button below 👏👏👏

You can also follow us on Facebook, Twitter and LinkedIn.

--

--