Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
bcd6707
Support configuring version per profile
RobinBoers Apr 25, 2025
9f9a237
Rename back to `configured_version`
RobinBoers Apr 25, 2025
2669b81
Don't change default argument order
RobinBoers Apr 25, 2025
57b26bc
`configured_version` -> `configured_version!`
RobinBoers Apr 25, 2025
b300964
Collect & filter required versions before installing
RobinBoers Apr 25, 2025
087dd35
Update lib/tailwind.ex
RobinBoers Apr 25, 2025
c2c42c4
Update lib/tailwind.ex
RobinBoers Apr 25, 2025
dc5d41f
Filter profiles for keyword lists
RobinBoers Apr 25, 2025
f8bf6b9
Mark `@doc false` on `install/2`
RobinBoers Apr 25, 2025
eac9354
Improve documentation
RobinBoers Apr 25, 2025
f002055
Fix broken test
RobinBoers Apr 25, 2025
790a893
Fix flaky test
RobinBoers Apr 25, 2025
17436fd
Resolve merge conflicts
RobinBoers May 21, 2026
7115673
Fix wrong docstring
RobinBoers May 22, 2026
fec5d16
Move `config_keys` to module attribute
RobinBoers May 22, 2026
459d3ac
Make targets version-aware
RobinBoers May 22, 2026
c79c938
Refactor run function for performance
RobinBoers May 22, 2026
4faea82
Fix `mix tailwind.install` not working if no profiles are configured
RobinBoers May 22, 2026
cc80df1
Fix typo
RobinBoers May 22, 2026
7ab3784
Add docstring to `bin_version/1`
RobinBoers May 22, 2026
ad64d70
Fix hardcoded path in warning
RobinBoers May 22, 2026
cf5293a
Make `File.chmod!` also a bang
RobinBoers May 22, 2026
ea29b6d
Fix bug where computing `bin_path` on unsupported platforms crashes, …
RobinBoers May 22, 2026
913df53
Make `configured_target/1` private
RobinBoers May 22, 2026
1dd71d8
Refactor `configured_target/1` to be consistent with `configured_vers…
RobinBoers May 22, 2026
28d1de0
Raise on boot when `:path` is set and one or more profiles configure …
RobinBoers Jun 3, 2026
170bb6c
Update lib/tailwind.ex
SteffenDE Jun 3, 2026
7a4b934
Apply suggestion from @SteffenDE
SteffenDE Jun 3, 2026
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
105 changes: 76 additions & 29 deletions lib/mix/tasks/tailwind.install.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@ defmodule Mix.Tasks.Tailwind.Install do
@moduledoc """
Installs Tailwind executable and assets.

Usage:

$ mix tailwind.install TASK_OPTIONS BASE_URL

Example:

$ mix tailwind.install
$ mix tailwind.install --if-missing

Expand All @@ -15,9 +21,7 @@ defmodule Mix.Tasks.Tailwind.Install do
binary (beware that we cannot guarantee the compatibility of any third party
executable):

```bash
$ mix tailwind.install https://people.freebsd.org/~dch/pub/tailwind/v3.2.6/tailwindcss-freebsd-x64
```
$ mix tailwind.install https://people.freebsd.org/~dch/pub/tailwind/$version/tailwindcss-$target

## Options

Expand All @@ -36,44 +40,87 @@ defmodule Mix.Tasks.Tailwind.Install do

@impl true
def run(args) do
valid_options = [runtime_config: :boolean, if_missing: :boolean]

{opts, base_url} =
case OptionParser.parse_head!(args, strict: valid_options) do
{opts, []} ->
{opts, Tailwind.default_base_url()}
{opts, base_url} = parse_arguments(args)

{opts, [base_url]} ->
{opts, base_url}
if opts[:runtime_config] do
Mix.Task.run("app.config")
end

{_, _} ->
Mix.raise("""
Invalid arguments to tailwind.install, expected one of:
case resolve_versions(opts) do
[] -> :ok
versions -> install_versions(base_url, versions)
end
end

mix tailwind.install
mix tailwind.install 'https://github.com/tailwindlabs/tailwindcss/releases/download/v$version/tailwindcss-$target'
mix tailwind.install --runtime-config
mix tailwind.install --if-missing
""")
end
defp resolve_versions(opts) do
for {version, latest?} <- collect_versions(),
!(opts[:if_missing] && latest?) do
version
end
end

if opts[:runtime_config], do: Mix.Task.run("app.config")
defp install_versions(base_url, versions) do
ensure_install_ready()

if opts[:if_missing] && latest_version?() do
if Enum.all?(versions, &(Tailwind.install(base_url, &1) == :ok)) do
:ok
else
if function_exported?(Mix, :ensure_application!, 1) do
Mix.ensure_application!(:inets)
Mix.ensure_application!(:ssl)
end
:error
end
end

defp ensure_install_ready do
if function_exported?(Mix, :ensure_application!, 1) do
Mix.ensure_application!(:inets)
Mix.ensure_application!(:ssl)
end

Mix.Task.run("loadpaths")
Tailwind.install(base_url)
Mix.Task.run("loadpaths")
end

defp parse_arguments(args) do
case OptionParser.parse_head!(args, strict: schema()) do
{opts, []} ->
{opts, Tailwind.default_base_url()}

{opts, [base_url]} ->
{opts, base_url}

{_, _} ->
Mix.raise("""
Invalid arguments to tailwind.install, expected one of:

mix tailwind.install
mix tailwind.install 'https://github.com/tailwindlabs/tailwindcss/releases/download/v$version/tailwindcss-$target'
mix tailwind.install --runtime-config
mix tailwind.install --if-missing
""")
end
end

defp latest_version?() do
defp collect_versions do
case Tailwind.profiles() do
[] ->
[{Tailwind.configured_version(), latest_version?()}]

profiles ->
for {profile, _} <- profiles, uniq: true do
{Tailwind.configured_version(profile), latest_version?(profile)}
end
end
end

defp latest_version? do
version = Tailwind.configured_version()
match?({:ok, ^version}, Tailwind.bin_version())
end

defp latest_version?(profile) do
version = Tailwind.configured_version(profile)
match?({:ok, ^version}, Tailwind.bin_version(profile))
end

defp schema do
[runtime_config: :boolean, if_missing: :boolean]
end
end
Loading
Loading