📑
Elmの初期テンプレートファイルを作る elm-initを作った
elm-initって何?
Elmのプロジェクトを書き始めるぞ!というときに使うCLIツールです。どういったアプリケーションを作るかで、ファイルを吐き出し分けることができます。
elm-initは、こちらからお試しできます。
なぜ、このようなツールを使う必要があるのか?
Elmはフレームワークが内蔵されている言語で、用意すべき関数があらかじめ決められています。そして作りたいアプリケーションによって型が厳密に定められています。実際には以下のようなアプリケーションの種類があります。詳しくはBrowserパッケージをご覧ください。
- sandbox — ボタンやチェックボックスのような、ユーザの入力に反応させたいとき
- element — HTTPとJavaScript相互呼び出しのような、外の世界と対話させたいとき
- document — <title> と <body> をコントロールしたいとき
- application — SPAを作りたいとき
開発者はこのアプリケーションの種類から自分の作りたいものに合わせて、main関数中に上記の関数を呼び出し分ける必要がありますが、それに合わせて、view
, update
, subscription
, module
の書き方などが変化します。これを調整するためにいろんなサンプルを見て回ってコピペをするのは苦痛です。そのためにelm-initを作成しました。
どうやって使うの?
helpを呼び出せば、説明が出てきます。
elm-init --help
elm-init 0.0.1
ABAB↑↓BA <@ababupdownba>
elm-init CLI
USAGE:
elm-init [FLAGS] <mode>
FLAGS:
-f, --flags flags option
-h, --help Prints help information
-p, --ports ports option
-V, --version Prints version information
ARGS:
<mode> Elm app mode.
sandbox — react to user input, like buttons and checkboxes
element — talk to the outside world, like HTTP and JS interop
document — control the <title> and <body>
application — create single-page apps
elm-initコマンドを呼び出すとoutput
ディレクトリが出力されます。中には、index.html
とMain.elm
が吐き出されます。
$ elm-init element -f p
$ tree output
output
├── index.html
└── src
└── Main.elm
1 directory, 2 files
中身はこのようなファイルが出力されます。
<html>
<head>
<style>
/* you can style your program here */
</style>
</head>
<body>
<main></main>
<script>
var storedData = localStorage.getItem('echo history');
var flags = storedData ? JSON.parse(storedData) : [];
var app = Elm.Main.init({ node: document.querySelector('main') ,flags: flags })
var socket = new WebSocket('wss://echo.websocket.org');
app.ports.sendMessage.subscribe(function(message) {
flags.push(message);
localStorage.setItem('echo history', JSON.stringify(flags));
socket.send(message);
});
socket.addEventListener("message", function(event) {
app.ports.messageReceiver.send(event.data);
});
</script>
</body>
</html>
port module Main exposing (..)
import Browser
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (..)
port sendMessage : String -> Cmd msg
port messageReceiver : (String -> msg) -> Sub msg
type alias Model =
{ draft : String
, messages : List String
}
init : List String -> ( Model, Cmd Msg )
init flags =
( { draft = "", messages = flags }
, Cmd.none
)
type Msg
= DraftChanged String
| Send
| Recv String
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
DraftChanged draft ->
( { model | draft = draft }
, Cmd.none
)
Send ->
( { model | draft = "" }
, sendMessage model.draft
)
Recv message ->
( { model | messages = model.messages ++ [ message ] }
, Cmd.none
)
subscriptions : Model -> Sub Msg
subscriptions _ =
messageReceiver Recv
view : Model -> Html Msg
view model =
div []
[ h1 [] [ text "Echo Chat" ]
, input
[ type_ "text"
, placeholder "Draft"
, onInput DraftChanged
, value model.draft
]
[]
, button [ onClick Send ] [ text "Send" ]
, ul []
(List.map (\msg -> li [] [ text msg ]) model.messages)
]
main : Program (List String) Model Msg
main =
Browser.element
{ init = init
, view = view
, update = update
, subscriptions = subscriptions
}
おまけ
applicationを選択すると、お茶目です。elm-spaを使うことをおすすめされます。
$ elm-init application
You should use elm-spa( https://www.elm-spa.dev/ ).
まとめ
今回はElmをやる上でいつもちょっと面倒だなあって思う時の便利ツールを作ってみました。よければ使ってみて、要望を出してください。個人的には対話型のアプリにして、もうちょっとフレンドリーなツールにしてみたいです(Rustわからん)。
Discussion