Creating a markdown-based changelog for LiveView apps

Check how I added a changelog to my Phoenix LiveView web app.

I can add my changelog separately to my blog or docs site. But I decided to experiment with keeping it inside the app.

I’ve also decided to group changes under a version number which doesn’t make much sense for a web app. But I still wanted to do that.

Simplest approach

For a first simple approach I have created a new LiveView named changelog_live.ex:

changelog_live.ex
defmodule OurnextbookWeb.ChangelogLive do
  use OurnextbookWeb, :live_view

  def mount(_params, _session, socket) do
    {:ok, socket}
  end

  def render(assigns) do
    ~H"""
    <h1>Changelog</h1>
    <h3>v0.2</h3>
    <small>2025-02-03</small>
    <ul>
      <li>Introduce little stars.</li>
      <li>Make changelog public.</li>
    </ul>
    <h3>v0.1</h3>
    <small>2024-11-03</small>
    <ul>
      <li>Add authentication.</li>
      <li>Add clubs & memberships.</li>
    </ul>
    """
  end
end
Phoenix LiveView

This works great, but I always have to type the HTML markup along with the content of the changelog. It’s fine for short entries, but I want to focus on the content.

What if I can use markdown for the changelog content, and have the app convert it dynamically to HTML?

Enter Earmark.

Earmark

Earmark is an Elixir Hex package that parses Markdown and converts it into HTML.

To bring the package in my web app, I am adding the dependency to my mix.exs file:

mix.exs
defp deps do
  [
    {:earmark, "~> 1.4"}
  ]
end
Elixir

I then run mix deps.get in my terminal to get the new dependency.

Now I need a new file to put my changelog in markdown format:

priv/static/changelog.md
# Changelog

### v0.2
<small>2025-02-03</small>

- Introduce little stars.
- Make changelog public.

### v0.1
<small>2024-11-03</small>

- Add authentication.
- Add clubs & memberships.
Markdown

I want to replace the static content in changelog_live.ex with the markdown content converted to HTML, dynamically. Here’s the updated file:

changelog_live.ex
defmodule OurnextbookWeb.ChangelogLive do
  use OurnextbookWeb, :live_view
  alias Earmark

  require Logger

  def mount(_params, _session, socket) do
    changelog_html = load_changelog()
    {:ok, assign(socket, changelog_html: changelog_html)}
  end

  defp load_changelog do
    file_path = Application.app_dir(:ournextbook, "priv/static/changelog.md")

    case File.read(file_path) do
      {:ok, content} ->
        Earmark.as_html!(content)

      {:error, reason} ->
        Logger.error("Failed to load changelog from #{file_path}: #{inspect(reason)}")
        "<p>Failed to load changelog.</p>"
    end
  end

  def render(assigns) do
    ~H"""
    <div>
      <%= raw(@changelog_html) %>
    </div>
    """
  end
end
Phoenix LiveView

Here’s how it looks:

Thoughts

  • I don’t really have to use LiveView for this one. It can be a normal page.
  • I generally don’t want to add new dependencies to my apps unless I really have to. Earmark doesn’t bring other dependencies so I am good with that.
  • There’s a cool way to watch (in :dev) the markdown file for changes and refresh the LiveView automatically. But I don’t mind the manual refresh.
  • Phoenix uses TailwindCSS by default. Normally, I’d have to style the HTML output using the utility classes. But the output looks good without me worrying about figuring out how to style Earmark’s output. How that’s possible you ask? I have introduced a classless approach based on SimpleCSS without removing TailwindCSS. I will blog about that soon. In the meantime, if you need to style the generated HTML, check the Tailwind CSS Typography plugin with its prose classes.

Here’s what I am doing

At Amignosis, I pour my heart and skill into crafting slowly brewed software, one thoughtful line at a time. I am craftsman in a world of complexity and low-quality solutions. I am a shoemaker. I take the time to create simple, timeless software built to last. Check what I am doing now and talk to me.

Join 67 other subscribers

Responses

  1. Jerry Cheung Avatar

    That looks really sweet!

    1. Petros Avatar

      Thank you Jerry. Not exactly staying focused, haha! But that’s what I felt like doing yesterday 😀.

Leave a Reply

Discover more from Petros Amoiridis

Subscribe now to keep reading and get access to the full archive.

Continue reading