PureScript の環境構築

PureScript の環境が無いので Recommended tooling for PureScript applications in 2019 を参考に作っていこうと思います。

まとめ

λ brew install yarn  
λ mkdir my-project && cd my-project  
λ yarn add --dev purescript spago parcel-bundler  

λ yarn spago init  
λ yarn spago run  

λ yarn spago install halogen  
λ yarn add marked  

λ mkdir dist  
λ yarn spago bundle-app --main Main --to dist/app.js  
λ mkdir assets && touch assets/index.html  
# index.html を編集  
λ yarn parcel build assets/index.html  

ツールについて

2019年に PureScript を始めるなら以下のツールが良いそうです。

yarn

これは良く使うやつですね。僕も最初は npm を使っていましたが、途中でyarnに切り替えました。

どうやら、

  • PureScript コンパイラ
  • JavaScript のライブラリ

をインストールする際に使うようです。

λ brew install yarn  
λ yarn --version  
1.19.1  

spago

スパゴ?(IPA: /spao/)
の絵文字から、スパゲッティっぽい感じは伝わってきます。

このツールでは

  • PureScript のパッケージマネージャ
    • PureScript のライブラリのインストール
  • PureScript プロジェクトのビルド, ドキュメントの生成など

ができるらしいです。つまり cabalstack みたいなやつですかね。

リポジトリを見ると Haskell で書かれてる!(何かあったらコード直せますね)

webpack, parcel

あんまり詳しく無いけど webpack は使ったことある。parcel は名前だけ。
ツリーシェイキングやモジュールバンドラーのために使うってことですね。

プロジェクトの作成

とりあえずサンプルプロジェクトを作ります。

λ mkdir my-project && cd my-project  

ツールのインストール

参考にしているドキュメントでは spagoparcel-bundler はローカルインストールしているので、同じようにします。ちなみに spago の公式ドキュメントではグローバルインストールが推奨されています。

λ yarn add --dev purescript spago parcel-bundler  

--dev を指定しているため package.jsondevDependencies に追加されます。この段階で生成されるディレクトリと

λ tree -L 1 .  
.  
├── node_modules  
├── package.json  
└── yarn.lock  

1 directory, 2 files  

package.json の中身はこんな感じ。

{  
  "devDependencies": {  
    "parcel-bundler": "^1.12.4",  
    "purescript": "^0.13.4",  
    "spago": "^0.10.0"  
  }  
}  

ローカルインストールなのでインストールした spago コマンドは yarn spago のように呼び出す必要があります。

λ spago version  
fish: Unknown command spago  

λ yarn spago version  
yarn run v1.19.1  
warning package.json: No license field  
$ /Users/gupi/Desktop/my-project/node_modules/.bin/spago version  
0.10.0.0  
  Done in 0.11s.  

プロジェクトの雛形作成

yarn spago init コマンドでプロジェクトを開始します。(cabal init と同じですね)

λ yarn spago init  
...  

λ tree -I "node_modules" .  
.  
├── package.json  
├── packages.dhall  
├── spago.dhall  
├── src  
│ └── Main.purs  
├── test  
│ └── Main.purs  
└── yarn.lock  

新たに作られたものは

  • packages.dhall
  • spago.dhall
  • src/Main.purs
  • test/Main.purs

の4つです。PureScriptの拡張子ってpursなんですね。

何でpsじゃないのかなと思ったんですが、Use a different file extension #45の通りPostScriptと被るのでpurescriptpursが候補となってたみたいです。納得の理由です。

ここで普通の人は見慣れない拡張子 dhall に戸惑うかもしれませんが、Haskeller ならたぶん見たことある。
まだ何も知らないですが、たぶん spago のパッケージ管理の設定言語に dhall を採用したってことですね。

公式ドキュメントによると

ファイル名 役割
packages.dhall プロジェクト内で利用可能な全パッケージの情報を含む
spago.dhall プロジェクトの設定を記述

という感じで2つのファイルを使い分けるようです。

packages.dhall

packages.dhall のコメントを削除した中身はこんな感じになってます。

let upstream =  
      https://github.com/purescript/package-sets/releases/download/psc-0.13.4-20191025/packages.dhall sha256:f9eb600e5c2a439c3ac9543b1f36590696342baedab2d54ae0aa03c9447ce7d4  

let overrides = {=}  
let additions = {=}  
in  upstream // overrides // additions  

正直 dhallは使ったことが無いので記法は良くわかりませんが、upstreamに指定している部分が重要っぽいですね。たぶんstackのスナップショットみたいなやつで、package set と呼ぶみたいです。
公式のパッケージセットはpurescript/package-setsリポジトリで管理してるみたいです。

役割的には stack でいうところの stack.yamlresolverextra-deps に近いのかなぁ。

spago.dhall

コメントを削除したspago.dhallファイルの中身はこんな感じです。

{ name =  
    "my-project"  
, dependencies =  
    [ "effect", "console", "psci-support" ]  
, packages =  
    ./packages.dhall  
, sources =  
    [ "src/**/*.purs", "test/**/*.purs" ]  
}  

このファイルはHaskellプロジェクトで言うところのcabalファイルや package.yaml ファイルに近いかもしれないですね。

設定項目
name プロジェクト名
dependencies プロジェクトの依存関係
packages パッケージセット
sources ビルド対象ファイルの指定

ビルド&実行

cabal runstack run のように spago run でプロジェクトのビルド&実行が可能です。

module Main where  

import Prelude  

import Effect (Effect)  
import Effect.Console (log)  

main :: Effect Unit  
main = do  
  log ""  

上記のコードを実行するとが表示されました。

λ yarn spago run  
...  
Build succeeded.  

依存関係のインストール

PureScriptJavaScriptでコマンドが違うので注意。

作業する前のspago.dhallは以下の通り。

{ name =  
    "my-project"  
, dependencies =  
    [ "console", "effect", "halogen", "psci-support" ]  
, packages =  
    ./packages.dhall  
, sources =  
    [ "src/**/*.purs", "test/**/*.purs" ]  
}  

作業する前のpackage.jsonは以下の通り。

{  
  "devDependencies": {  
    "parcel-bundler": "^1.12.4",  
    "purescript": "^0.13.4",  
    "spago": "^0.10.0"  
  }  
}  

PureScript ライブラリのインストール

yarn spago install <pkg> という形でインストールできる。

ここでは例として halogen をインストールしてみる。

λ yarn spago install halogen  

コマンドを実行するとライブラリがインストールされ、spago.dhalldependencieshalogenが追加される。

λ cat spago.dhall  
{ name =  
    "my-project"  
, dependencies =  
    [ "console", "effect", "halogen", "psci-support" ]  
, packages =  
    ./packages.dhall  
, sources =  
    [ "src/**/*.purs", "test/**/*.purs" ]  
}  

JavaScript ライブラリのインストール

yarn add <pkg> という形でインストールできる。
ここでは例としてmarkedをインストールする。

λ yarn add marked  

コマンドを実行するとライブラリがインストールされ、package.jsondependenciesmarkedが追加される。

λ cat package.json  
{  
  "devDependencies": {  
    "parcel-bundler": "^1.12.4",  
    "purescript": "^0.13.4",  
    "spago": "^0.10.0"  
  },  
  "dependencies": {  
    "marked": "^0.7.0"  
  }  
}  

バンドル

PureScriptJavaScript に変換する作業です。

λ mkdir dist  
λ yarn spago bundle-app --main Main --to dist/app.js  

これでdis/app.jsにアプリケーションが出力されました。

最後にindex.htmlを作ります。

λ mkdir assets && touch assets/index.html  

index.htmlは以下の内容に書き換えます。

<!DOCTYPE html>  
<html>  
  <body>  
    <div id="app"></div>  
    <script src="../dist/app.js"></script>  
  </body>  
</html>  

最後に以下のコマンドで完成!らしいけど、正直今回の記事では恩恵が良くわからなかった。

λ yarn parcel build assets/index.html  

スクリプト化

package.jsonscripts をこんな感じに定義すれば yarn build, yarn bundle などの短縮形でコマンドを実行できるよっていう紹介。

{  
  "scripts": {  
    "postinstall": "spago install",  
    "build": "spago build",  
    "clean": "rm -rf node_modules output .spago dist/* *.lock",  
    "bundle": "spago bundle-app --main Main --to dist/app.js && parcel build assets/index.html",  
  },  
  "devDependencies": {  
    "parcel-bundler": "^1.12.3",  
    "purescript": "^0.13.3",  
    "spago": "^0.9.0"  
  },  
  "dependencies": {  
    "marked": "^0.7.0"  
  }  
}  

この辺はPureScriptというよりもyarnの使い方の話。

参考リソース