# Phoenix Min
> Slim down Phoenix to LiveView-only with inline HEEx templates
Phoenix Min is a post-installation tool that transforms a default Phoenix installation by removing controller-based infrastructure and converting all templates to inline HEEx using the `~H` sigil.
## Why Phoenix Min?
Phoenix is fantastic, but the default installation includes controller infrastructure that you might not need if you're building a LiveView-only application. Phoenix Min embraces:
1. **LiveView-first**: All pages are LiveViews, no controllers needed
2. **Colocation**: Templates live in the same file as behavior (no more `.html.heex` files)
3. **Simplicity**: Fewer files, fewer directories, easier navigation
4. **Flexibility**: Works with or without Ecto, assets, gettext, etc.
## Installation
### Option 1: One-Step Install (Recommended)
Create a new Phoenix application with Phoenix Min already applied:
```bash
mix igniter.new my_app --install phoenix_min --with=phx.new
```
This single command creates a new Phoenix application and immediately applies all Phoenix Min transformations.
### Option 2: Add to Existing Project
Add `phoenix_min` to your Phoenix project's `mix.exs`:
```elixir
def deps do
[
{:phoenix_min, "~> 0.1.0", only: [:dev], runtime: false}
]
end
```
Then fetch dependencies:
```bash
mix deps.get
```
## Usage
### Option 1: One-Step Install
Create a new Phoenix application with Phoenix Min in one command:
```bash
mix igniter.new my_app --install phoenix_min --with=phx.new
cd my_app
```
Igniter will show you a diff of all the changes. Review and accept them.
### Option 2: Add to Existing Project
After creating a new Phoenix application:
```bash
mix phx.new my_app
cd my_app
```
Run the Phoenix Min installer:
```bash
mix igniter.install phoenix_min
```
Or directly:
```bash
mix phoenix_min.install
```
Igniter will show you a diff of all the changes. Review and accept them.
## What Gets Modified
Phoenix Min makes the following transformations:
### Files Created
- `lib/my_app_web/home_live.ex` - LiveView with inline template replacing PageController
- `test/my_app_web/live/home_live_test.exs` - LiveView test
### Files Modified
- `lib/my_app_web/router.ex` - Root route changed from `get "/", PageController, :home` to `live "/", HomeLive, :index`
- `lib/my_app_web/components/layouts.ex` - Converted from `embed_templates` to inline `def root(assigns)` and `def app(assigns)` functions
- `lib/my_app_web/controllers/error_html.ex` - Converted to inline `render/2` functions
- `test/my_app_web/controllers/error_html_test.exs` - Updated to test inline templates
### Files Removed
- `lib/my_app_web/controllers/page_controller.ex`
- `lib/my_app_web/controllers/page_html.ex`
- `lib/my_app_web/controllers/page_html/` (directory)
- `lib/my_app_web/controllers/error_html/` (directory)
- `lib/my_app_web/components/layouts/` (directory)
- `test/my_app_web/controllers/page_controller_test.exs`
### What's NOT Modified
- Your dependencies (Ecto, Tailwind, etc.) remain untouched
- Core components stay as-is
- Your custom routes and controllers (if any)
- Your existing LiveViews
- Phoenix framework files
## Example: Before & After
### Before (Default Phoenix)
**lib/my_app_web/controllers/page_controller.ex:**
```elixir
defmodule MyAppWeb.PageController do
use MyAppWeb, :controller
def home(conn, _params) do
render(conn, :home)
end
end
```
**lib/my_app_web/controllers/page_html.ex:**
```elixir
defmodule MyAppWeb.PageHTML do
use MyAppWeb, :html
embed_templates "page_html/*"
end
```
**lib/my_app_web/controllers/page_html/home.html.heex:**
```heex
<div>Welcome to Phoenix!</div>
```
**Router:**
```elixir
get "/", PageController, :home
```
### After (Phoenix Min)
**lib/my_app_web/home_live.ex:**
```elixir
defmodule MyAppWeb.HomeLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, socket}
end
def render(assigns) do
~H"""
<div>Welcome to Phoenix!</div>
"""
end
end
```
**Router:**
```elixir
live "/", HomeLive, :index
```
## Inline Templates in Phoenix
Phoenix Min uses inline HEEx templates via the `~H` sigil. Here's how to write them:
```elixir
defmodule MyAppWeb.MyLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, name: "World")}
end
def render(assigns) do
~H"""
<div class="container">
<h1>Hello, {@name}!</h1>
<.button phx-click="greet">
Say Hello
</.button>
<%= if @show_message do %>
<p>Message shown!</p>
<% end %>
</div>
"""
end
def handle_event("greet", _params, socket) do
{:noreply, assign(socket, show_message: true)}
end
end
```
### Layouts
Layouts are also converted to inline:
```elixir
defmodule MyAppWeb.Layouts do
use MyAppWeb, :html
def root(assigns) do
~H"""
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<.live_title>{@page_title}</.live_title>
</head>
<body>
{@inner_content}
</body>
</html>
"""
end
def app(assigns) do
~H"""
<header>
<nav>Navigation here</nav>
</header>
<main>
<.flash_group flash={@flash} />
{@inner_content}
</main>
"""
end
end
```
## Philosophy
Phoenix Min is opinionated about LiveView-first development:
- **Everything is a LiveView**: Even static pages benefit from LiveView's live reload and future interactivity
- **Colocation > Separation**: When templates are small and specific to one LiveView, keeping them inline reduces cognitive overhead
- **Less is More**: Fewer files and directories mean faster navigation and less context switching
- **You're in Control**: Phoenix Min only modifies generated files, never your dependencies or custom code
## Compatibility
- **Phoenix**: 1.7.x and 1.8.x
- **Elixir**: 1.15 or later
- **Works with**:
- Ecto or `--no-ecto`
- Tailwind or `--no-tailwind`
- Esbuild or `--no-esbuild`
- Gettext or `--no-gettext`
- LiveDashboard or `--no-dashboard`
## FAQ
### Can I still use controllers?
Yes! Phoenix Min only removes the default `PageController`. You can still generate controllers with `mix phx.gen.html` or create them manually. Your existing controllers are not touched.
### What about core_components.ex?
Phoenix Min leaves `core_components.ex` untouched. It's a large file with many components that you'll use across your app, so keeping it as-is makes sense.
### Can I convert my existing LiveViews to inline?
Yes! Simply move the content from your `.html.heex` file into a `render/1` function with the `~H` sigil, then delete the template file.
### What if I already deleted PageController?
Phoenix Min gracefully handles missing files. It will only modify what exists in your project.
### Does this work with umbrella apps?
Yes! Phoenix Min detects umbrella apps and operates on the `_web` application.
### Can I undo these changes?
While there's no automated "undo" feature, all changes are shown in a diff before you accept them. You can review and reject any changes you don't want.
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
MIT License - see LICENSE file for details.
## Credits
Built with [Igniter](https://github.com/ash-project/igniter) - the code generation and project patching framework for Elixir.