Svx: a proof of concept for single-file components in LiveView

Svx 0.1.16

Code is horrible (I was basically typing whatever first came to mind, no thinking about architecture, or tests, or…). But it works :smiley:

What does it look like?

See priv/example in the repo above for a full example with Phoenix and LiveView. Just the component looks like this:

<script language="elixir">
  alias Example.Thermostat

  def mount(_params, _session, socket) do
    if connected?(socket), do: Process.send_after(self(), :update, 1000)

    case Thermostat.get_reading() do
      {:ok, temperature} ->
        {:ok, assign(socket, temperature: temperature)}

      {:error, _reason} ->
        {:ok, redirect(socket, to: "/error")}
    end
  end

  def handle_info(:update, socket) do
    Process.send_after(self(), :update, 1000)
    {:ok, temperature} = Thermostat.get_reading()
    {:noreply, assign(socket, :temperature, temperature)}
  end
</script>

<p class={"example temp-#{ @temperature > 30 }"}>
  Current temperature: <%= @temperature %>
</p>

<style>
  .example {
    font-size: 40pt;
  }

  .temp-true {
    color: orange;
  }

  .temp-false {
    color: blue;
  }
</style>

Follow the steps in the README to install and see how this works for yourself.

Why?

Why not :smiley:

It turns out I have quite a few components where there’s not that much elixir code, but there’s a lot of template code. I always found it weird to place that inside a string, or to put a component’s css so far away from the actual component, or…

Also, I like Svelte, and I wanted a similar thing.

OMG Scoped CSS?!!

No :slight_smile:

It’s definitely doable with this approach, but parsing CSS correctly is not for the faint of heart, and definitely outside the scope of a simple PoC.

Will you use this?

I will definitely use this in a side project.

8 Likes

Version 0.2

  • + Add config :your_app, :svx, :prelude: [...]

    You can use it to provide top-level things like requres, imports, uses etc. across all your live views

  • + Minior update to README on how set up reloadable_compilers (makes sure that Phoenix/Elixir’s own reloads don’t break)

1 Like

Version 0.3.2

Breaking

Functionality is the same, getting it to work is significantly easier. It works faster and more reliably.

** Requires fswatch ** (apt-get fswatch or brew install fswatch)

  1. Add svx to your list of dependencies in mix.exs:
def deps do
  [
    {:svx, "~> 0.3.2"}
  ]
end
  1. In lib/<you_app>/application.ex add Svx to apps that you start:
{Svx.Compiler, [path: "lib/<your_app>_web/live", namespace: ExampleWeb.Live]}
  1. Add @import "./generated.css"; to assets/css/app.css
  2. Create your views as .lsvx in lib/your_app_web/live

They will be available under ExampleWeb.Live.

2 Likes