Static blog with front page summary
Goal: have a personal blog, and try out another point in the 'modular app design with elixir' space. Designing OTP systems with elixir had some interesting ideas.
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
defmodule Blogex do
|
||||
@moduledoc """
|
||||
Blogex — a multi-blog engine for Phoenix apps, powered by NimblePublisher.
|
||||
|
||||
Blogex lets you host multiple blogs (e.g. engineering blog, release notes)
|
||||
from markdown files in your repo. Posts are compiled into the BEAM at build
|
||||
time for instant reads with zero runtime I/O.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Add `blogex` to your dependencies:
|
||||
|
||||
```elixir
|
||||
def deps do
|
||||
[
|
||||
{:blogex, "~> 0.1.0"}
|
||||
]
|
||||
end
|
||||
```
|
||||
|
||||
2. Create your markdown posts:
|
||||
|
||||
```
|
||||
priv/blog/engineering/2026/03-10-our-new-architecture.md
|
||||
priv/blog/release-notes/2026/03-01-v2-launch.md
|
||||
```
|
||||
|
||||
Each file has frontmatter + content:
|
||||
|
||||
```markdown
|
||||
%{
|
||||
title: "Our New Architecture",
|
||||
author: "Jane Doe",
|
||||
tags: ~w(elixir architecture),
|
||||
description: "How we rebuilt our platform"
|
||||
}
|
||||
---
|
||||
Your markdown content here...
|
||||
```
|
||||
|
||||
3. Define blog modules in your app:
|
||||
|
||||
```elixir
|
||||
defmodule Firehose.EngineeringBlog do
|
||||
use Blogex.Blog,
|
||||
blog_id: :engineering,
|
||||
app: :firehose,
|
||||
from: "priv/blog/engineering/**/*.md",
|
||||
title: "Engineering Blog",
|
||||
description: "Deep dives into our tech stack",
|
||||
base_path: "/blog/engineering"
|
||||
end
|
||||
|
||||
defmodule Firehose.ReleaseNotes do
|
||||
use Blogex.Blog,
|
||||
blog_id: :release_notes,
|
||||
app: :firehose,
|
||||
from: "priv/blog/release-notes/**/*.md",
|
||||
title: "Release Notes",
|
||||
description: "What's new in our product",
|
||||
base_path: "/blog/releases"
|
||||
end
|
||||
```
|
||||
|
||||
4. Register blogs in your config:
|
||||
|
||||
```elixir
|
||||
config :blogex,
|
||||
blogs: [Firehose.EngineeringBlog, Firehose.ReleaseNotes]
|
||||
```
|
||||
|
||||
5. Mount routes in your Phoenix router:
|
||||
|
||||
```elixir
|
||||
scope "/blog" do
|
||||
pipe_through :browser
|
||||
|
||||
forward "/engineering", Blogex.Router, blog: Firehose.EngineeringBlog
|
||||
forward "/releases", Blogex.Router, blog: Firehose.ReleaseNotes
|
||||
end
|
||||
```
|
||||
|
||||
6. Enable live reloading in `config/dev.exs`:
|
||||
|
||||
```elixir
|
||||
live_reload: [
|
||||
patterns: [
|
||||
...,
|
||||
~r"priv/blog/*/.*(md)$"
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
## Architecture (Poncho Pattern)
|
||||
|
||||
Blogex is designed as a "poncho" — it wraps NimblePublisher and provides
|
||||
a clean public API while the inner library does the heavy lifting of
|
||||
markdown parsing and compilation. The host app's supervision tree is used
|
||||
directly; Blogex adds no processes of its own since all data is compiled
|
||||
into module attributes at build time.
|
||||
|
||||
## Modules
|
||||
|
||||
* `Blogex.Blog` — macro to define a blog context
|
||||
* `Blogex.Post` — post struct
|
||||
* `Blogex.Registry` — cross-blog queries
|
||||
* `Blogex.Feed` — RSS/Atom feed generation
|
||||
* `Blogex.SEO` — meta tags and sitemap generation
|
||||
* `Blogex.Components` — Phoenix function components
|
||||
* `Blogex.Router` — mountable Plug router
|
||||
"""
|
||||
|
||||
defdelegate blogs, to: Blogex.Registry
|
||||
defdelegate get_blog!(blog_id), to: Blogex.Registry
|
||||
defdelegate get_blog(blog_id), to: Blogex.Registry
|
||||
defdelegate all_posts, to: Blogex.Registry
|
||||
defdelegate all_tags, to: Blogex.Registry
|
||||
end
|
||||
Reference in New Issue
Block a user