A self publishing platform and presentation framework on fire built with Elixir & Phoenix LiveView 🐦‍🔥 alchemy-pub.fly.dev
liveview slides blog-engine ssg blog markdown elixir presentation rss phoenix
README.md

AlchemyPub #

AlchemyPub is a static site generator on fire built with Elixir & Phoenix LiveView.

It generates websites from markdown files. Changes to the source files are instantly published to all viewers. If no JavaScript is available on the client, it falls back gracefully to fully server-side rendered content. There is also an RSS feed generated from the articles.

Instead of saving generated pages as html files, they are rendered on startup and stored in memory using ETS. A file watcher picks up changes and broadcasts them using PubSub. Using the magic of Phoenix LiveView the change is immediately visible to all page viewers.

As a markdown parser, MDEx is used. It parses CommonMark with GFM tables, strikethrough and [[Wikilinks]] enabled, and its document AST is what the engine transforms: anchors are generated for headers, slides and columns are split at thematic breaks, and speaker notes are stripped from public decks.

For styling, daisyUI allows easy change of themes and creation of your own style using Tailwind. The site is fully responsive for mobile and desktop resolutions, and supports themes for dark and light mode. Code blocks are highlighted at compile time by Lumis, so no JavaScript runs in the browser for it.

With LiveDeck, AlchemyPub comes with an interactive presentation framework. It can turn any markdown page into a dynamic, interactive presentation. You can see an example of LiveDeck running here.

LiveDeck example

Pages can be turned into a onesheet — a dense, print-ready single-page reference layout — by setting onesheet: true in the frontmatter. Content is split into flex columns using --- dividers and scales to fit one A4 page when printed.

Setting forward: <url> in a page's frontmatter turns it into a redirect, sending visitors to an external URL. This is useful for creating short links or named redirects within the site.

Sites and their articles can be published to the AT Protocol network as standard.site records, kept in sync with the pages from the account configured in config/runtime.exs.

Further page options are documented on their own pages: an image gallery with lightbox and blur-up placeholders, password protected pages, embedding an external site via iframe, and pulling a Bluesky post with its replies below a page so the discussion happens on the AT Protocol network. Two layouts are available, a classic sidebar and a minimal top bar, selected with nav_style in config/config.exs.

Page visits are tracked anonymously. Thanks to Phoenix Presence, it can keep track of navigation and the duration of each page visit. This also powers the live online counter in the navigation bar. The tracking data — including page, duration, referrer, user agent, and country — is stored in a file-based SQLite database using Ecto. No external database or configuration is required. The tracking data can be explored through a custom Phoenix LiveDashboard analytics page.

Using AlchemyPub for your own site #

AlchemyPub runs standalone (this repository is the demo site), but the intended way to build a site is as a dependency: your repository holds only content, configuration and styling, and platform updates arrive with mix deps.update alchemy_pub. See examples/site for a complete, minimal site that does exactly that.

Getting Started #

To start your Phoenix server:

  • Run mix setup to install and setup dependencies
  • Start Phoenix endpoint with mix phx.server or inside IEx with iex -S mix phx.server

Now you can visit localhost:4000 from your browser.

Put your pages as markdown files in the priv/pages directory. You can read more on the Home page.

Ready to run in production? Please check the Phoenix deployment guides.

Release #

mix assets.deploy
MIX_ENV=prod mix release
mix phx.digest.clean --all
PHX_SERVER=true PHX_HOST=localhost SECRET_KEY_BASE="{{ key }}" _build/prod/rel/alchemy_pub/bin/alchemy_pub start

Content outside the release #

A release carries its own copy of priv, so pages and images change only with a new release. Pointing CONTENT_DIR at a directory with pages and images, for example the priv of the checked out repository, keeps them live across rebuilds: a git pull is enough to publish new content, and the running site picks it up within seconds.

CONTENT_DIR=/srv/site/priv PHX_SERVER=true ... _build/prod/rel/alchemy_pub/bin/alchemy_pub start

Deployment on fly.io #

Set an admin secret

flyctl secrets set ADMIN_SECRET=(openssl rand -base64 48)

And deploy

flyctl deploy

Credits #

AlchemyPub is originally brought to you by j4nk.dev. It is published under the GNU General Public License v3.0.