mcpField
E
elixir-phoenix

elixir-phoenix

github.com/gsmlg-devDevelopment037 installsUpdated 3w ago
Repository

About elixir-phoenix

elixir-phoenix is a setup skill for Phoenix projects using Bun, Tailwind v4, devenv, and PostgreSQL. It provides configuration patterns for assets, database connections, runtime binaries, and explicitly invoked end-to-end tests.

Key features

  1. 01Configure Bun in place of esbuild
  2. 02Set up Tailwind v4 asset workflows
  3. 03Configure devenv and PostgreSQL
  4. 04Resolve Phoenix JavaScript dependencies with NODE_PATH
  5. 05Configure runtime binary paths
  6. 06Keep end-to-end tests opt-in

Use cases

  1. 01Create a Phoenix project with PostgreSQL
  2. 02Configure Bun and Tailwind asset builds
  3. 03Set up local development using devenv
  4. 04Run end-to-end tests only on request

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/gsmlg-dev/code-agent --skill elixir-phoenix

After installing, type/elixir-phoenixin Claude Code to confirm it loaded.

Bundled filesreferences/devenv-template.md

Details

From the project README

Phoenix Project Setup

Standard patterns for Phoenix projects using Bun, Tailwind v4, devenv, and PostgreSQL.

1. Create the Phoenix Project

# Standard project
mix phx.new my_app --database postgres

# Umbrella app
mix phx.new my_app --umbrella --database postgres

After generation, replace the default esbuild config with bun.

2. Replace esbuild with Bun

In mix.exs deps, replace {:esbuild, ...} with:

{:bun, "~> 1.4", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.2", runtime: Mix.env() == :dev},

In config/config.exs, replace the config :esbuild block with:

config :bun,
  version: "1.3.4",
  my_app: [
    args: ~w(build assets/js/app.js --outdir=priv/static/assets --external /fonts/* --external /images/*),
    cd: Path.expand("../", __DIR__)
  ]

config :tailwind,
  version: "4.1.11",
  my_app: [
    args: ~w(--input=assets/css/app.css --output=priv/static/assets/app.css),
    cd: Path.expand("../", __DIR__)
  ]

For umbrella apps, use Path.expand("../apps/my_app", __DIR__) for cd:.

In config/dev.exs, update watchers:

watchers: [
  tailwind: {Tailwind, :install_and_run, [:my_app, ~w(--watch)]},
  bun: {Bun, :install_and_run, [:my_app, ~w(--sourcemap=inline --watch)]}
]

Update mix.exs aliases:

"assets.deploy": [
  "phx.digest.clean",
  "tailwind my_app --minify",
  "bun my_app --minify",
  "phx.digest"
]

3. Set NODE_PATH for Phoenix Dependency Resolution

Set NODE_PATH to the project root's deps/ directory so Bun resolves Node-style packages from Phoenix's deps/ directory. Imports like import {Socket} from "phoenix" and import "phoenix_html" will resolve to the Elixir dependency packages without needing node_modules/.

In devenv.nix, this is already configured using an absolute path:

env.NODE_PATH = "${config.git.root}/deps";

For non-devenv setups, export it in your shell or build scripts:

export NODE_PATH="$(pwd)/deps"

No npm install or symlinks needed — Phoenix ships JS alongside its Elixir source in deps/<package>/priv/static/.

5. Configure runtime.exs for Binary Paths

In config/runtime.exs, read env vars so devenv-provided binaries are used instead of downloading copies. Both packages require explicit configuration:

if System.get_env("MIX_BUN_PATH") do
  config :bun, path: System.get_env("MIX_BUN_PATH")
end

if System.get_env("MIX_TAILWIND_PATH") do
  config :tailwind, path: System.get_env("MIX_TAILWIND_PATH")
end

When path is set, the hex packages skip downloading and use the provided binary directly. devenv sets these env vars via lib.getExe to point at the Nix store paths (see step 4).

6. Set Up devenv

See references/devenv-template.md for the full devenv.yaml and devenv.nix templates.

Key points:

  • lib.getExe resolves Nix store paths for MIX_BUN_PATH and MIX_TAILWIND_PATH
  • PostgreSQL runs via Unix socket only (listen_addresses = "") — no port conflicts
  • DATABASE_URL uses ?socket= parameter pointing to devenv's state directory
  • PGHOST is set so psql and Ecto both find the socket automatically

7. Configure Ecto for URL-based Connection

In config/dev.exs, support both Unix socket (devenv) and TCP (manual setup):

db_config =
  [
    username: System.get_env("POSTGRES_USER", "my_app_dev"),
    password: System.get_env("POSTGRES_PASSWORD", "my_app_dev"),
    database: System.get_env("POSTGRES_DB", "my_app_dev"),
    show_sensitive_data_on_connection_error: true,
    pool_size: 10
  ]
  |> then(fn config ->
    case System.get_env("PGHOST") do
      nil ->
        config ++ [hostname: System.get_env("POSTGRES_HOST", "localhost"),
                   port: String.to_integer(System.get_env("POSTGRES_PORT", "5432"))]
      pghost when is_binary(pghost) ->
        if String.starts_with?(pghost, "/") do
          config ++ [socket_dir: pghost]
        else
          config ++ [hostname: pghost,
                     port: String.to_integer(System.get_env("POSTGRES_PORT", "5432"))]
        end
    end
  end)

config :my_app, MyApp.Repo, db_config

This auto-detects whether PGHOST is a Unix socket path or a hostname.

8. Production Database via URL

In config/runtime.exs for prod:

if config_env() == :prod do
  database_url =
    System.get_env("DATABASE_URL") ||
      raise "DATABASE_URL is not set"

  config :my_app, MyApp.Repo,
    url: database_url,
    pool_size: String.to_integer(System.get_env("POOL_SIZE", "10"))
end

9. End-to-End Tests

E2e tests live in e2e_test/ alongside the standard test/ folder. They are expensive and must never run automatically — only on explicit request.

Add the test.e2e alias in mix.exs:

defp aliases do
  [
    # ... existing aliases ...
    "test.e2e": ["run --no-halt", "cmd mix test e2e_test/"]
  ]
end

Configure e2e_test/ as an extra test path in mix.exs project config so Mix finds the helpers, but exclude it from the default mix test run:

def project do
  [
    # ...
    test_paths: ["test"],
    elixirc_paths: elixirc_paths(Mix.env()),
  ]
end

Run e2e tests explicitly:

mix test.e2e

Never add test.e2e to CI pipelines, pre-commit hooks, or any automated alias that runs as part of a normal build or test cycle.

Quick Reference

ToolHex PackageEnv Vardevenv Source
Bun{:bun, "~> 1.4"}MIX_BUN_PATHlib.getExe pkgs.bun
Tailwind{:tailwind, "~> 0.2"}MIX_TAILWIND_PATHlib.getExe pkgs.tailwindcss_4
PostgreSQL{:ecto_sql, ...} + {:postgrex, ...}DATABASE_URL / PGHOSTservices.postgres

Comments

Markdown supported