Skip to content

feat(website): add comparison pages for other diff tools - #968

Merged
benvinegar merged 3 commits into
mainfrom
claude/hunk-comparison-seo-pages-7prw08
Sep 1, 2026
Merged

feat(website): add comparison pages for other diff tools#968
benvinegar merged 3 commits into
mainfrom
claude/hunk-comparison-seo-pages-7prw08

Conversation

@benvinegar

@benvinegar benvinegar commented Sep 1, 2026

Copy link
Copy Markdown
Member

The problem

People deciding on a terminal diff tool search "hunk vs delta", "hunk vs difftastic", "better git diff". hunk.dev had nothing to answer those queries, so the ranking went to third-party listicles that get Hunk wrong.

This adds a /compare/ section: a hub plus five head-to-head pages, at the URLs the questions are typed as.

Page Why this one
/compare/hunk-vs-delta/ The default answer to "better git diff"
/compare/hunk-vs-difftastic/ Different axis entirely, worth being honest about
/compare/hunk-vs-git-diff/ The head term
/compare/hunk-vs-diff-so-fancy/ High-volume legacy, still in a lot of dotfiles
/compare/hunk-vs-plannotator/ The closest direct competitor for reviewing agent output

Approach

Each page is one entry in website/src/data/comparisons.ts, rendered three ways: the HTML page, a Markdown variant at the same URL plus .md, and JSON-LD. One catalog means a capability mark cannot differ between what a reader sees and what a crawler reads.

Page shape is built for the reader who arrived from a "hunk vs X" query: the answer first, then a two-sided verdict, then the argument, then the capability table, then the questions that query implies.

For answer engines and agents. Every page carries TechArticle, FAQPage, and BreadcrumbList, with the capability table republished as additionalProperty on both products so the comparison is readable without inferring it from a <table>. The products are multi-typed ["SoftwareApplication", "Product"] because additionalProperty is outside SoftwareApplication's schema.org domain and a validator would otherwise drop the payload. Row notes are deliberately not published as either product's description: a note describes the row, so attaching it to one product prints claims about the other tool under this tool's name. Each page is also served as clean Markdown, linked with <link rel="alternate"> and surfaced in /llms.txt, matching what the docs already do for AI crawlers.

Editorial rule. Every mark comes from the other project's own documentation, with the caveat beside it wherever a bare mark would mislead, and rows the other tool wins stay in the tables. Tests enforce this rather than trusting it: a page that never recommends the other tool, concedes no capability, leaves a hedged mark unexplained, or cites no source from the rival's own host fails the suite.

Non-goals

  • Not a listicle or a "best diff tools" roundup. Five focused pages beat a thin sprawl.
  • No second-tier targets (lazygit, tig, vimdiff, GitHub PR review). Different search intent; adding them would dilute the cluster.
  • No change to any existing page's rendered output.

Incidental refactors

  • PageHead.astro extracts the <head> shared by the hand-built marketing pages, rather than adding a third copy. The emitted head for / and /extensions/ is byte-for-byte identical to before (verified against a build of the parent commit).
  • The JSON-LD serializer moves to website/src/lib/jsonLd.ts now that two catalogs use it. As a side effect the home page picks up <-escaping it previously lacked.
  • The Markdown renderer lives in website/src/lib/comparisonMarkdown.ts so it is unit-testable without pulling Astro's DOM types into the root TypeScript program.

Review process

Two Opus reviews ran against the first commit, one fact-checking rival claims against primary sources and one auditing the Hunk-side claims against this repo plus the code. bc66289 is the fixes; the notable ones:

  • diff-so-fancy computes character-level emphasis with a bundled copy of git contrib/diff-highlight. It does not pass through git --word-diff.
  • Plannotator toggles Split/Unified from its settings panel, polls for a moved working tree, exposes WebMCP tools on its plan and annotate surfaces, and has AI review built in. All four were marked absent, and the AI-review row was missing entirely.
  • diff.external is Git's external diff driver, not a difftool, and other subcommands then need --ext-diff.
  • delta's n/N are opt-in via navigate and move between files, and delta has its own theme collection beyond bat's syntax themes.
  • difftastic's performance caveat is under README "Known Issues", not a FAQ, and its manual lists many more languages than the README's "over 30".
  • git diff does have --word-diff / --color-words; the row was missing from the one table where Git is the subject.
  • On Hunk's own side: the "Runtime dependency" row was polarity-inverted and contradicted the install docs, --fast lost its "experimental" qualifier, and one row asserted a performance property nothing in the repo establishes. All fixed or dropped.

Verification

  • bun run typecheck, bun run lint, bun run format:check — clean
  • bun test scripts/ — 302 pass
  • cd website && bun run check — 0 errors; bun run build — 60 pages
  • Playwright, both viewport projects — 101 pass, 1 skipped, including axe (wcag2a/wcag2aa) across the hub and all five comparison pages

Not run: the TUI suites (test:integration, test:tty-smoke). This change touches no Hunk source, only website/ and three root test files.

Known limitations and follow-ups

  • Website unit tests live in root scripts/, not beside the code they cover. Colocation would be better, but nothing currently runs unit tests under website/src/: DEFAULT_TEST_PATTERNS in scripts/run-test-suite.ts does not include ./website, and the website workspace's only test script is Playwright with testDir: "./tests". Moving them today would silently drop the coverage. Doing it properly means wiring a Bun test runner into the website workspace plus a CI job — a separate change. The current placement follows the existing convention set by scripts/check-extension-catalog.test.ts, which tests website/src/data/extensions.ts the same way. (Raised by Greptile; discussed on that thread.)
  • The five pages share the generic og.png. Per-comparison OG images would be better; website/scripts/generate-og.ts already exists if that is worth a follow-up.
  • Rival claims are true as of the review date each page states. They will need re-checking as those projects move.

🤖 Generated with Claude Code

https://claude.ai/code/session_01NsaTD6RoPx9Q6sQobq9fFK

Adds a /compare/ cluster answering the "hunk vs X" query directly: a hub
plus head-to-head pages for delta, difftastic, diff-so-fancy, git diff,
and Plannotator.

Each page is one catalog entry rendered three ways, so the HTML page, the
`.md` variant agents read, and the structured data can never disagree
about a capability mark. The capability table is republished as
`additionalProperty` on both products in the page's TechArticle, which
lets an answer engine read the comparison without inferring it from a
`<table>`, and each page also carries FAQPage and BreadcrumbList data.

Marks come from each project's own documentation, with a note wherever a
bare mark would mislead, and rows the other tool wins are in the tables.
Tests enforce that: every page recommends the other tool for something,
concedes at least one capability, explains every hedged mark, and cites
its sources.

Also extracts the head shared by the hand-built marketing pages into
PageHead.astro rather than adding a third copy of it, and moves the
JSON-LD serializer to a shared module now that two catalogs use it.
Two Opus reviews of the comparison pages, one fact-checking the rival
claims against each project's own docs and one auditing the Hunk claims
and the code, turned up errors worth fixing before this ships.

Wrong about other projects:
- diff-so-fancy computes character-level emphasis with a bundled copy of
  git contrib/diff-highlight. It does not pass through git --word-diff.
- Plannotator toggles Split and Unified from its settings panel, polls
  the repo for a moved working tree, exposes WebMCP tools on its plan and
  annotate surfaces, and has AI review built in. All four were marked
  absent; the AI review row was missing entirely.
- `diff.external` is Git's external diff driver, not a difftool, and
  other subcommands then need --ext-diff.
- delta's n/N are opt-in via `navigate` and move between files, and delta
  has its own theme collection beyond bat's syntax themes.
- difftastic's performance caveat is under README "Known Issues", not a
  FAQ, and its manual lists far more languages than the README's "over 30".
- git diff does have word-level diffing (--word-diff, --color-words);
  the row was missing from the one table where Git is the subject.
- diff-so-fancy gets the same partial mark delta gets for pager-based VCS
  support, rather than a bare no for the same mechanism.

Wrong about Hunk:
- The "Runtime dependency" row was polarity-inverted against every other
  row and contradicted Hunk's own install docs. It is now "Runs with no
  language runtime installed", marked honestly.
- --fast is experimental everywhere else, so say so here.
- Dropped a "predictable cost on heavily-changed files" row that asserted
  a property nothing in the repo establishes.
- Hunk does open git log -p under `hunk pager`, so that is out of the
  blame/grep row, and saving preferences can write .hunk/config.toml.

Structured data:
- Row notes are no longer published as each product's `description`. A
  note describes the row, so attaching it to one product printed claims
  about the other tool under this tool's name.
- Products are multi-typed ["SoftwareApplication", "Product"] because
  additionalProperty is outside SoftwareApplication's schema.org domain
  and validators would have dropped the whole payload.
- Breadcrumbs carry a real trail, and datePublished no longer moves when
  claims are re-checked.

Also derives the title year from the review date, moves the Markdown
renderer to lib/comparisonMarkdown.ts so it is unit-testable without
pulling Astro's types into the root program, and shares SITE_ORIGIN and
Hunk's own language/license/platform facts instead of retyping them.

Tests now cover the Markdown renderer directly, and assert capability
names are unique, sources cite the rival's own host, the answer names
both tools, the title year tracks the review date, and no row note leaks
into the structured data.
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hunk-web Ready Ready Preview Sep 1, 2026 8:37pm UTC

Request Review

@greptile-apps

greptile-apps Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR adds a catalog-backed comparison section with five HTML pages, parallel Markdown endpoints, and structured data, while extracting shared marketing-page metadata helpers.

  • Adds the comparison catalog, hub, detail routes, styling, navigation, and browser coverage.
  • Generates HTML, Markdown, and JSON-LD representations from the same catalog.
  • Centralizes shared page-head and JSON-LD serialization behavior.
  • The new unit suites should be moved beside the website modules they test.

Confidence Score: 4/5

The PR appears safe to merge after the non-blocking unit-test colocation issue is addressed.

The comparison routes, shared renderers, metadata extraction, and documented CLI surfaces have no established functional regression; the remaining issue is the repository-required placement of two new unit suites.

Files Needing Attention: scripts/check-website-helpers.test.ts and scripts/check-comparison-catalog.test.ts

Important Files Changed

Filename Overview
website/src/data/comparisons.ts Defines the shared five-entry comparison catalog and support metadata consumed by all output formats.
website/src/pages/compare/[slug].astro Renders catalog entries as accessible HTML pages with JSON-LD, capability tables, FAQs, and sibling navigation.
website/src/lib/comparisonMarkdown.ts Produces agent-readable Markdown variants from the same catalog, including tables, sources, and cross-links.
website/src/components/PageHead.astro Centralizes canonical, social, icon, analytics, and safely serialized JSON-LD head markup without an established existing-page regression.
scripts/check-website-helpers.test.ts Adds useful helper and Markdown-renderer coverage but places unit tests outside the repository-required source colocation.
website/tests/compare-smoke.spec.ts Adds production-preview browser coverage for comparison routing, structured data, Markdown output, navigation, and accessibility.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  Catalog[Comparison catalog] --> HTML[HTML comparison pages]
  Catalog --> Markdown[Markdown endpoints]
  Catalog --> JSONLD[JSON-LD structured data]
  HTML --> Hub[Comparison hub and sibling links]
  PageHead[Shared PageHead component] --> HTML
  PageHead --> Home[Existing home page]
  PageHead --> Extensions[Existing extensions page]
Loading
Prompt To Fix All With AI
### Issue 1
scripts/check-website-helpers.test.ts:1-5
**Website unit tests are misplaced**

These suites directly test modules under `website/src/`, but they live in the unrelated root `scripts/` directory. Colocate this suite with the website helpers it covers, and likewise move `check-comparison-catalog.test.ts` beside the comparison catalog, so source changes and their unit coverage remain discoverable together.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Reviews (1): Last reviewed commit: "fix(website): correct comparison claims ..." | Re-trigger Greptile

Comment thread scripts/check-website-helpers.test.ts
`astro check` covers website/tests, so the destructured `({ name })`
callbacks added with the JSON-LD assertions failed noImplicitAny in CI.
Annotate the shape `evaluate` returns instead, which also documents what
the block is asserting about.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NsaTD6RoPx9Q6sQobq9fFK
@benvinegar
benvinegar merged commit 566220b into main Sep 1, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants