Hyperappを試してみた。
Hyperappとは?
1Kという常識を覆すほどの超軽量のJavascriptフレームワーク Reactからいらないものを極限まで削ぎ落とした感じ。 驚くことにみんな大好きQiitaで採用されているとのこと。
ここら辺に作成者さんの思想などが詰まっているのだけれども、一言で羨ましい。 これを作れる技術力も、コミュニティの温かさも、設計思想も。 OSSとしてこういうものを作れるエンジニアになりたいよね。
他、紹介記事はここら辺。
ReactやVueなどのフレームワークは個人で何かを作るとなった際には、正直大きすぎるので 速度重視の場合にはこういうものを使いたいよねということで今回目をつけました。あとは新しい物好きの興味本位。
Setup
超絶怒涛のウルトラスーパー簡単セットアップ。
<script> import {h, app} from "https://unpkg.com/hyperapp?module" </script>
View
JSX的な書き方が使える。Hyperappからimportしたh
という
関数がComponentに対応している感じ。ほぼほぼhtmlの書き心地と同じである。
<!doctype html> <html> <head> <link rel="stylesheet" href="https://zaceno.github.com/hatut/style.css"> <script type="module"> // -- IMPORTS -- import {h, app} from "https://unpkg.com/hyperapp?module" // -- ACTIONS -- // -- VIEWS --- // -- RUN -- app({ node: document.getElementById("app"), view: () => h("div", {id: "app", class: "container"}, [ h("div", {class: "filter"}, [ " Filter: ", h("span", {class: "filter-word"}, "ocean"), h("button", {}, "\u270E") ]), h("div", {class: "stories"}, [ h("ul", {}, [ h("li", {class: "unread"}, [ h("p", {class: "title"}, [ "The ", h("em", {}, "Ocean"), " is Sinking!" ]), h("p", {class: "author"}, "Kat Stropher") ]), h("li", {class: "reading"}, [ h("p", {class: "title"}, [ h("em", {}, "Ocean"), " life is brutal" ]), h("p", {class: "author"}, "Surphy McBrah"), ]), h("li", {}, [ h("p", {class: "title"}, [ "Family friendly fun at the ", h("em", {}, "ocean"), " exhibit" ]), h("p", {class: "author"}, "Guy Prosales") ]) ]) ]), h("div", {class: "story"}, [ h("h1", {}, "Ocean life is brutal"), h("p", {}, ` Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. `), h("p", {class: "signature"}, "Surphy McBrah") ]), h("div", {class: "autoupdate"}, [ "Auto update: ", h("input", {type: "checkbox"}) ]) ]), }) </script> </head> <body> <div id="app"></div> </body> </html>
State
素晴らしいのが状態管理システムを持つところ。 初期状態を定義してviewに引数として渡してやると、利用できるようになる。 更新箇所はReactのように限定はできないようだが、小さいApplicationでは全然気にはならない。
app({ node: document.getElementById("app"), init: { filter: "ocean", reading: "113", stories: { "112": { title: "The Ocean is Sinking", author: "Kat Stropher", seen: false, }, "113": { title: "Ocean life is brutal", author: "Surphy McBrah", seen: true, }, "114": { title: "Family friendly fun at the ocean exhibit", author: "Guy Prosales", seen: true, }, view: state => ... });
Action
actionもお手の物。Reactとほぼほぼ同じである。 任意の値を引数として渡す場合には、関数を渡している箇所を配列に変更して 追加でpayloadとして渡してやればいいだけ。ものすごくシンプルである。
const StartEditingFilter = state => ({...state, editingFilter: true}) const Filter = state => h("div", {class: "filter"}, [ "Filter:", h("span", {class: "filter-word"}, state.editingFilter), h("button", { onClick: StartEditingFilter }, "\u270E") ])
Effect
APIとの通信関連の箇所の様子。Http通信後に帰ってきた値をpayloadとして引数のactionを 実行する。本当にReactとかの必要な機構をミニマムでとってきた感がする。 これらの仕組みを1Kになってるのがすげえよなぁ...
import {Http} from "https:/unpkg.com/hyperapp-fx@next?module" const StopEditingFilter = state => [ { ...state, editingFilter: false, }, Http({ // <--- url: `https://zaceno.github.io/hatut/data/${state.filter.toLowerCase()}.json`, // <--- response: "json", // <--- action: GotStories, // <--- }) ]
初期stateとしても使えるみたい。
init: FetchStories({ editingFilter: false, autoUpdate: false, filter: "ocean", reading: null, stories: {}, }),
まとめ
フロントを作る際に必要な箇所を詰め込んだフレームワークという印象。 複雑なものを作る際にはもっと色々と必要になるが、個人プロジェクトなどを作る際は全然使えそう。 学習コストなども非常に低そうなので、色々と小回りが効きそうなフレームワーク 。 何より小さい。すごい。
今年はOSSに貢献することを目標にしているので、こういうところからはじめられたらいいなと。