hyperappとは

ReactやVueと同じく、フロントエンド用のビューライブラリ。同じく、と書いたがソースコードのサイズが合計1KBとなっており先に述べたフレームワークと比べかなり軽量・シンプルなつくりになっている。
のでその気になればソースを全て読んで内部の挙動を把握したうえで使うことができる。

詳細については開発者さんが記事を書いているのでそちらを参照。
2018 年は Hyperapp の年だ - Qiita

GitHubはこちら
GitHub - hyperapp/hyperapp: 1 KB JavaScript library for building frontend applications.

またソースコードを解説している記事もあるのでそちらも読んでおくと理解が深まる。
Hyperapp のソースコードを読む

サンプルアプリ

簡単なTODOアプリやカウンターを実装したものが公開されているが
ある程度規模の大きなものをコンポーネントに分けて開発するする場合どんな感じになるのかしら、と思い
その辺を意識してサンプルを作ってみた。

hyperapp.png

作ったのはカウンターとよくあるTODOアプリを無理やりガッチャンコしたもの(見た目も機能もひどい)。
ビルドにはwebpack+babelを使用。GitHubのREADME記載の通り、
transform-react-jsxプラグインを入れてJSX⇒h関数への変換を行う設定を追加した。
component,actionを以下の構成のようにそれっぽく分けて定義した。

App/
 │
 ├ actions/
 │  CounterActions.js
 │  TodoListActions.js
 │
 ├ components/
 │   Counter.js
 │   AddTodo.js
 │   TodoList.js   
 │     
 ├ app.js
 └ index.html

ソース

Todoまわりのソースを抜粋

app.js
import { h, app } from "hyperapp"
import TodoList from "./components/TodoList"
import Counter from "./components/Counter"

import CounterActions from "./actions/CounterActions"
import TodoListActions from "./actions/TodoListActions"


const state = {
 /*コンポーネントごとにstateの階層をつくる*/
  counter: { count: 0 },
  todoList: { todos: [ { id: '1', value: 'Homework', done: false },
                       { id: '2', value: 'Clean the room', done: false } ] 
            }
}

const actions = {
  /*stateと階層を合わせることで同階層のstateを更新するactionを簡単に定義できる*/
  counter: CounterActions,
  todoList: TodoListActions
}


const view = (state, actions) => (
  <div id="main">
    <h1>HyperApp_Sample</h1>
    <Counter state={state.counter} actions={actions.counter} />
    <TodoList state={state.todoList} actions={actions.todoList} />
  </div>
)

app(state, actions, view, document.body)
TodoListActions.js
const actions = {

    toggle: ({ done, id }) => state => {

        return {
            todos: state.todos.map(todo => {

                return {
                    id: todo.id,
                    value: todo.value,
                    done: todo.id === id ? !todo.done : todo.done
                }
            })
        }
    },
    addTodo:(value) => state => {

        return {todos: [...state.todos,{id:state.todos.length,value:value,dane:false}]}

    }
}

export default actions;
TodoList.js
import { h } from "hyperapp"
import AddTodo from "./AddTodo"

export default ({ state, actions }) => {

    return (
        <div id="todo-area" >
            <h2>TODO List</h2>
            <AddTodo state={state} addTodo={actions.addTodo}/>
            <ul>
                {state.todos.map(({ id, value, done }) => {
                    return <li id={id} key={id} className={[done ?"done" :"doing", "todo"].join(' ')} onclick={e => actions.toggle({done,id}) }>{value}</li>
                })}
            </ul>

        </div>

    )

}
AddTodo.js
import { h } from "hyperapp"

export default ({ state, addTodo }) => {

    return (
        <div>
            <input id="todo-val" type="text" />
            <button onclick={e => addTodo(document.querySelector('#todo-val').value)} >ADD TODO</button>
        </div>
    )

}

感想

stateやactionが増えてくるとこんな感じで各モジュールに分割するのかなー、という感じで
やってみたが、これが正解であるかどうかはわからないため、おかしなところがあればぜひ指摘いただきたいです。

今回は使わなかったがReactのようにライフサイクルフックも用意されており、
VDOMを設計の骨子にしてアプリを作るための最低限かつ十分な機能が提供されていると感じた。
ボイラープレートも少なく、基本的にピュアなjsで実装していくことができるので
React,Reduxで心が折れた人にもやさしいライブラリになっているのではないだろうか。
どうやらQiitaもhyperappで作られているらしく1、今後もちゅーもくしていきしたい。