1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
|
# Lustre for Elm developers
Lustre has been directly inspired by Elm and shares some of the primary architectural
features of "The Elm Architecture", otherwise known as Model-View-Update. This
guide is for Elm developers who are new to Lustreand want to get up to speed quickly.
## How do I...?
### Setup a new project
**In Elm**, all you really need to get started is to install the `elm` binary.
Running `elm make` against an Elm file will transpile your code to either Javascript,
or HTML with the Javascript output inlined. Most people will build out their own
toolchain to support build-on-save and hot-reload, with tools like Vite or Webpack
with the appropriate plugins. A simple hello world might look like this:
```elm
module Main exposing (main)
import Html
main =
Html.text "Hello, world"
```
**In Lustre** you need to install the `lustre` package with `gleam add lustre`.
Most Lustre projects will add the dev tools too with `gleam add --dev lustre_dev_tools`.
A simple hello world might look like this:
```gleam
import lustre
import lustre/element/html
pub fn main() {
let app = lustre.element(html.h1([], [html.text("Hello, world")]))
let assert Ok(_) = lustre.start(app, "#app", Nil)
}
```
### Render some HTML
**In Elm**, you can call functions in the `elm/html` package to render HTML
elements. The `Html` module in `elm/html` contains functions for most standard
HTML tags; these functions take as parameters a list of attributes from
`Html.Attributes`, or events from `Html.Events` - as well as a list of child
elements:
```elm
Html.button
[ Html.Attributes.class "primary"
, Html.Events.onClick ButtonClicked
]
[ Html.text "Click me" ]
```
---
**In Lustre**, HTML is rendered by calling functions, many of whom share the same
signature - functions in `lustre/element/html` represent HTML tags, and most
functions accept a list of `lustre/attribute` or `lustre/event` values, as well
as a list of child elements.
```lustre
html.button([attribute.class("primary"), event.on_click(ButtonClicked)], [
html.text("Click me")
])
```
### Render some text
**In Elm**, text is rendered by passing a `String` to the `Html.text` function:
```elm
Html.span [] [ Html.text <| "Hello, " ++ name ]
```
---
**In Lustre**, text is rendered by passing a `String` to the `html.text` or
`element.text` functions:
```gleam
html.span([], [
html.text("Hello, " <> name),
])
```
### Manage state
**In Elm** all state is stored in a single `Model` type and updates happen through
a central `update` function:
```elm
type alias Model = Int
init : Model
init = 0
type Msg
= Incr
| Decr
update : Msg -> Model -> Model
update msg model =
case msg of
Incr ->
model + 1
Decr ->
model - 1
```
---
**In Lustre** all state is stored in a single `Model` type and updates happen
through a central `update` function, just like in Elm:
```gleam
fn init(_) {
0
}
type Msg {
Incr
Decr
}
fn update(model: Model, msg: Msg) -> Msg {
case msg {
Incr -> model + 1
Decr -> model - 1
}
}
```
### Handle events
**In Elm** event handlers are decoders for event objects. When the decoder succeeds,
that value is dispatched as a message to your `update` function.
```elm
Html.input [ Html.Events.onInput UserUpdatedNameField ] []
type Msg
= UserUpdatedNameField String
type alias Model = { name : String }
update : Msg -> Model -> Model
update msg model =
case msg of
UserUpdatedNameField name
{ model | name = name }
```
---
**In Lustre** event handlers work in the same way. Lustre provides functions to
handle most common events, in [`lustre/effect`](https://hexdocs.pm/lustre/lustre/effect.html):
```gleam
button([on_click(Decr)], [text("-")])
```
```gleam
input([on_input(UpdateInput)])
```
```gleam
div([on("mousemove", fn(event) {
...
}], [...])
```
### Fetch data
**In Elm** you can fetch data by making a HTTP request. HTTP request functions
both return a value of type `Cmd msg`, and are handled by the application's `update`
function; the payload from the response is available within the `update` function
and can be used to update the `Model`, or call other functions that return a value
of type `Cmd msg`.
```elm
type Msg
= ApiReturnedBookResponse (Result Http.Error String)
getBook : Cmd Msg
getBook =
Http.get
{ url = "https://elm-lang.org/assets/public-opinion.txt"
, expect = Http.expectString ApiReturnedBookResponse
}
type alias Model = { bookResponse : Result Http.Error String }
update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
case msg of
ApiReturnedBookResponse response ->
{ model | bookResponse = response }
```
---
**In Lustre**, the approach is similar, using types and functions from the
[`lustre_http` package](https://hexdocs.pm/lustre_http/lustre_http.html):
```gleam
pub type Msg {
ApiReturnedBookResponse(Result(String, lustre_http.HttpError))
}
fn get_book() -> effect.Effect(Msg) {
lustre_http.get(
"https://elm-lang.org/assets/public-opinion.txt",
lustre_http.expect_text(ApiReturnedBookResponse)
)
}
pub type Model {
Model(book_response: Result(String, HttpError))
}
pub fn update(model: Model, msg: Msg) -> #(Model, effect.Effect(Msg)) {
case msg {
ApiReturnedBookResponse(response) -> #(Model(..model, book_response: response), effect.none())
}
}
```
## Where to go next
To walk through setting up a new Lustre project and building your first app, check
out the [quickstart guide](https://hexdocs.pm/lustre/guide/01-quickstart.html).
If you prefer to learn by example, we have a collection of examples that show
off specific features and patterns in Lustre. You can find them in the
[examples directory](https://hexdocs.pm/lustre/reference/examples.html)
If you're having trouble with Lustre or not sure what the right way to do
something is, the best place to get help is the [Gleam Discord server](https://discord.gg/Fm8Pwmy).
You could also open an issue on the [Lustre GitHub repository](https://github.com/lustre-labs/lustre/issues).
|