ElmをWindows + Visual Studio Codeの環境で開発していて便利だったことまとめ

## 概要
ElmでWebページを作ってみて便利だったもののまとめ。

* [作成したページ：惨劇RoopeRオンラインツール](https://rooper-tool.web.app/rooper/)
* [ソース](https://github.com/hibohiboo/rooper-elm)

## 環境

### バージョン

- Windows 10 Home
- Vagrant 2.2.6
- virtualbox 6.0.14
- Ubuntu 18.04 LTS (Bionic Beaver)
- Docker version 19.03.2, build 6a30dfc
- docker-compose version 1.24.1, build 4667896b


## Elm用のVSCode設定

### Elm用の拡張機能をインストール
* `elmtooling.elm-ls-vscode`を使用。一番上に出てくる、elmのマークの`sbrink.elm`はdeprecatedになってた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/05bb1520-cb12-5774-1bf2-dcc4081d9e81.png)


### 拡張機能のために、elmをグローバルインストール

* 手軽に使い始めたかったので。

```
$npm install -g elm elm-format elm-test
$npm ls -g --depth=0
+-- elm@0.19.1-3
+-- elm-format@0.8.2
+-- elm-test@0.19.1
```

* 設定でelmPathを指定したあげればローカルインストールでもできるぽい。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/adcb4464-a08f-ab4f-efb2-1567c526f16a.png)

## VSCodeのショートカット

### 指定行移動 [Ctrl + G]

* elmはコンパイラがエラーの行数を出してくれるので、非常によく使った
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/592187d5-fa1e-5fcf-7a37-52922f1099cb.png)

### 指定シンボルに移動 [Ctrl+Shift+O]

* Elmのコードって縦に長くなるので。。特にMsgに移動するのによく使った気がする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/f028db04-5242-c0fe-fcb5-89995d4b6259.png)


### シンボルをリネーム (直したい名前の上にカーソルがある状態で[F2]）
* 登場箇所を一括で直してくれる。置換よりも便利。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99876/6b9fb06c-d5a1-92a2-0b12-d4654a109082.png)

## Elmの追加パッケージ

```bash
$elm install elm-community/html-extra
$elm install elm-community/list-extra
$elm install elm-community/maybe-extra
$elm install elm-community/json-extra
$elm install NoRedInk/elm-json-decode-pipeline
```

### elm-community/html-extra

* [doc](https://package.elm-lang.org/packages/elm-community/html-extra/latest/Html-Events-Extra#onChange)
* `onChange`用を使いたかった。
  * inputタグでも、`onInput`だと、iphoneで入力に不具合が起きたので`onChange`のほうがよい。。。

```elm
import Html.Events.Extra exposing (onChange)
import Html.Extra as ExHtml

select : String -> (String -> msg) -> String -> List ( String, String ) -> Html msg
select nodeKeySuffix chgMsg selectedKey rs =
    Keyed.node "select"
        [ onChange chgMsg ]
    <|
        List.indexedMap (\i r -> keyedOption i nodeKeySuffix r selectedKey) rs
```

* [doc](https://package.elm-lang.org/packages/elm-community/html-extra/latest/Html-Extra#nothing)
* あとは`nothing`なんかも。`text ""`より、こっちのほうが明示的で好き。

```elm
mastermindSheets : Model -> Html msg
mastermindSheets model =
    section [ class "section" ]
        [ case model.room of
            Just room ->
                Script.scriptView room.script

            Nothing ->
                ExHtml.nothing
        ]
```

### elm-community/list-extra

* [doc](https://package.elm-lang.org/packages/elm-community/list-extra/latest/List-Extra#remove)
* 色々便利そうなの揃ってる
  * 今回は、removeを使いたかった。

```elm
import List.Extra as ExList


exceptList : List a -> List a -> List a
exceptList list target =
    exceptListHelp list target


exceptListHelp : List a -> List a -> List a
exceptListHelp remaining accumulator =
    case remaining of
        [] ->
            accumulator

        first :: rest ->
            exceptListHelp rest (ExList.remove first accumulator)
```


### elm-community/maybe-extra

* [docs](https://package.elm-lang.org/packages/elm-community/maybe-extra/latest/Maybe-Extra)
* `ExMaybe.values`が便利だった。
  * 例えば、`[Just 1, Nothing, Just 2]` を `[1,2]`に変換できる。
* `ExMaybe.isJust`も便利に使った。

```elm 
import Maybe.Extra as ExMaybe


getSelectedBoardComponentTypeAll : List Hand -> List BoardType
getSelectedBoardComponentTypeAll list =
    list
        |> List.map
            (\h ->
                case h.onComponent of
                    Just (BoardComponentType t) ->
                        Just t

                    _ ->
                        Nothing
            )
        |> ExMaybe.values

```

### elm-community/json-extra

* [docs](https://package.elm-lang.org/packages/elm-community/json-extra/2.7.0/Json-Encode-Extra)
* Maybe型のエンコードってどうやってやるんだっけ？？と。

```elm
import Json.Encode as E
import Json.Encode.Extra as ExEncode

encode : Hand -> E.Value
encode { id, formId, handType, onComponent, isUsed } =
    E.object
        [ ( "id", E.string id )
        , ( "formId", E.int formId )
        , ( "handType", E.string <| typeToString handType )
        , ( "onComponent", ExEncode.maybe (E.string << componentTypeToString) onComponent )
        , ( "isUsed", ExEncode.maybe E.bool isUsed )
        ]
```

### NoRedInk/elm-json-decode-pipeline

* [docs](https://package.elm-lang.org/packages/NoRedInk/elm-json-decode-pipeline/latest)
* デフォルトのデコーダより見やすいなーと。

```elm
import Json.Decode as D
import Json.Decode.Pipeline as Pipeline

type ComponentType
    = CharacterComponentType CharacterType
    | BoardComponentType BoardType


type alias Hand =
    { id : String
    , formId : Int -- 選択された手札の番号
    , handType : HandType
    , onComponent : Maybe ComponentType
    , isUsed : Maybe Bool
    }

decoder : D.Decoder Hand
decoder =
    D.succeed Hand
        |> Pipeline.required "id" D.string
        |> Pipeline.required "formId" D.int
        |> Pipeline.required "handType" (D.map (typeFromString >> Maybe.withDefault ParanoiaPlus1) D.string)
        |> Pipeline.optional "onComponent" (D.map componentTypeFromString D.string) Nothing
        |> Pipeline.optional "isUsed" (D.maybe D.bool) Nothing
```
### パッケージ検索

* [Elm Search](http://klaftertief.github.io/elm-search/)
  * 欲しい関数の型を指定して検索できる

## Vagrant上でのテスト時の注意

* WindowsのVagrant上でテストを動かしているために発生する
* 直接動かしている人ならおそらく不要
* `--watch`オプションをつけても、そのままでは動かない。
  * `chokidar`にpollingしてやる設定を行う必要がある。

```docker:Dockerfile
RUN yarn add --dev elm-test
RUN sed -i -e "s/\(cwd: projectRootDir,\)/\1\n    usePolling: true, /g" /app/node_modules/elm-test/lib/elm-test.js
```

```bash 
cd $docker_dir && docker-compose -f $composeFile run $container_name yarn run elm-test --watch
```


## 参考

[【Windows版】VS Code キーボードショートカット一覧 （オススメ付き）](https://qiita.com/TakahiRoyte/items/cdab6fca64da386a690b)
[Elmのライブラリの探し方](https://qiita.com/miyamo_madoka/items/e8ea0396ce2b12a136e7)