reelm-framework
v0.1.11
Published
Reelm: Elm-style architecture for ReScript and JavaScript.
Maintainers
Readme
Pure ReScript Elm-style architecture
Reelm is a ReScript-first framework inspired by Elm Architecture:
- explicit
type msgwith pattern matching inupdate - pure state transitions
- explicit effects (
Fx) and subscriptions (Subs) - deterministic VDOM rendering
- typed router contracts (
Router)
Repository Quickstart
bun install
bun run res:rebuild
bun test
bun run buildMinified Production Build
bun run buildOutput:
dist/reelm.min.js
package.json exports point "." and "./bundle" to this minified bundle.
Run Examples
cd examples/counter
bun install
bun run devAvailable examples:
examples/counterexamples/todoexamples/nested-teaexamples/spa-routerexamples/paintexamples/infinite-scrollexamples/benchmark
Minimal ReScript App
type model = {count: int}
type msg = Inc | Dec
type document
type node
@val external documentObj: document = "document"
@send external getElementById: (document, string) => node = "getElementById"
let init: model = {count: 0}
let update = (model: model, msg: msg) =>
switch msg {
| Inc => ReelmApp.step({count: model.count + 1})
| Dec => ReelmApp.step({count: model.count - 1})
}
let view = (model: model, dispatch: msg => unit) => {
let txt = ReelmJsx.string
<main className="p-6 space-y-3">
<h1 className="text-2xl font-bold"> {txt("Count: " ++ Int.toString(model.count))} </h1>
<div className="flex gap-2">
<button className="btn" onClick={_ => dispatch(Dec)}> {txt("-1")} </button>
<button className="btn btn-primary" onClick={_ => dispatch(Inc)}> {txt("+1")} </button>
</div>
</main>
}
let _app =
ReelmApp.start({
"init": ReelmApp.step(init),
"update": update,
"view": view,
"node": getElementById(documentObj, "app"),
})Effects and Subscriptions
type msg =
| Inc
| DelayedInc
| Tick
type model = {count: int, auto: bool}
let update = (model, msg) =>
switch msg {
| Inc => ReelmApp.step({...model, count: model.count + 1})
| DelayedInc => ReelmApp.stepFx(model, Fx.delay(500, Inc))
| Tick => ReelmApp.step({...model, count: model.count + 1})
}
let subscriptions = (model: model) =>
if model.auto {
[Subs.every(1000, Tick)]
} else {
[]
}Router
type shared = {appName: string}
type pageModel = unit
let homePage = {
"init": (_params: unit, _shared: shared) => (),
"update": (model: pageModel, _msg: unit, _shared: shared) => model,
"view": (_model: pageModel, shared: shared, _dispatch: unit => unit) =>
<h1 className="text-2xl font-bold"> {ReelmJsx.string("Welcome to " ++ shared.appName)} </h1>,
}
let router =
Router.createRouter({
"routes": [Router.page(Router.route("/"), homePage)],
"shared": {appName: "Reelm"},
"strict": true,
})Documentation
- Architecture
- Effects and Subscriptions
- JSX in ReScript
- Router
- CLI
- ReScript examples coverage
- Feature parity
- Safety hardening plan
CLI Note
CLI supports both modes:
- ReScript mode:
--res(generates/uses.respages +src/generated/Router.res) - JS mode:
--js(generates/uses.js/.jsxpages +src/generated/router.js) --jsxis available in JS mode for JSX scaffolding
add/gen/dev/build auto-detect mode from src/pages when not specified.
Current Known Issues
- No known test failures in the default suite (
bun test).
License
MIT
