How to structure an Elm project?

The answer to this question can be found in the Beginning Elm book. This question will therefore be removed at some time in the future.

Do not overuse: Files are allowed to get quite big without needing to split them.

Problem
Solution
Problem
Todo.elm
type Task =
Task
{ name : String
, completed : Bool
}
createTask : String -> Task
completeTask : Task -> Task
type Form a =
Valid a
| Invalid a
| Partial a
validate : (Form a -> Form ()) -> Form a -> Form a
type alias TaskForm =
{ name : String
, validated : Bool
}
validateTaskForm : Form TaskForm -> Form ()
type User =
User
{ name : String
, lastOnline : Posix
}
createUser : String -> Posix -> User
type alias UserForm =
{ name : String
, password : String
, validated : Bool
}
validateUserForm : Form UserForm -> Form ()
type alias TodoPageModel =
{ form :
Form TaskForm
, todo : Array Task
, User : User
}
type alias LoginPageModel =
Form UserForm
type Model =
LoginPage LoginPageModel
| TodoPage TodoPageModel
type LoginPageMsg =
NameEntered String
| PasswordEntered String
| Submited
| GotTime Posix
type TodoPageMsg =
LoggedOut
| TaskAdded String
| TaskCompleted Int
| TaskDeleted
type Msg =
LoginSpecific LoginPageMsg
| TodoSpecific TodoPageMsg
init : () -> Model
updateTodoPage : TodoPageModel -> (TodoPageModel, Cmd TodoPageMsg)
updateLoginPage : LoginPageModel -> (LoginPageModel, Cmd LoginPageMsg)
update : Msg -> (Model, Cmd Msg) -> (Model, Cmd Msg)
viewUserForm : Form UserForm -> Html Msg
viewLoginPage : LoginPageModel -> Html Msg
viewTask : Task -> Html Msg
viewTaskForm : Form TaskForm -> Html Msg
viewTodoPage : TodoPageModel -> Html Msg
view : Model -> Html Msg
subscription : Model -> Sub Msgexpos
Solution
Main.elm
importing Todo.Page.Login as LoginPage
importing Todo.Page.Todo as TodoPage
type Model =
LoginPage LoginPage.Model
| TodoPage TodoPage.Model
type Msg =
LoginSpecific LoginPage.Msg
| TodoSpecific TodoPage.Msg
init : () -> Model
update : Msg -> (Model, Cmd Msg) -> (Model, Cmd Msg)
view : Model -> Html Msg
subscription : Model -> Sub Msg
Page/Login.elm
module Todo.Page.Login exposing (Model,Msg,view,update)
importing Todo.Data.Form as Form exposing (Form)
importing Todo.Data.User as User exposing (User,UserForm)
type alias Model =
Form UserForm
type Msg =
NameEntered String
| PasswordEntered String
| Submited
| GotTime Posix
update : Model -> (Model, Cmd Msg)
viewUserForm : Form UserForm -> Html Msg
view : Model -> Html Msg
Page/Todo.elm
module Todo.Page.Login exposing (Model,Msg,view,update)
importing Todo.Data.Task as Task exposing (Task,TaskForm)
importing Todo.Data.User as User exposing (User,UserForm)
type alias Model =
{ form :
Form TaskForm
, todo : Array Task
, User : User
}
type Msg =
LoggedOut
| TaskAdded String
| TaskCompleted Int
| TaskDeleted
update : Model -> (Model, Cmd Msg)
viewTask : Task -> Html Msg
viewTaskForm : Form TaskForm -> Html Msg
view : Model -> Html Msg
Data/Task.elm
module Todo.Data.Task exposing (Task,create,complete,validate)
importing Todo.Data.Form as Form exposing (Form)
type Task =
Task
{ name : String
, completed : Bool
}
create : String -> Task
complete : Task -> Task
type alias TaskForm =
{ name : String
, validated : Bool
}
validate : Form TaskForm -> Form ()
Data/Form.elm
module Todo.Data.Form exposing (Form(..),validate)
type Form a =
Valid a
| Invalid a
| Partial a
validate : (Form a -> Form ()) -> Form a -> Form a
Data/User.elm
module Todo.Data.User exposing (User,UserForm,create,validate)
importing Todo.Data.Form as Form exposing (Form)
type User =
User
{ name : String
, lastOnline : Posix
}
create : String -> Posix -> User
type alias UserForm =
{ name : String
, password : String
, validated : Bool
}
validate : Form UserForm -> Form ()

Question

How should I structure my Elm project?

Answer

Use the following file structure:

  • Main.elm - Contains the main code

  • Data.elm - Contains utility functions for types (like constants)

    • Data/.. - Contains types. Group them logically, for example User and UserForm into Data/User.elm.

  • View.elm - Contains utility functions for views (like view specific constants and very general function.)

    • View/.. - Contains different Views. Sometimes a type has different views. A login page might have a special view for a wrong login.

  • Page.elm - Contains utility functions for pages. For page-transitions its handy to store the different models in here.

    • Page/.. - Contains a Model/View/Update for every page.

  • .. - in the same style you can add your project specific folders like a separate folder for validation.

Further reading