PureScript + psc-package + Halogen + Electronでサンプルを動かす
はじめに
前回の記事ではElm + Electronの組み合わせでサンプルを作成した。
今回はPureScript + Electronの組み合わせでサンプルを作ってみる。
ElmとPureScriptのそれぞれの特徴や比較など。
Elm
関数型JSフレームワークとしてシンプルで分かりやすく関数型の良さをフロントエンドに取り入れたい時に、軽く取り入れることが出来る。初心者でも導入しやすい。
Elm専用パッケージ管理コマンドでパッケージを導入するが、パッケージがそこまで多くはない。が、フロントエンド特化のパッケージなので、基本何でもできる。
Haskellライクな書き方ができるが、Haskellのような特性を活かしたコーディングは出来ない。あくまで純粋関数の特性を活かせるものと思った方が良いかもしれない。
Elmのパッケージhtmlのprogram
を使ってMVUモデルを作っていく感じでコーディングしていく。
Electronとの相性だが、現在パッケージが少なく、Portsという仕組みを使ってnode_modulesへアクセスすることになるため、完全にJavaScriptから抜け出せないため、
若干Electronの相性がまだよくないかもしれない。今後もパッケージが増えていくと思うので、だんだんElectronとの相性もよくなっていくと考える。
仮想DOMを扱っているので、最近のJSフレームワーク同様高速で動き、再描画が優れている。
PureScript
Elmと比べて、Haskellの特性により近づけた関数型JSフレームワーク。
Elmより複雑で難しく初心者には向かない。Haskellの基礎またはElmのいずれかを軽く触ってからPureScriptを触ると入りやすい。
Elmよりもパッケージが豊富でElectronやSqlite3を操作するものがあったりとElectronとの相性が良いと言える。が、パッケージが多すぎて何を使うべきか、分かりづらい。
調べた限り、Domというパッケージがあって簡単にDOM操作出来そうだが、Halogenの方が多機能で仮想DOMを使っているので、難しくてもHalogenを使った方が良い気がする。
加えて、基本はpurescriptにパッケージを追加する際はbowerを使うが今後主流になると思われるpsc-packageを使って実装してみる。
と、いうことで今回は題名の通り、PureScript + psc-package + Electron + Halogenを使ってみる。
環境
mac
electron 2.0.2
node.js 10.0.1
purescript 0.12
psc-package 0.3.2
フォルダ構成
手順
electronとpurescriptのパッケージを導入
npm i -g electron purescript psc-package
electronの初期設定は過去記事を参照
purescriptの初期ファイル生成
pulp --psc-package init
psc-package.jsonのバージョンを以下に揃える
{ "name": "electron-purescript-halogen-sample", "set": "psc-0.12.0", "source": "https://github.com/purescript/package-sets.git", "depends": [ "prelude", "halogen" ] }
※setの箇所は、purescript/package-sets.gitの最新版に書き換えると、install出来るパッケージが増やすことが出来る。
基本パッケージとhalogenパッケージをダウンロードする
psc-package install
srcフォルダのソースコードを以下のソースにおきかえる。
Halogenのサンプルソース使ってソースコードにコメントを挿入している。
ソースコード
Main.purs
module Main where -- 基本コマンドモジュール import Prelude import Effect (Effect) import Halogen.Aff as HA import Halogen.VDom.Driver (runUI) import Button as B main :: Effect Unit -- 非同期処理のHalogenを実行する main = HA.runHalogenAff do -- DOMが読み込まれるのを待ってから、Body要素を取得してセット body <- HA.awaitBody -- bodyに対して、ボタン要素をマウント runUI B.myButton unit body
Button.purs
module Button where -- いつものやつモジュール import Prelude -- 値が入っていないのを許容するモジュール import Data.Maybe (Maybe(..)) -- halogenの基本モジュール import Halogen as H -- halogenのHTML要素モジュール import Halogen.HTML as HH -- halogenのEvent系を取り扱うモジュール import Halogen.HTML.Events as HE -- helogenのプロパティを表現するモジュール import Halogen.HTML.Properties as HP -- ボタンの状態を表す type State = Boolean -- クエリ代数 -- Queryとは、type: -> type:で、常に型変数を持っている data Query a -- アクションのコンストラクタ = Toggle a -- リクエストのコンストラクタ | IsOn (Boolean -> a) -- 親コンポーネントがあった場合に使うが、今回使わないのでUnitを使用する type Input = Unit -- コンポーネントに必要な出力メッセージを定義する。 -- 今回はボタン切替と状態を返す data Message = Toggled Boolean myButton :: forall m. H.Component HH.HTML Query Input Message m myButton = H.component { initialState: const initialState , render , eval , receiver: const Nothing } where initialState :: State initialState = false render :: State -> H.ComponentHTML Query render state = let label = if state then "On" else "Off" in HH.div_ [ HH.text "Hello PureScript トグルボタン" ,HH.div_ [HH.button [ HP.title label , HE.onClick (HE.input_ Toggle) ] [ HH.text label ] ] ] eval :: Query ~> H.ComponentDSL State Query Message m eval = case _ of Toggle next -> do state <- H.get let nextState = not state H.put nextState H.raise $ Toggled nextState pure next IsOn reply -> do state <- H.get pure (reply state)
コンパイルする
pulp build -t output.js
index.htmlが読み込めるように、jsとして出力する。
index.htmlを編集する
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>hello purescript!!</title> </head> <body> <script src="./output.js"></script> </body> </html>
実行する
electron .
ソースコード
ここからダウンロードすれば使えるようになる。詳しくは README参照。 github.com
まとめ
今回は、PureScript + psc-package + Halogen + Electronを使ったサンプルを作ってみたが、Halogenのサンプルが難解で完全に解析出来ていないのが心残りになってしまった。。。
動くものという意味で、公式のサンプルを作ってみたが、アレンジする場合は、Halogenをもっと知る必要があるため、実用的な動きが出来る段階になるまでの学習コストはかなり高い。
またbowerというパッケージ管理コマンドを使わずにpsc-packageでHalogenを扱えるようになったのは大きいと思う。
もう少し自由にコーディング出来るようになった時にまた記事にしたい。