aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHayleigh Thompson <me@hayleigh.dev>2024-02-27 17:40:17 +0000
committerHayleigh Thompson <me@hayleigh.dev>2024-02-29 17:37:59 +0000
commit834c4f9dca378cc87cf2e5c71988061f64ee489d (patch)
treeac863054aa6fd5638912be004145967ecf54d6ed
parent495e64027d8fe7aa6a7346484f874c8881b84468 (diff)
downloadlustre-834c4f9dca378cc87cf2e5c71988061f64ee489d.tar.gz
lustre-834c4f9dca378cc87cf2e5c71988061f64ee489d.zip
:recycle: Rename add/remove_renderer to (un)subscribe. Move into lustre/server module.
-rw-r--r--src/lustre.gleam40
-rw-r--r--src/lustre/internals/runtime.gleam24
-rw-r--r--src/lustre/server.gleam33
3 files changed, 47 insertions, 50 deletions
diff --git a/src/lustre.gleam b/src/lustre.gleam
index 884b6f5..b79488d 100644
--- a/src/lustre.gleam
+++ b/src/lustre.gleam
@@ -163,6 +163,7 @@
// IMPORTS ---------------------------------------------------------------------
+import argv
import gleam/bool
import gleam/dict.{type Dict}
import gleam/dynamic.{type Decoder}
@@ -170,15 +171,14 @@ import gleam/erlang/process.{type Subject}
import gleam/option.{type Option, None, Some}
import gleam/otp/actor.{type StartError}
import gleam/result
-import lustre/effect.{type Effect}
-import lustre/element.{type Element}
-import lustre/internals/runtime
-import lustre/server.{type Patch}
-import argv
import glint
import lustre/cli/add
import lustre/cli/build
import lustre/cli/dev
+import lustre/effect.{type Effect}
+import lustre/element.{type Element}
+import lustre/internals/patch
+import lustre/internals/runtime
// MAIN ------------------------------------------------------------------------
@@ -288,6 +288,14 @@ pub type ServerComponent
pub type Action(msg, runtime) =
runtime.Action(msg, runtime)
+/// Patches are sent by server components to any connected renderers. Because
+/// server components are not opinionated about your network layer or how your
+/// wider application is organised, it is your responsibility to make sure a `Patch`
+/// makes its way to the server component client runtime.
+///
+pub type Patch(msg) =
+ patch.Patch(msg)
+
/// Starting a Lustre application might fail for a number of reasons. This error
/// type enumerates all those reasons, even though some of them are only possible
/// on certain targets.
@@ -505,21 +513,6 @@ pub fn register(_app: App(Nil, model, msg), _name: String) -> Result(Nil, Error)
// ACTIONS ---------------------------------------------------------------------
-/// A [`ServerComponent`](#ServerComponent) broadcasts patches to be applied to
-/// the DOM to any connected clients. This action is used to add a new client to
-/// a running server component.
-///
-/// The `id` should be a unique identifier for the client, but it can be any type
-/// you want. This is only used if you want to remove the client in the future
-/// using [`remove_renderer`](#remove_renderer).
-///
-pub fn add_renderer(
- id: any,
- renderer: fn(Patch(msg)) -> Nil,
-) -> Action(msg, ServerComponent) {
- runtime.AddRenderer(dynamic.from(id), renderer)
-}
-
/// Dispatch a message to a running application's `update` function. This can be
/// used as a way for the outside world to communicate with a Lustre app without
/// the app needing to initiate things with an effect.
@@ -531,13 +524,6 @@ pub fn dispatch(msg: msg) -> Action(msg, runtime) {
runtime.Dispatch(msg)
}
-/// Remove a registered renderer from a server component. If no renderer with the
-/// given id is found, this action has no effect.
-///
-pub fn remove_renderer(id: any) -> Action(msg, ServerComponent) {
- runtime.RemoveRenderer(dynamic.from(id))
-}
-
/// Instruct a running application to shut down. For client SPAs this will stop
/// the runtime and unmount the app from the DOM. For server components, this will
/// stop the runtime and prevent any further patches from being sent to connected
diff --git a/src/lustre/internals/runtime.gleam b/src/lustre/internals/runtime.gleam
index 716daac..49d1982 100644
--- a/src/lustre/internals/runtime.gleam
+++ b/src/lustre/internals/runtime.gleam
@@ -25,7 +25,7 @@ type State(model, msg, runtime) {
update: fn(model, msg) -> #(model, Effect(msg)),
view: fn(model) -> Element(msg),
html: Element(msg),
- renderers: Dict(Dynamic, fn(Patch(msg)) -> Nil),
+ renderers: Dict(String, fn(Patch(msg)) -> Nil),
handlers: Dict(String, fn(Dynamic) -> Result(msg, Nil)),
on_attribute_change: Dict(String, Decoder(msg)),
)
@@ -34,16 +34,16 @@ type State(model, msg, runtime) {
///
///
pub type Action(msg, runtime) {
- AddRenderer(Dynamic, fn(Patch(msg)) -> Nil)
Attrs(List(#(String, Dynamic)))
Batch(List(msg), Effect(msg))
Debug(DebugAction)
Dispatch(msg)
Emit(String, Json)
Event(String, Dynamic)
- RemoveRenderer(Dynamic)
SetSelector(Selector(Action(msg, runtime)))
Shutdown
+ Subscribe(String, fn(Patch(msg)) -> Nil)
+ Unsubscribe(String)
}
pub type DebugAction {
@@ -106,14 +106,6 @@ fn loop(
|> loop(state)
}
- AddRenderer(id, renderer) -> {
- let renderers = dict.insert(state.renderers, id, renderer)
- let next = State(..state, renderers: renderers)
-
- renderer(Init(dict.keys(state.on_attribute_change), state.html))
- actor.continue(next)
- }
-
Batch([], _) -> actor.continue(state)
Batch([msg], other_effects) -> {
let #(model, effects) = state.update(state.model, msg)
@@ -189,7 +181,15 @@ fn loop(
}
}
- RemoveRenderer(id) -> {
+ Subscribe(id, renderer) -> {
+ let renderers = dict.insert(state.renderers, id, renderer)
+ let next = State(..state, renderers: renderers)
+
+ renderer(Init(dict.keys(state.on_attribute_change), state.html))
+ actor.continue(next)
+ }
+
+ Unsubscribe(id) -> {
let renderers = dict.delete(state.renderers, id)
let next = State(..state, renderers: renderers)
diff --git a/src/lustre/server.gleam b/src/lustre/server.gleam
index 841f897..d478e19 100644
--- a/src/lustre/server.gleam
+++ b/src/lustre/server.gleam
@@ -16,6 +16,7 @@ import gleam/erlang/process.{type Selector}
import gleam/int
import gleam/json.{type Json}
import gleam/result
+import lustre.{type Patch, type ServerComponent}
import lustre/attribute.{type Attribute, attribute}
import lustre/effect.{type Effect}
import lustre/element.{type Element, element}
@@ -23,16 +24,6 @@ import lustre/internals/constants
import lustre/internals/runtime.{type Action, Attrs, Event, SetSelector}
import lustre/internals/patch
-// TYPES -----------------------------------------------------------------------
-
-/// Patches are sent by server components to any connected renderers. Because
-/// server components are not opinionated about your network layer or how your
-/// wider application is organised, it is your responsibility to make sure a `Patch`
-/// makes its way to the server component client runtime.
-///
-pub type Patch(msg) =
- patch.Patch(msg)
-
// ELEMENTS --------------------------------------------------------------------
/// A simple wrapper to render a `<lustre-server-component>` element.
@@ -103,6 +94,26 @@ pub fn include(properties: List(String)) -> Attribute(msg) {
|> attribute("data-lustre-include", _)
}
+// ACTIONS ---------------------------------------------------------------------
+
+/// A [`ServerComponent`](../lustre#ServerComponent) broadcasts patches to be applied
+/// to the DOM to any connected clients. This action is used to add a new client
+/// to a running server component.
+///
+pub fn subscribe(
+ id: String,
+ renderer: fn(Patch(msg)) -> Nil,
+) -> Action(msg, ServerComponent) {
+ runtime.Subscribe(id, renderer)
+}
+
+/// Remove a registered renderer from a server component. If no renderer with the
+/// given id is found, this action has no effect.
+///
+pub fn unsubscribe(id: String) -> Action(msg, ServerComponent) {
+ runtime.Unsubscribe(id)
+}
+
// EFFECTS ---------------------------------------------------------------------
///
@@ -136,7 +147,7 @@ fn do_set_selector(_sel: Selector(Action(runtime, msg))) -> Effect(msg) {
///
pub fn decode_action(
dyn: Dynamic,
-) -> Result(Action(runtime, msg), List(DecodeError)) {
+) -> Result(Action(runtime, ServerComponent), List(DecodeError)) {
dynamic.any([decode_event, decode_attrs])(dyn)
}