README.md

# 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.