{"id":18045288,"url":"https://github.com/dpb587/tailwind-config-reporter","last_synced_at":"2025-04-05T03:41:41.568Z","repository":{"id":226265608,"uuid":"768211406","full_name":"dpb587/tailwind-config-reporter","owner":"dpb587","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-06T18:56:17.000Z","size":37,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-02-10T11:48:27.000Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dpb587.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-03-06T17:09:23.000Z","updated_at":"2024-12-02T04:55:08.000Z","dependencies_parsed_at":"2024-03-06T19:00:02.257Z","dependency_job_id":"a79c0ed6-ccc3-483c-9ae1-56de241ccd70","html_url":"https://github.com/dpb587/tailwind-config-reporter","commit_stats":null,"previous_names":["dpb587/tailwind-config-reporter"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpb587%2Ftailwind-config-reporter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpb587%2Ftailwind-config-reporter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpb587%2Ftailwind-config-reporter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dpb587%2Ftailwind-config-reporter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dpb587","download_url":"https://codeload.github.com/dpb587/tailwind-config-reporter/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247284914,"owners_count":20913691,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-30T18:12:43.953Z","updated_at":"2025-04-05T03:41:41.551Z","avatar_url":"https://github.com/dpb587.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# tailwind-config-reporter\n\nSome unofficial scripts to try and analyze how people use [Tailwind CSS](https://tailwindcss.com/) (no affiliation). You can see the latest analysis results from the [`tailwind-config-dataset` repository](https://github.com/dpb587/tailwind-config-dataset). This is more of a utilitarian script approach, not some super efficient and elegant system. Here is the general process and more interesting components:\n\n* [customsearch](./customsearch) uses the GitHub API to discover public repositories and paths which contain Tailwind-related projects.\n* [worker](./worker) uses a Docker container to clone, install, and analyze a public git repository. A private container network restricts outbound access, and a [proxy](./worker-proxy/squid.conf) enables limited network access for well-known package installations with heavy local caching.\n  * [squash-package](./worker/squash-package.mjs) is used to try and only install dependencies needed to compile the `tailwind.config.*` file. If it fails, install tries again with the original `package.json` dependencies.\n  * [two](./worker/tailwind.config.exporter3.mjs) [methods](./worker/tailwind.config.exporter2.cjs) are used to try and export the `tailwind.config.*` file depending on the `tailwindcss` package being used. It is run for both a minimal config file to capture a baseline configuration, and then again with the user customizations.\n* [transformer](./transformer) runs additional analysis on the files and metadata captured by a worker.\n  * [tailwind-changes-analyzer](./transformer/tailwind-changes-analyzer) compares the baseline and effective Tailwind configurations to generate more meaningful records about what was customized.\n* [aggregator](./aggregator) collects all the transformed results into a SQLite database.\n  * [exporter](./aggregator/exporter) runs some common queries against the database and generates the Markdown data shown in the [`tailwind-config-dataset` repository](https://github.com/dpb587/tailwind-config-dataset).\n\nI'm not a particular expert in Tailwind nor Node+JavaScript's confusing matrix of toolchains and conventions, so there might be some odd assumptions. Many of these scripts and snippets are cobbled together from past work and experiments; your mileage may vary. My goal wasn't 100% Tailwind coverage and build success which seems difficult given the broad userspace nature. Plus this was just kind of an experiment. There are a few, repeated build and analysis errors that I think could still be resolved.\n\n## Rough Technical Notes\n\nProbably want to run this on a short-lived VM since it runs arbitrary-ish user code (even though it should be fairly secure within the Docker container). The following are needed:\n\n* [Go](https://go.dev/dl/) - for the repository search\n* [Docker](https://docs.docker.com/engine/install/) (or equivalent) - for running the proxy and worker\n* [jq](https://jqlang.github.io/jq/download/) - for much of the data transformations and utilities\n* [SQLite](https://sqlite.org/download.html) - must support extensions which may not be available in default OS packages\n* [sqlean](https://github.com/nalgeon/sqlean/releases) (expanded into `./mnt/sqlite/sqlean`) - SQLite extension for decoding values during import\n\nA local directory for tracking results...\n\n```\nmkdir -p mnt/dataset\n```\n\nBuild the container images, create the internal network, and run the proxy server...\n\n```\n./init.sh\n```\n\nRun a single analysis...\n\n```\n./worker/run-task-docker.sh github.com/tailwindlabs/headlessui main playgrounds/react\n#                           repository                        branch   [subdirectory]\n```\n\nOr query and then analyze a full list from GitHub...\n\n```\n( cd customsearch \u0026\u0026 GITHUB_API_TOKEN=a1b2c3d4... go run . )\n( echo '#!/bin/sh' ; jq -sr 'sort_by(.CachedData.StargazersCount) | reverse | map(select(.Valid))[] | . as $repo | .FileMatches // [] | map(select(.Valid))[] | @sh \"./worker/run-task-docker.sh \\($repo.Name) \\($repo.CachedData.DefaultBranchName) \\(.Path | split(\"/\")[0:-1] | join(\"/\"))\"' \u003c mnt/dataset/seed/github.jsonl ) \u003e run-github-seed.sh \u0026\u0026 chmod +x run-github-seed.sh\n./run-github-seed.sh\n```\n\nAfter running, compile all the captured analysis data...\n\n```\n./transformer/run.sh\n./aggregator/run.sh\n```\n\nGenerate and review the default Markdown reports...\n\n```\n./aggregator/exporter/run.sh\nopen ./mnt/dataset/analysis/README.md\n```\n\nManually access the data in the SQLite database and run custom queries...\n\n```\nsqlite3 mnt/dataset/aggregate/db.sqlite\n\u003e .tables\n\u003e .schema tailwind_changes\n```\n\nManually use a container for debugging...\n\n```\ndocker run \\\n  -it \\\n  --rm \\\n  --workdir /home/node \\\n  --network tailwind-config-reporter-worker \\\n  -e http_proxy=http://test:ok@172.18.0.2:3128 \\\n  -e HTTP_PROXY=http://test:ok@172.18.0.2:3128 \\\n  -e https_proxy=http://test:ok@172.18.0.2:3128 \\\n  -e HTTPS_PROXY=http://test:ok@172.18.0.2:3128 \\\n  tailwind-config-reporter-worker\n$ yarn config set httpProxy http://test:ok@172.18.0.2:3128\n$ yarn config set httpsProxy http://test:ok@172.18.0.2:3128\n```\n\n## Ideas\n\n* this only looks at the user-configuration, so it doesn't take into account what features actually end up being used; it might be interesting to have another step which generates the actual stylesheet (assuming content and files are present)\n  * related, tools which can reverse engineer a generated stylesheet and possibly content files to understand the effective Tailwind configuration that might have been used for it; seems like it'd be a more accurate reflection of usage\n* could probably add plugin support; there are some initial pieces, but I haven't really looked at the data and I think there are some cases where the baseline configuration doesn't currently capture enough about it\n* probably continue to run `customsearch` to further expand the dataset as GitHub activity and pagination changes expose more public sources\n* maybe extract additional metadata about values and CSS functions being used\n* a more complicated data solution would help surface individual repository examples behind some of the numbers; useful for investigating interesting configurations that stand out\n\n## License\n\n[MIT License](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpb587%2Ftailwind-config-reporter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdpb587%2Ftailwind-config-reporter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdpb587%2Ftailwind-config-reporter/lists"}