🍎

【PureScript】Halogen を導入して、サンプルコードのカウンターアプリを試してみる。

2021/09/20に公開

前回の記事の続きです。

https://zenn.dev/purenium/articles/587febd192d7fd

概要

前回作成した、PureScript 環境に、PureScript の UI ライブラリである Halogen を導入します。
それから、Halogen 公式のサンプルコード(カウンターアプリ)が動作するところまで確認します。

Halogen について

Halogen とは何かについて、説明いたします。
Halogen とは、一言で言いますと、React のような、フロントエンドの User Interface を制作するライブラリです。
React は JavaScript や TypeScript で制作しますが、Halogen は PureScript で制作します。
メリットとして、PureScript の強力な型システムを利用し、型安全な開発を行うことができるなるなどがあります。

以下、公式から引用します。

Halogen は PureScript で User Interface を制作する型安全なライブラリーです。

宣言型
アプリケーションの状態ごとに、シンプルなView を記述します。
すると、Halogen は、効果的かつ聡明に、componentをアップデートし、あなたが記述したInterface を再レンダーします。

コンポーネント設計
自身の状態を管理するカプセル化されたコンポーネントを書き、それらを組み合わせて複雑なユーザー インターフェースを構築することができます。
また、単一のコンポーネントを使って、Elmのようなアーキテクチャを実装することもできます。

PureScript純一のライブラリ
Halogen とその仮想DOM実装はPureScriptで書かれています。Halogen のパフォーマンスやバンドルサイズは、ReactやAngularといった一般的なJavaScriptのUIライブラリとほぼ同等です。

(原文)

Halogen is a type-safe library for building user interfaces in PureScript.

  • Declarative Write simple views for each state in your application, and Halogen will efficiently and intelligently update the right components and re-render your user interface.
  • Component Architecture Write encapsulated components which manage their own state, and compose them together to build complex user interfaces. Or, use a single component to implement an Elm-like architecture.
  • Entirely PureScript Halogen and its virtual DOM implementation are written in PureScript. Halogen's performance and bundle sizes are roughly equivalent to popular JavaScript UI libraries like React and Angular.

引用元:
https://github.com/purescript-halogen/purescript-halogen

カウンターアプリのサンプルコードを試す。

今回制作する、プロジェクトは、最終的に以下のようなディレクトリ構成になります。

├── index.html
├── index.js
├── output
├── packages.dhall
├── spago.dhall
├── src
│   └── Main.purs
└── test
    └── Main.purs

PureScript Halogen をインストールします。

spago install halogen

まず、ルートに、PureScript から生成した JavaScript を読み込む HTML ファイル(index.html)を用意します。
以下は例です。

index.html
<!DOCTYPE html>
<html>

  <head>
    <meta charset="UTF-8">
    <title>PureScript Halogen Counter App</title>
  </head>

  <body>
    <script src="./index.js"></script>
  </body>

</html>

次に、こちらの Halogen Guide のサンプルコードを src/Main.purs に Copy & Paste します。

https://github.com/purescript-halogen/purescript-halogen/tree/master/docs/guide

src/Main.purs
module Main where

import Prelude

import Effect (Effect)
import Halogen as H
import Halogen.Aff as HA
import Halogen.HTML as HH
import Halogen.HTML.Events as HE
import Halogen.VDom.Driver (runUI)

main :: Effect Unit
main = HA.runHalogenAff do
  body <- HA.awaitBody
  runUI component unit body

data Action = Increment | Decrement

component =
  H.mkComponent
    { initialState
    , render
    , eval: H.mkEval $ H.defaultEval { handleAction = handleAction }
    }
  where
  initialState _ = 0

  render state =
    HH.div_
      [ HH.button [ HE.onClick \_ -> Decrement ] [ HH.text "-" ]
      , HH.div_ [ HH.text $ show state ]
      , HH.button [ HE.onClick \_ -> Increment ] [ HH.text "+" ]
      ]

  handleAction = case _ of
    Increment -> H.modify_ \state -> state + 1
    Decrement -> H.modify_ \state -> state - 1

spago bundle-app を実行し、PureScript から、index.js を生成します。

❯ spago bundle-app
[info] Build succeeded.
[info] Bundle succeeded and output file to index.js

すると、ルートに、index.js が、生成され、上記に記載したディレクトリ構成になります。

index.html をブラウザで見てみます。

すると、React のサンプルであるようなカウンターアプリが動いていることを確認できました。
(+ボタンを押すと数字が1増える。-ボタンを押すと数字が1減る。)


続いて、Main.purs で、増減する数字を100に変更してみます。
(spago bundle-app で JS を更新します。)

src/Main.purs
  handleAction = case _ of
-    Increment -> H.modify_ \state -> state + 1
+    Increment -> H.modify_ \state -> state + 100
-    Decrement -> H.modify_ \state -> state - 1
+    Increment -> H.modify_ \state -> state + 100

増減する値が100ずつに変わりました。

Halogen を導入し、簡単なカウンターアプリの動作確認をすることができました。

今回はサンプルコードの説明などを省略いたしました。
また、このカウンターアプリ自体、非常に単純なものとなります。

今後の私の課題としては、より深く PureScript、そして、Halogen に対しての理解を深め複雑なアプリケーションを作ることです。

以上です。

その他参考文献

PureScript Getting-Started
https://github.com/purescript/documentation/blob/master/guides/Getting-Started.md

Discussion