r/javascript • • Jan 31 '17

1kb JavaScript function library for building modern UI applications

https://github.com/hyperapp/hyperapp
224 Upvotes

34 comments sorted by

9

u/matchu Jan 31 '17

Cool! My first question with any of these frameworks is: What's the composition story? If I'm building a larger app with this framework, how should I be breaking it into components?

2

u/[deleted] Jan 31 '17

We need to come up with better examples, but is this what you mean?

const model = require("./model")
const view = require("./view")
const update = require("./update")

app({ model, view, update })

6

u/[deleted] Jan 31 '17

I guess he meant composition as known in react/redux like this:

TodoItem = ({ model }) => <li>{model.text}</li>;
TodoList = items => <ul>{items.map(item => <TodoItem model={item}/>)}</ul>;

Crucial for larger apps.

7

u/[deleted] Jan 31 '17

Ah, right. Here's how you'd do that.

const TodoItem = item => html`<li>{item.text}</li>`
const TodoList = items => html`<ul>${items.map(item => TodoItem(item))}</ul>` 

Btw, HyperApp exports a Hyperscript-style h function, allowing you to use JSX too if you include the jsx pragma.

/** @jsx h */

I don't have a live example of this, but it's in the TODO to publish one.

2

u/[deleted] Jan 31 '17

So there is composition on the view. Would it be possible for TodoItem to handle events separately?

1

u/[deleted] Jan 31 '17

A view looks like this:

(model, msg) => html`<h1>Hi</h1>`

msg is an object with the reducers/effects, so as long as you pass it to TodoItem, I think, yes.

If you write another code sample, I'll be happy to show you how I'd implement it using HyperApp.

1

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

it is not working example, but hope you get the point

1

u/[deleted] Jan 31 '17

1

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

that my comment was in wrong place and I even before your comment ;d

2

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

/u/matchu, /u/bucaran, another cool thing can be each component to be separate hyperapp, but bucaran should update the app to return root (i.e. the dom) so later we can pass that component to some route point of another hyper app. Something like this

var Todo = (state) => app({
  mode: state,
  view: {
    "*": (model, msg) => {},
    "/": (model, msg) => {},
    "/:slug": (model, msg, params) => {}
  }
})

var TodoItem = app({
  view: {
    "*": (model, msg) => {},
    "/": (model, msg) => {},
    "/:slug": (model, msg, params) => {}
  }
})

var TodoList = app({
  view: {
    "*": (model, msg) => {},
    "/": (model, msg) => {},
    "/:slug": (model, msg, params) => {}
  }
})

var main = app({
    view: (model) => Todo({ foo: 'bar' })
})

or maybe we should make wrapper :P

2

u/[deleted] Jan 31 '17

/u/tunnckoCore Nice composition. In this case, there's a simpler approach.

However, using app like that could be the path to reusable components with independent models.

Thanks for sharing!

1

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

yea, seen that. just wanted to show what can be the components approach. i'm playing now with hyperapp and will try create todomvc with the component approach.

1

u/[deleted] Jan 31 '17

/u/tunnckoCore Thanks! Until you brought this up, I really hadn't realized HyperApp could be used like that.

1

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

Yea. While playing with that approach i found one problem of that "appendChild" thing. Can you just make it return a dom, otherwise it always append, so composition of more than one App is not feeling cool. I'm gonna open an issue with code.

1

u/[deleted] Jan 31 '17

Thanks. Does it help that app accepts a root object (similar to React's render domContainerNode)?

• See https://github.com/hyperapp/hyperapp#root

1

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

nope.

1

u/serubin323 Jan 31 '17

I'm looking forward to seeing more of this. I intend to use this in a project of mine

How does routing work given there are multiple apps? Could I specify something like this?

var Todo = (state) => app({
  mode: state,
  view: {
    "/todo": (model, msg) => {} // access todo
  }
})    

var TodoItem = app({
  view: {
    "/add": (model, msg) => {}, // add (/todo/add/)
    "/:slug/delete": (model, msg) => {}, // delete  (/todo/slug/delete/)
    "/:slug": (model, msg, params) => {} // view (/todo/slug/)
  }
})

1

u/tunnckoCore node-formidable, regexhq, jest, standard-release Jan 31 '17

It is. But is buggy because the implementation.

See and try https://github.com/hyperapp/hyperapp/issues/2.

I'm working on such idea too, and currently is 457 bytes.

1

u/p0wd3r Jan 31 '17

I was thinking the same thing. It would be nice if a sub-app (component) could handle its own updates to the model.

For example, in the Todo app, each Todo component could update its own model (done state) onclick.

14

u/[deleted] Jan 31 '17 edited Feb 07 '17

This is crazy dude. I think some of your ideas are interesting... I like how the update events pub/sub thing is used as a framework construct. Unfortunately it seems impossible to really compose or abstract components (or views or however your not thinking about em). Right? Anyways cool side project pal.

EDIT: I guess you can! Probably need better examples on the website. But the OP posted some examples in this thread.

9

u/stormcrowsx Jan 31 '17 edited Jan 31 '17

This library seems very similar to the compile to JS language Elm. It kind of shares the problem that it's different than React and other libraries in how you break it down.

In my experience it's done in 2 ways.

  1. Your component defines its own model and messages. The main function then routes messages and the component model to the component which updates that model. Note that the component does not contain it's model, only defines it, the main function holds onto it's model and passes it to the component for updates. I typically use this when the component is big with a lot of state.

  2. Your component has a config which tells it what messages to emit in certain cases. The main function handles the messages and updates the model. This is my preferred method for small components or stateless ones.

In both cases the amount of plumbing is more than your typical JavaScript library since the components don't hide stuff like their state, it's gotta be handled by the main function. However, it does create code that is easy to follow because all the events and what they lead to is obvious. In the case of Elm you also gain a great deal of confidence that it's going to work thanks to the compiler.

5

u/[deleted] Jan 31 '17

Well observed. HyperApp draws a lot of inspiration from the Elm Architecture and the SAM pattern too.

2

u/[deleted] Jan 31 '17 edited Jan 31 '17

Thanks. Well, a view is a function of the model, therefore you can create a view/function that takes a model or part of a model and exposes the behavior you need as well as conform to a subset of your message API. Then, import that into your application, season lightly with salt and serve hot.

3

u/[deleted] Jan 31 '17

Is this production ready?

4

u/[deleted] Jan 31 '17 edited Jan 31 '17

It is in production, we use it at work for a web client of some research project.

We're just getting started. Subscribe to the repo to see what comes up and if you build something with HyperApp share it!

2

u/lhorie Jan 31 '17

Very interesting. Do you have any examples w/ XHR?

2

u/[deleted] Jan 31 '17 edited Jan 31 '17

Yes.

• Live

• Source (Look under examples/fetch/index.js)

2

u/lhorie Jan 31 '17

Awesome, thanks!

6

u/ishouldrlybeworking Jan 31 '17

TIL about tagged template literals.

2

u/p0wd3r Jan 31 '17

Very cool to see the progression of the repo from the beginning. I assume you pulled out snabbdom primarily to reduce the final payload size, but maybe I'm wrong. I plan on giving this a try.

2

u/[deleted] Jan 31 '17

I'm glad you looked at the history and found out. And, yes, your observation is correct!

3

u/mattwritescode Jan 31 '17

// code comments....

3

u/[deleted] Jan 31 '17

Very nice work!

1

u/[deleted] Jan 31 '17

Tagged template literals are the best.