Skip to content

Instantly share code, notes, and snippets.

@thiagomajesk
Last active August 8, 2022 20:43
Show Gist options
  • Save thiagomajesk/d6bb0672b786bc5aa656d897bb68de99 to your computer and use it in GitHub Desktop.
Save thiagomajesk/d6bb0672b786bc5aa656d897bb68de99 to your computer and use it in GitHub Desktop.
Finds unused CSS classes in HTML files using Elixir
# (!) This is a first-effort/ naive script to find unused CSS in HTML files.
# This should (hopefully) work as the opposite of what you get from PURGE CSS.
# Configure the variables bellow and execute the file with `elixir purge_html_css.exs`.
# Configures the default location to look for the outputed CSS.
# Ideally this file should not be transformed to preserve new lines.
outputed_css = "priv/static/css/app.css"
# Configures the default pattern to look for files that may contain CSS to purge.
# Currently inculdes .eex and .heex files. Change this if necessary.
contents_glob = "lib/*_web/**/*.*ex"
map_out_classes = fn line ->
~r|\.(?<class>[a-z0-9-]+)\s*|
|> Regex.scan(line, capture: [:class])
|> List.flatten()
end
outputed_classes =
outputed_css
|> File.stream!()
|> Stream.flat_map(map_out_classes)
|> Stream.uniq()
|> Enum.to_list()
map_file_classes = fn line ->
~r|class="(?<class>[a-z0-9-\s]+)"|
|> Regex.scan(line, capture: [:class])
|> List.flatten()
|> Enum.flat_map(&String.split/1)
end
# Only reads N amount of lines concurrently at a time (one task per line)
task_opts = [max_concurrency: 50, on_timeout: :kill_task]
file_classes =
contents_glob
|> Path.wildcard()
|> Stream.flat_map(&File.stream!(&1))
|> Task.async_stream(map_file_classes, task_opts)
|> Stream.flat_map(fn
{:ok, classes} -> classes
{:exit, :timeout} -> []
end)
|> Stream.uniq()
|> Enum.to_list()
IO.puts(Enum.join(file_classes -- outputed_classes, "\n"))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment