はじめに
私はブラウザ上で動く簡単なアプリを作る際にelm
を用いることが多い。
elm
はブラウザの状態とユーザーの入力を言語の機能とそのアーキテクチャで簡単に管理できるため、簡単なアプリであればほとんど迷うことがなく作りたいものが作れる点で気にいっている。
ただ最近では、elm
の便利な状態管理の手法は JS のフレームワークにも導入され、React のコンポーネントを用いた UI 開発や JS のその他の資源と組み合わせることで効率的にフロントエンドを開発することが主流になってきている。
このような流れのためか、ここ数年はelm
を用いた開発を行う人が極端に少なくなってきていると感じている。
ただフロントエンドの専門家ではない私からすると、フレームワークの選定に迷う必要がない点や、ts
にするかjs
にするか迷わなくて良い点や、Haskell
ライクな言語の楽さとelm-format
の利便性などの観点から考えると、簡単な Web アプリであれば依然としてelm
を用いて開発を行うことは悪くない選択肢だと思っている。
この記事ではelm
とBootstrap
やelm
とTailwind CSS
を組み合わせたサンプルアプリの構築方法を解説する。
環境構築(Bootstrap 編)
プロジェクトを作成
$ mkdir elm-bootstrap-sampleapp
$ cd elm-bootstrap-sampleapp
$ npm init -y
bootstrap をインストール(参考)
$ npm i --save-dev parcel
$ npm i --save-dev bootstrap @popperjs/core
elm をインストールして環境を構築
$ npm i --save-dev elm @parcel/transformer-elm
$ npx elm init
必要なファイルを作成
$ touch src/index.html src/index.js src/index.scss src/Main.elm
src/index.html
を書く。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="index.scss" rel="stylesheet" />
</head>
<body>
<div id="root"></div>
<script type="module" src="index.js"></script>
</body>
</html>
src/index.js
を書く。
bootstrap
とelm
のjavascript
が共存している。
import * as bootstrap from "bootstrap";
import { Elm } from "./Main.elm";
Elm.Main.init({ node: document.getElementById("root") });
src/index.scss
を書く。
@import "bootstrap/scss/bootstrap";
src/Main.elm
を書く。
module Main exposing (main)
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class)
import Html.Events exposing (onClick)
main =
Browser.sandbox { init = init, update = update, view = view }
type alias Model =
{ score : Int
}
init : Model
init =
{ score = 0
}
type Msg
= Select String
update : Msg -> Model -> Model
update msg model =
case msg of
Select _ ->
{ model | score = model.score + 1 }
view : Model -> Html Msg
view model =
div []
[ button
[ class "btn btn-primary", onClick (Select "a") ]
[ text (String.fromInt model.score) ]
]
package.json
を書く。
{
"name": "elm-bootstrap-sampleapp",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "parcel src/index.html",
"build": "parcel build src/index.html --no-source-maps",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@parcel/transformer-elm": "^2.7.0",
"@parcel/transformer-sass": "^2.7.0",
"@popperjs/core": "^2.11.6",
"bootstrap": "^5.2.2",
"elm": "^0.19.1-5",
"parcel": "^2.7.0"
}
}
npm run start
で開発出来る。
npm run build
で圧縮してビルドが出来る。
環境構築(Tailwind CSS 編)
プロジェクトを作成
$ mkdir elm-tailwindcss-sampleapp
$ cd elm-tailwindcss-sampleapp
$ npm init -y
elm
とparcel
とtailwindcss
をインストール
$ npm i -D elm parcel tailwindcss @parcel/transformer-elm
elm
とtailwindcss
の環境を構築
$ npx elm init
$ npx tailwindcss init
必要なファイルを作成する。
$ touch .postcssrc src/index.html src/index.css src/index.js src/Main.elm
.postcssrc
を作成してtailwindcss
をコンパイル出来るようにする。
{
"plugins": {
"tailwindcss": {}
}
}
tailwindcss
が見るファイルにhtml
とjs
とelm
を設定する。
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./src/**/*.{html,js,elm}",
],
theme: {
extend: {},
},
plugins: [],
}
package.json
を書く。
{
"name": "elm-tailwindcss-sampleapp",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "parcel src/index.html",
"build": "parcel build src/index.html --no-source-maps",
"clean": "rm dist/*",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@parcel/transformer-elm": "^2.7.0",
"elm": "^0.19.1-5",
"parcel": "^2.7.0",
"tailwindcss": "^3.1.8"
}
}
src/index.html
を書く。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="index.css" rel="stylesheet">
</head>
<body>
<div id="root"></div>
<script type="module" src="index.js"></script>
</body>
</html>
src/index.css
を書く。
@tailwind base;
@tailwind components;
@tailwind utilities;
src/index.js
を書く。
import { Elm } from "./Main.elm";
Elm.Main.init({ node: document.getElementById("root") });
src/Main.elm
を書く。
module Main exposing (main)
import Browser
import Html exposing (Html, button, div, text)
import Html.Attributes exposing (class)
import Html.Events exposing (onClick)
main =
Browser.sandbox { init = init, update = update, view = view }
type alias Model =
{ score : Int
}
init : Model
init =
{ score = 0
}
type Msg
= Select String
update : Msg -> Model -> Model
update msg model =
case msg of
Select _ ->
{ model | score = model.score + 1 }
view : Model -> Html Msg
view model =
div []
[ button
[ class "rounded-full bg-gray-300 px-4 py-2", onClick (Select "a") ]
[ text (String.fromInt model.score) ]
]
npm run start
で開発出来る。
npm run build
で圧縮してビルドが出来る。
感想
Bootstrap
はjs
に依存しているのでelm
と組み合わせて使って良いものなのかよくわからない。とりあえずはうまく動いている。一方で pureCSS のTailwind CSS
は css が書ける人用のフレームワークのため、css が得意でない私では使いこなせない代物だと思う。私は楽したいのでBootstrap
が好みかなぁ。React
もts
と状態管理フレームワークと組み合わせればelm
以上に開発効率が良いのだろうなぁと思う。elm
のHaskell
ライクな言語が好きなのでなかなかそちらに行けないが。