Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -233,3 +233,15 @@ url = Routes.url("/users/confirm/#{token}")

Features: versioned migrations, database tables prefix support, idempotent operations, PostgreSQL validation, production mailer templates.

### External module route discovery

Routes from external PhoenixKit modules (e.g., `phoenix_kit_entities`) are auto-discovered at compile time via `ModuleDiscovery` beam scanning. The host router automatically recompiles when module deps are added or removed — the `phoenix_kit_routes()` macro injects `__mix_recompile__?/0` into the host router with a hash of the discovered module set.

No manual config is needed. If auto-discovery fails, register route modules explicitly as a fallback:

```elixir
# config/config.exs
config :phoenix_kit,
route_modules: [PhoenixKitEntities.Routes]
```

14 changes: 14 additions & 0 deletions lib/phoenix_kit/module_discovery.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,20 @@ defmodule PhoenixKit.ModuleDiscovery do
Enum.uniq(scanned ++ configured)
end

@doc """
Returns a deterministic hash of the current set of discovered external modules.

Used by `__mix_recompile__?/0` (injected into the host router) to detect when
modules are added or removed, triggering router recompilation.
"""
@spec module_hash() :: binary()
def module_hash do
discover_external_modules()
|> Enum.sort()
|> :erlang.term_to_binary()
|> then(&:erlang.md5/1)
end

@doc """
Scans beam files of phoenix_kit-dependent apps for `@phoenix_kit_module` attribute.

Expand Down
13 changes: 13 additions & 0 deletions lib/phoenix_kit_web/integration.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1149,7 +1149,20 @@ defmodule PhoenixKitWeb.Integration do
# Auto-discovered public routes from external PhoenixKit modules
module_public_routes = compile_module_public_routes(url_prefix)

# Snapshot discovered modules so the host router auto-recompiles when deps change
current_hash = PhoenixKit.ModuleDiscovery.module_hash()
mix_lock_path = Path.expand("mix.lock")

quote do
# Recompile router when deps change (mix.lock is updated by mix deps.get)
@external_resource unquote(mix_lock_path)

# Precise check: only actually recompile if the set of PhoenixKit modules changed
@doc false
def __mix_recompile__? do
unquote(current_hash) != PhoenixKit.ModuleDiscovery.module_hash()
end

# Generate pipeline definitions
unquote(generate_pipelines())

Expand Down
Loading