Packages
phoenix_kit
1.7.113
1.7.208
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] || []
# Ensure all dep applications are loaded for module discovery
for dep <- Mix.Dep.cached() do
Application.ensure_loaded(dep.app)
end
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))
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
# 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