Tailwind interpolation from macro output

The Tailwind library says that it does not support interpolation Link. I have use case that demands that purging be done after some macros have dynamically generated/selected classes.

Is there a way for me to access compiled eex files and modules provide the contents to the Tailwind purger when compiling the css?

The CI flow would look like:

  1. Compile Elixir app
  2. Access macro generated module and compiled eex views
  3. Compile tailwind
  4. Build a release?


Since nobody responded so far… I can’t say much / anything about accessing compiled Elixir (maybe it’s a known fact that all strings remain intact there) but I wonder if that’s really the best way to achieve what you need.

Normally what one has to pass to Tailwind’s purging process is a set of files, where it can do a regex search and find full class names for keeping in the final CSS. Dynamic string interpolation doesn’t work because there it can’t match full class names. Dynamic selection does work though and that’s what I’d look closer at.

If still in your case you don’t / can’t select classes at runtime but for some reasons really have to do it at compile time (and purge everything what doesn’t make it into output as opposed to keep the complete set of possible ones) then I’d probably look at having the build process output a sort of “index file(s)” with full names of finally selected classes and feeding this to Tailwind’s purge task. Not that I’ve done that myself though :wink:


Dynamic selection would not work in my case. I am building a DSL to mimic elm-ui with Tailwind as my css library. Nothing fancy, I just need to be able to think in rows and columns instead of divs.

The goal is to be able to type something like:

column [Padding.all 4, Height.fill, Spacing.xy 10 10] do
    text "Hello"
    text "World"

and have it compile into something like:

<div class="p-4 h-full space-x-10 space-y-10">

I have had some success today with generating module attributes from macros. I don’t like the approach though. In a perfect world, Padding.all 4 would be replaced with {:class, "p-4"} at compile time. Instead, I get an ast. Need to brush up on my metaprogramming. I tried

defmodule Padding do
    defmacro all(padding) when is_integer(padding) do 
        quote do: "p-#{unquote(padding)}"

Moving the unquote outward solved the issue.

This produces the full class name:

defmodule Padding do
    defmacro all(padding) when is_integer(padding) do 
        quote do: unquote("p-#{padding}")

That means problem 1 is solved. My code generates full class names. I still need to use the compiled module for my tailwind purge.

This mix plugin lets me decompile my built modules.
The challenge now is how to purge based on those files.
Maybe I can hard code view files for now as I test whether the whole DSL thing would work in practice.

Thanks @silverdr, I think I will take this approach once I validate the general idea.

Maybe I can:

  • steal code from decompile to access the contents of my views
  • save these files somewhere
  • tell Tailwind to look there before purging

All this because divs have no clear layout semantics :man_facepalming:. ElmUI, SwiftUI and Flutter have spoiled me.