わたしのかんがえるさいきょうの開発環境（PureScript + Halogen）

趣味で PureScript + Halogen を使って SPA を作っています[^1]。

[^1]: GitHub Pages で公開しています。 https://amderbar.github.io/mkpasswdpwa/

これの開発のために構築した開発環境が結構快適に思われるので公開してみることにしました。

# TL; DR

PureScript + Halogen を使って SPA を開発環境として、自動ビルド + ホットリロードをシンプルな設定で構築できたので広めたい。

# OSなど

私の普段使いのマシンは Windows 10 のデスクトップです。

* WSL （Ubuntu 18.04.4）
* Node.js v12.18.x（nvm 経由）

WSL が便利ですよね。WSL 2 はやく使えるようにならないかな…。

PureScript 自体のインストールは npm で行い、ビルドなども npm スクリプトを使いますので Node.js が必要です。Node.js そのものをがっつり使うわけではないので LTS をインストールしています。Node.js のバージョン管理ツールはいろいろあるみたいですが、WSL だしオーソドックスに nvm で。気づいたときに最新版にあげます。

なお、Node.js が使えればいいので Mac や Linux を使っていても問題ないです。

# エディタ

* VS Code

ここはお気に入りのものを使えばいいですが、IDE になってくれるほうがやはりはかどります。VS Code は下にあげたプラグインで PureScript の IDE として使えます。

## 拡張機能

* [Remote - WSL](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl)
* [PureScript IDE](https://marketplace.visualstudio.com/items?itemName=nwolverson.ide-purescript)
* [PureScript Language Support](https://marketplace.visualstudio.com/items?itemName=nwolverson.language-purescript)
* [vscode-purty](https://marketplace.visualstudio.com/items?itemName=mvakula.vscode-purty)

Remote - WSL で VS Code から WSL につないでいます。これだけ Local にインストールしていて、他の拡張機能はすべて WSL にインストールしてあります。

PureScript IDE と PureScript Language Support をインストールしておけば、色分けや補完は効くようになります。

加えて vscode-purty をインストールしておけば、`Shift+Alt+F`でコードの自動整形できます。
ただ後述するように npm パッケージのインストールも必要です。

# プロジェクト設定

ディレクトリ構成はおおむね以下のような感じにしています（自動生成されるディレクトリは除く）。

```
project-dir/
├─ .github/
├─ .gitignore
├─ dist/
│  ├─ css/
│  ├─ index.html
|  └─ js/
├─ LICENSE
├─ package-lock.json
├─ package.json
├─ packages.dhall
├─ spago.dhall
├─ README.md
├─ src/
└─ test/
```

npm を使った Node.js のプロジェクトとしては特に変わったところはないかなと。

packages.dhall と spago.dhall は PureScript のビルドツールに spago を使う場合は自動で作られるファイルで、package.json と似たような役割のファイルです。

src ディレクトリにアプリのソースコードを入れて、test ディレクトリにテストコードを入れます。

GitHub Actions を使う場合は .github/ ディレクトリに設定ファイルを入れておきましょう。

package.json の中身は以下のようにします。

```json:package.json
{
  (省略)
  "private": true,
  "scripts": {
    "build": "spago bundle-app --to dist/js/app.js",
    "watch": "spago bundle-app --watch --to dist/js/app.js",
    "serve": "live-server --no-browser dist",
    "test": "spago test"
  },
  "devDependencies": {
    "live-server": "^x.x.x",
    "purescript": "^x.x.x",
    "purty": "^x.x.x",
    "spago": "^x.x.x"
  }
}
```

まずは依存パッケージについて。

`purescript`は言わずもがなとして、ビルドツールとして`spago`をインストールします。[Pursuit](https://pursuit.purescript.org) にパッケージを公開する場合は pulp と bower が必要っぽい（？）ですが、アプリケーションを作るなら spago を選ぶといいでしょう。

`purty`は先述のコードフォーマッタ vscode-purty に必要なパッケージです。これを入れておかないとフォーマットされません。vscode-purty の設定上デフォルトではその時開いているディレクトリの node_modules 下を探しに行きますので、devDependencies に入れておけば特に設定不要で使えるようになります。もちろんグローバルインストールして vscode-purty の設定を変えておくのでもOKです。

そして`live-server`ですが、これが今回の設定の肝といえるでしょう。spago はとても使い勝手のいいツールですが、開発用サーバー機能は備えていないようです[^2]。そこでこれを補完し、ホットリロードを実現するために live-server を組み合わせます。

[^2]: PureScript 自体がフロントエンド特化というわけではないので当たり前かとは思いますが、なぜか pulp にはついているんだよなぁ…。

`spago bundle-app`が PureScript のソースコードをコンパイルしてブラウザで読み込み可能な js ファイルを生成するコマンドです。これに`--watch`オプションを付け加えることでソースの保存時に自動的にビルドを実行してくれるようになります。ただ、spago が面倒を見てくれるのはここまでです。それ以降は live-server が js ファイルが出力されるディレクトリを含む公開用ディレクトリを監視し、js ファイルその他が変更されるとブラウザをリロードします。

上の npm スクリプトは以上の目的を実現するようなものとなっています。

## 構築手順

上記のような開発環境を作るための手順は以下の通りです。

## 1. ディレクトリ作成と依存関係インストール

```shell-session
mkdir project-dir && cd ptoject-dir
npm init
npm install -D purescript spago purty live-server
npx spago init
npx spago install
mkdir -p dist/js
```

## 2. ファイルの作成、編集

1. package.json のスクリプトを書く
    - `build`、`watch`、`serve`、`test`の4つ。前3つは好きな名前でOK
2. index.html を作る
3. .gitignore にビルド生成物を追加する
    - `build`で作られる js ファイルを無視する設定
    - 上の例でいうと`/dist/js/app.js`を無視する

# 開発中の使い方

実際にコードを書いているときは、バックグラウンドで以下の二つのコマンドを常に実行しておきます。

* `npm run watch`
* `npm run serve`

こうすることで PureScript のソースコードを編集して保存すれば自動的にビルドが走り、結果として生成された js ファイルの変更を検知してブラウザが自動でリロードされる仕組みです。

VS Code を使用していれば、Explorer ビューから NPM SCRIPTS をクリックで実行できますのでらくちんです。

`npm run watch`を実行しているコンソールが見えるようにしておけば、コンパイルエラーを見て修正をすることもできます。

# 課題とか

こうやって作った開発環境はおおむね快適に使えますが、課題もあります。

## `spago install`に失敗する問題

PureScript のパッケージが必要になって、`spago install`をすることがありますが、これが下のようなエラーメッセージを出してこけることが多々あります。

```shell-session
$ npx spago install
[info] Installing XX dependencies.
[info] Searching for packages cache metadata..
[info] Unable to find packages cache metadata, downloading from GitHub..
[info] ・・・
（省略）
[error] Installation failed
[error] Error:
[error] .spago/__download-xxx-vx.x.x-xxxxxxxxxx/download: rename: permission denied (Permission denied)
```

.spago ディレクトリの所有者を確認してもコマンドの実行ユーザになっており、権限も`777`。また ~/.cache/spago というディレクトリがグローバルキャッシュとしてありますが、これも`777`。全くの謎現象です。ただこれが起こると何度繰り返しても同じで、インストールできません。

起こりやすい条件として、以下のものがありそうです。

* VS Code から WSL ターミナルを使っている
* `npm run watch`を使っている（？）

二つ目については、開発中は大体いつも使っているので、関連性はちょっとよくわかりませんが…。

### 解決策

根本的な解決策は分かっていません。ただ、いったん VS Code を終了した後で WSL のターミナルを開き、そこでインストールコマンドを実行すればうまくいきます。

PureScript ではなく Go 言語での開発時のお話ですが、「[WSL&VScode&Go=permission denied](https://qiita.com/icy_mountain/items/50287a5cd05f4e03a1bf)」という記事もあり、どうも WSL を VS Code から使った時に何か問題があるんだなという感じです。