defmodule Mix.Tasks.Npm.Size do
@shortdoc "Show node_modules size analysis"
@moduledoc """
Analyze `node_modules` disk usage.
mix npm.size
mix npm.size --top 10
Shows total size, file count, and per-package breakdown.
## Options
* `--top` — number of largest packages to show (default: 10)
"""
use Mix.Task
alias NPM.NodeModules
@impl true
def run(args) do
{opts, _, _} = OptionParser.parse(args, strict: [top: :integer])
top_n = Keyword.get(opts, :top, 10)
dir = "node_modules"
total_size = NodeModules.disk_size(dir)
total_files = NodeModules.file_count(dir)
Mix.shell().info("node_modules analysis:")
Mix.shell().info(" Total size: #{NPM.FormatUtil.format_size(total_size)}")
Mix.shell().info(" Total files: #{total_files}")
packages = NodeModules.installed(dir)
Mix.shell().info(" Packages: #{length(packages)}")
if packages != [] do
Mix.shell().info("\n Top #{top_n} by size:")
print_top(dir, packages, top_n)
end
end
defp print_top(dir, packages, top_n) do
packages
|> Enum.map(fn name ->
pkg_dir = Path.join(dir, name)
size = NodeModules.disk_size(pkg_dir)
{name, size}
end)
|> Enum.sort_by(fn {_, size} -> -size end)
|> Enum.take(top_n)
|> Enum.each(fn {name, size} ->
Mix.shell().info(" #{NPM.FormatUtil.format_size(size)} #{name}")
end)
end
end