Script helpers

Dstar can append safe script actions over SSE for one-off browser effects, console diagnostics, and redirects.

Demo

Presets

This runs in your browser only. Signals are per-connection, so nothing you type here can reach anyone else's tab.

JSON. It reaches the helper as a map, which Jason.encode!/1 renders into the console call.

A full page load, so it clears everything below. That is the point.

Helper log

Last action: idle

runs 0

No helper has run yet.

Console mirror

Open your DevTools console (⌘⌥J) — those are the real entries. This panel is a copy, and it mirrors everything the page logs, framework noise included.

Script residue

auto_remove: false leaves the tag in the DOM. These are the ones still there.


  

How it works

  • execute_script/3 appends a script tag through a patch.
  • console_log/3 emits structured browser console output.
  • redirect/3 performs a server-commanded navigation.
  • The helper scripts stay inert after they execute.

These three helpers append a one-shot <script> through a patch: execute_script/3 runs browser code, console_log/3 emits a structured console entry, and redirect/3 commands a navigation. auto_remove: false leaves the tag in the DOM after it has run, so you can go and look at it. The other demos avoid these helpers so the server-rendered patch flow stays easy to inspect.

lib/dstar_demo_web/pages/scripts_page.ex
conn
|> patch_signals(%{script_runs: runs, last_script_action: "execute_script"})
|> prepend_log(runs, "execute_script/3", source)
|> execute_script(source,
  auto_remove: false,
  attributes: %{"data-demo-script" => "run"}
)

If this were LiveView

Both sides run browser code from the server and both perform a server-commanded navigation; they disagree about what crosses the wire.

Dstar

lib/dstar_demo_web/pages/scripts_page.ex
conn
|> patch_signals(%{script_runs: runs, last_script_action: "execute_script"})
|> prepend_log(runs, "execute_script/3", source)
|> execute_script(source,
  auto_remove: false,
  attributes: %{"data-demo-script" => "run"}
)

LiveView

illustrative
# Illustrative LiveView equivalent — not compiled or run.
def handle_event("execute", _params, socket) do
  runs = socket.assigns.script_runs + 1

  {:noreply,
   socket
   |> assign(script_runs: runs, last_script_action: "push_event")
   |> push_event("script-pulse", %{run: runs})}
end

def handle_event("console", _params, socket) do
  runs = socket.assigns.script_runs + 1

  {:noreply,
   socket
   |> assign(script_runs: runs, last_script_action: "push_event")
   |> push_event("script-log", %{level: "info", run: runs})}
end

def handle_event("redirect", _params, socket) do
  {:noreply, push_navigate(socket, to: ~p"/scripts?redirected=1")}
end

# The browser half is a hook, declared once in your bundle rather than
# sent down per event:
#
#   Hooks.ScriptPulse = {
#     mounted() {
#       this.handleEvent("script-pulse", ({run}) => {
#         document.documentElement.dataset.dstarScriptPulse = String(run)
#       })
#
#       this.handleEvent("script-log", ({level, run}) => {
#         console[level]("dstar demo", {run})
#       })
#     }
#   }