Home

Awesome

Real Word Example App in Hyperapp v2

Design decisions

Zero-dependency micro libraries

For production dependencies prefer tiny zero-dependency libraries because:

Examples (minified+gzipped):

Development without tooling

Point your static web server to your src directory and you're ready to go. Startup time in milliseconds. No bundler, no transpiler, no file watcher needed. Just your web server, static files and a refresh button. View-source driven development in its finest form.

Common obstacles:

Functional thinking over OO thinking

Most important functional concepts in our codebase (by convention since language can't make those guarantees):

I find it easier to reason about and refactor functional code.

Minimal logic in view functions

Additionally this project uses functions with explicit input parameters destructuring. Tradeoff: more boilerplate but no magic.

Navigation pattern

We're doing client-side routing to be compliant with the RealWorld app spec. Personally I'd prefer server-side navigation between pages (less client side code, already implemented by the browser, no back-button amnesia etc.).

This app's navigation flow:

Ability to trigger action that sets immediate initial state removes unnecessary null checks in the view code.

Business centric code organization

Main application pages are split into individual files (pages/article.js, pages/editor.js etc.) with shared fragments extracted into a separate directory (pages/fragments).

Inside each page file we have the following structure:

// Actions & Effects
// ------------------
// actions and effects specific to a page
// export loadPage action for a page

// Views
// ------------------
// view fragments specific to a page
// selectors used by view fragments
// export main view function for a page

Since views and actions change together we keep them together (common closure principle). I find it easier to refactor code this way.

Also when we need to delete a business feature it's just a matter of deleting one file.

Finally, I prefer to keep folders relatively flat as too much nesting makes it hard for me to find things.

Keeping language features to a minimum

Hyperapp makes it easy to use the small subset of standard JS while skipping the bad parts and nonstandard extensions.

Things I don't use and what is used instead:

Build tools as a production optimisation step

esbuild is used to create ES6 minified/tree-shaken bundle (even faster load time).

Raw source size: < 1300 LOC (60% of the Hyperapp v1 version)

Minified+gzipped bundle: 13.8kB (used to be 28.5kB in v1)

Lighthouse score: 98 (with CSS being a constraint)

It makes it one of the smallest and fastest to load versions of RealWorld app.

When comparing different implementations remember that:

No code splitting

I've run some experiments with this codebase and code splitting per route/page brings only minor improvements over single bundle when visiting a home page. Single bundle minifies/gzips more efficiently so we ship fewer bytes overall when we navigate to other pages.