Packages
phoenix_kit
1.7.206
1.7.207
1.7.206
1.7.205
1.7.204
1.7.203
1.7.202
1.7.201
1.7.200
1.7.199
1.7.198
1.7.197
1.7.196
1.7.194
1.7.193
1.7.192
1.7.191
1.7.190
1.7.189
1.7.187
1.7.186
1.7.185
1.7.184
1.7.183
1.7.182
1.7.181
1.7.180
1.7.179
1.7.178
1.7.177
1.7.176
1.7.175
1.7.174
1.7.173
1.7.172
1.7.171
1.7.170
1.7.169
1.7.168
1.7.167
1.7.166
1.7.165
1.7.164
1.7.162
1.7.161
1.7.160
1.7.159
1.7.157
1.7.156
1.7.155
1.7.154
1.7.153
1.7.152
1.7.151
1.7.150
1.7.149
1.7.146
1.7.145
1.7.144
1.7.143
1.7.138
1.7.133
1.7.132
1.7.131
1.7.130
1.7.128
1.7.126
1.7.125
1.7.121
1.7.120
1.7.119
1.7.118
1.7.117
1.7.116
1.7.115
1.7.114
1.7.113
1.7.112
1.7.111
1.7.110
1.7.109
1.7.108
1.7.107
1.7.106
1.7.105
1.7.104
1.7.103
1.7.102
1.7.101
1.7.100
1.7.99
1.7.98
1.7.97
1.7.96
1.7.95
1.7.94
1.7.93
1.7.92
1.7.91
1.7.90
1.7.89
1.7.88
1.7.87
1.7.86
1.7.85
1.7.84
1.7.83
1.7.82
1.7.81
1.7.80
1.7.79
1.7.78
1.7.77
1.7.76
1.7.75
1.7.74
1.7.71
1.7.70
1.7.69
1.7.66
1.7.65
1.7.64
1.7.63
1.7.62
1.7.61
1.7.59
1.7.58
1.7.57
1.7.56
1.7.55
1.7.54
1.7.53
1.7.52
1.7.51
1.7.49
1.7.44
1.7.43
1.7.42
1.7.41
1.7.39
1.7.38
1.7.37
1.7.36
1.7.34
1.7.33
1.7.31
1.7.30
1.7.29
1.7.28
1.7.27
1.7.26
1.7.25
1.7.24
1.7.23
1.7.22
1.7.21
1.7.20
1.7.19
1.7.18
1.7.17
1.7.16
1.7.15
1.7.14
1.7.13
1.7.12
1.7.11
1.7.10
1.7.9
1.7.8
1.7.7
1.7.6
1.7.5
1.7.4
1.7.3
1.7.2
1.7.1
1.7.0
1.6.20
1.6.19
1.6.18
1.6.17
1.6.16
1.6.15
1.6.14
1.6.13
1.6.12
1.6.11
1.6.10
1.6.9
1.6.8
1.6.7
1.6.6
1.6.5
1.6.4
1.6.3
1.5.2
1.5.1
1.5.0
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.10
1.2.9
1.2.8
1.2.7
1.2.5
1.2.4
1.2.2
1.2.1
1.2.0
1.1.0
1.0.0
A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more
Current section
Files
Jump to
Current section
Files
lib/mix/tasks/compile.phoenix_kit_css_sources.ex
defmodule Mix.Tasks.Compile.PhoenixKitCssSources do
@moduledoc """
Mix compiler that auto-generates CSS @source directives for PhoenixKit modules.
Discovers external modules via `PhoenixKit.ModuleDiscovery`, calls `css_sources/0`
on each, resolves their paths, and writes `assets/css/_phoenix_kit_sources.css`.
The parent app's `app.css` imports this file.
Zero-config: add a module with `css_sources/0` and it gets picked up automatically.
## Setup
Add to your `mix.exs` compilers list:
compilers: [:phoenix_kit_css_sources, :phoenix_live_view] ++ Mix.compilers()
And import the generated file in `assets/css/app.css`:
@import "./_phoenix_kit_sources.css";
"""
use Mix.Task.Compiler
require Logger
@generated_file "assets/css/_phoenix_kit_sources.css"
@impl true
def run(_args) do
deps = Mix.Project.config()[:deps] || []
source_lines =
PhoenixKit.ModuleDiscovery.discover_external_modules()
|> Enum.flat_map(fn mod ->
if Code.ensure_loaded?(mod) and function_exported?(mod, :css_sources, 0) do
mod.css_sources()
else
[]
end
end)
|> Enum.uniq()
|> Enum.sort()
|> Enum.map(&format_source(&1, deps))
maybe_warn_zero_sources(source_lines)
content = """
/* Auto-generated by PhoenixKit — do not edit manually.
Regenerated on each compilation from css_sources/0 callbacks. */
#{Enum.join(source_lines, "\n")}
"""
path = Path.join(File.cwd!(), @generated_file)
existing =
case File.read(path) do
{:ok, data} -> data
_ -> nil
end
if existing != content do
File.mkdir_p!(Path.dirname(path))
File.write!(path, content)
Mix.shell().info(
"[PhoenixKit] Updated #{@generated_file} with #{length(source_lines)} source(s)"
)
end
{:ok, []}
end
# A silent empty file is the worst failure mode of CSS auto-discovery: the host's
# admin UI loses every responsive/variant utility from the dep with no error. When
# we emit zero @source lines but phoenix_kit-dependent deps are present on disk,
# surface it loudly so it isn't a multi-hour CSS mystery.
defp maybe_warn_zero_sources([]) do
self = Mix.Project.config()[:app]
case PhoenixKit.ModuleDiscovery.phoenix_kit_dependent_apps() -- [self, :phoenix_kit] do
[] ->
:ok
apps ->
Mix.shell().error(
"[PhoenixKit] #{@generated_file} generated with 0 @source lines, but found " <>
"phoenix_kit-dependent dep(s): #{inspect(apps)}. Their Tailwind classes will " <>
"NOT be compiled — responsive/variant utilities used only inside those deps " <>
"will be missing from the bundle. Ensure each module implements css_sources/0, " <>
"or set `config :phoenix_kit, modules: [...]` as a fallback."
)
end
end
defp maybe_warn_zero_sources(_), do: :ok
# Absolute paths are emitted verbatim — prepending `../../` would
# produce `@source "../..//abs/path";` which Tailwind can't resolve
# reliably. Relative paths stay relative to the generated file at
# `assets/css/_phoenix_kit_sources.css` (two levels up to project root).
# String entries from css_sources/0 — treated as literal paths (abs or rel).
defp format_source(entry, _deps) when is_binary(entry), do: source_for_path(entry)
# Atom entries — resolved via parent app's mix.exs deps.
defp format_source(entry, deps) when is_atom(entry) do
app_name = to_string(entry)
case find_dep_path(entry, deps) do
{:path, path} -> source_for_path(path)
:hex -> "@source \"../../deps/#{app_name}\";"
:not_found -> "@source \"../../deps/#{app_name}\";"
end
end
defp source_for_path("/" <> _ = abs_path), do: "@source \"#{abs_path}\";"
defp source_for_path(path), do: "@source \"../../#{path}\";"
defp find_dep_path(app_name, deps) do
dep =
Enum.find(deps, fn
{name, opts} when is_list(opts) -> name == app_name
{name, _version} -> name == app_name
{name, _version, opts} when is_list(opts) -> name == app_name
_ -> false
end)
case dep do
{_, opts} when is_list(opts) ->
if path = Keyword.get(opts, :path), do: {:path, path}, else: :hex
{_, _version, opts} when is_list(opts) ->
if path = Keyword.get(opts, :path), do: {:path, path}, else: :hex
{_, _version} ->
:hex
nil ->
:not_found
end
end
end