Elm Friendly functional frontend

Version 0.19.1 · source

Start here

elm init
New project
elm reactor
Dev server on :8000
elm make src/Main.elm
Compile to index.html
elm make src/Main.elm --output=elm.js
Compile to JS
elm install <author/package>
Add a package
elm repl
Try expressions
elm make src/Main.elm --optimize --output=elm.js
Production build
elm-test
Run tests

Concepts

  1. Model all state
  2. View Html Msg
  3. Msg what happened
  4. Update returns new Model
The Elm Architecture

Project

elm init
Create elm.json and src/
elm install <author/package>
Add a dependency
Example: elm install elm/http. Applications pin exact versions in elm.json.
elm repl
Start an interactive session
elm repl --no-colors
REPL without ANSI colours
elm repl --interpreter=<path>
Use another JS interpreter
elm <command> --help
Help for a command
elm --version
Print compiler version

Build

elm make src/Main.elm
Compile to index.html
elm make src/Main.elm --output=elm.js
Compile to a JS file
elm make src/Main.elm --optimize
Optimized build, no Debug
Fails if Debug.log or Debug.toString remain; then minify with uglify-js or terser.
elm make src/Main.elm --debug
Add the time-travel debugger
elm make src/Main.elm --output=/dev/null
Type-check only, no output
elm make src/A.elm src/B.elm --output=elm.js
Several Main modules, one file
elm make src/Main.elm --report=json
Machine-readable errors
elm make --docs=docs.json
Build package docs JSON
elm reactor
Serve the project at :8000
elm reactor --port=<n>
Serve on another port

Packages

elm publish
Publish a package version
Needs a package elm.json, a git tag matching the version and a public repo.
elm bump
Compute the next version
elm diff
API changes since last publish
elm diff <author/package> <v1> <v2>
API changes between versions
elm install elm/json
JSON encode and decode
elm install elm/http
HTTP requests
elm install elm/browser
Browser.element and Browser.application
elm install elm/url
Url parsing for routing
elm install elm/time
Time and zones
elm install elm/random
Random generators

Tooling

elm-format src/ --yes
Format all files in place
elm-format src/ --validate
Fail if not formatted (CI)
elm-format --stdin
Format from standard input
elm-test init
Create tests/ and test deps
elm-test
Run all tests in tests/
elm-test <file>
Run one test file
elm-test --watch
Re-run on change
elm-test --fuzz <n>
Fuzz runs per test
elm-test --seed <n>
Replay a fuzz seed
elm-test install <author/package>
Add a test dependency
elm-review
Lint the project with elm-review
Separate npm tool; needs a review/ config, create it with elm-review init.

Syntax

module Main exposing (main)
Module header
import Html exposing (Html, div, text)
Import names
import Html.Attributes as A
Import with alias
name : Int -> String
Type annotation
type alias User = { name : String }
Name a record type
type Msg = Inc | Dec
Custom type
type Maybe a = Just a | Nothing
Parameterised type
case x of ... -> ...
Pattern match
if a then b else c
Conditional, always an expression
let y = 1 in y + 1
Local bindings
\x -> x + 1
Anonymous function
{ model | count = 1 }
Update record fields
model.count / .count
Field access / accessor function
x |> f |> g
Pipe left to right
f << g / f >> g
Compose functions
(a, b) / ( a, b, c )
Tuples
-- note / {- block -}
Comments
"""multi line"""
Multiline string

Core library

List.map f xs
Transform each item
List.filter f xs
Keep matching items
List.foldl f init xs
Reduce a list
String.fromInt n / String.toInt s
Int to string / parse (Maybe)
Maybe.withDefault 0 m
Unwrap Maybe with fallback
Maybe.map f m
Apply inside Maybe
Result.map f r
Apply inside Result
Dict.fromList pairs
Build a Dict
Dict.get key d
Lookup, returns Maybe
Debug.log "label" value
Print and return value
Debug.todo "msg"
Placeholder that crashes

Programs

Browser.sandbox
Simple app: init, view, update
Browser.element
App with Cmd, Sub and flags
Browser.document
Control the page title and body
Browser.application
Full app with URL routing
Cmd.none / Sub.none
No effect / no subscription
Http.get { url = u, expect = e }
GET request as a Cmd
Decode.field "name" Decode.string
JSON decoder for a field
Html.Events.onClick Msg
Send a Msg on click
Html.Events.onInput Msg
Send a Msg on typing
port sendOut : String -> Cmd msg
Port out to JavaScript
Program types
Function Effects Use for
sandbox none Learning, toys
element Cmd, Sub Widget in a page
document Cmd, Sub Own title and body
application Cmd, Sub, URL Single-page app

Recipes

Minimal counter
module Main exposing (main)import Browserimport Html exposing (button, div, text)import Html.Events exposing (onClick)main = Browser.sandbox { init = 0, update = update, view = view }type Msg = Inc | Decupdate msg n =    case msg of        Inc -> n + 1        Dec -> n - 1view n =    div []        [ button [ onClick Dec ] [ text "-" ]        , text (String.fromInt n)        , button [ onClick Inc ] [ text "+" ]        ]
Embed compiled JS in a page
# elm make src/Main.elm --output=elm.js<div id="app"></div><script src="elm.js"></script><script>  Elm.Main.init({ node: document.getElementById('app') })</script>
Decode a JSON record
import Json.Decode as Dtype alias User = { name : String, age : Int }userDecoder : D.Decoder UseruserDecoder =    D.map2 User        (D.field "name" D.string)        (D.field "age" D.int)
Release build for production
elm make src/Main.elm --optimize --output=elm.jsnpx terser elm.js --compress --mangle -o elm.min.js