- Elm is not a frontend framework.
- Elm is neither V in MVC, nor MV in MVC, nor even MVC itself.
- You don't assemble libraries and configure options to make Elm do what you want.
Elm is a language. You write programs with it.
But instead of providing a regular main
function to run, Elm wants you to write at least 2 parts to run your program: init
and update
. This is my pseudo code for your init
and update
plugs into Elm runtime:
let [globalState, cmd] = init(optionFlags)
const messageBus = new EventEmitter()
messageBus.on('msg', function (msg) {
const [newState, newCmd] = update(msg, globalState)
globalState = newState // NOTE: globalState changes every update
execAndEmitMsg(newCmd, messageBus)
})
execAndEmitMsg(cmd, messageBus)
NOTE: if you are unfamiliar with
EventEmitter
, it is a "message bus" that provideemit
andon
listeners alternatively, you may prefer the Go example
Backend web devs are very familiar with writing programs in an event-driven manner: each incoming http request is handled by a stateless function, reading and writing a global database. Imagine doing the same, but not just to handle incoming http requests.
Elm is just saying, that's how we write all Elm programs.
In addition, Elm is saying it is best if init
and update
functions cannot perform any actual commands like open a file, or http get. Instead just return plain values to tell the runtime what to execute next:
cmd = { type: "Http.get", url: "http://roll.diceapi.com/json/d6", msg: "RollDice" }
In the first pseudo code on top, these cmd
values are handed off to a runtime function execAndEmitMsg
that performs the real actions:
function execAndEmitMsg (cmd, messageBus) {
switch (cmd.type) {
case 'Http.get':
fetchText(cmd.url).then((data) => messageBus.emit('msg', [cmd.msg, data]))
break
}
}
Notice that messageBus.emit('msg', ...)
? That's how the result is passed back through messageBus.on('msg', ...)
and handled by your update
And just like that, round and round we go.