This repository was archived by the owner on Oct 13, 2026. It is now read-only.
Repository navigation
feat(seo): Open Graph card, trailing-slash links, search-language titles - #31
Merged
Merged
Conversation
GitHub Pages serves dist/<slug>/index.html at <slug>/ and 301-redirects the slash-less form. The markdown link resolver only added the slash when a link ended in .md, so seven built links redirected: `(cli)` and `(./cli)` in mcp, schema and sdk, `(schema#version-compatibility)` in downstream, `(python-sdk)` and `(visualizer)` on the home page, and `(tutorials/refract-ui)` in visualizer. rewriteLink now resolves every relative link to a page (cli, ./cli, cli/, cli.md, ../index.md) to the page's trailing-slash URL. A path whose last segment has a file extension (.svg, .png, .ipynb) is an asset and keeps its form. Links with any URL scheme, such as mailto:, are left alone; before, only http(s) links were. Tests: - a built-site test fails if any internal link, including the canonical URL, points at a directory without the trailing slash; - unit tests cover rewriteLink's page, asset and external cases. build.mjs now builds only when run as a script, so tests can import it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No page had an og:image, and the PNGs in docs/assets are placeholders. The build now renders dist/social-card.png: the site icon and "Refract", the positioning line, and the site address, in the colors from assets/style.css. It is drawn from SITE_NAME and SITE_DESCRIPTION, so the card changes when the positioning line does. Every page's head gets og:image (absolute URL), og:image:width, og:image:height, og:image:alt, and twitter:card summary_large_image. social-card.mjs renders an SVG with @resvg/resvg-js. The site's font stack starts with system-ui, which resolves to the reader's OS face (SF Pro, Segoe UI) and cannot be redistributed in an image, so the card uses Roboto, the stack's OFL-licensed face, from @expo-google-fonts/roboto. System fonts are never loaded, so every machine renders the same PNG. The description is word-wrapped by measuring it in that font; a description too long for the card fails the build instead of clipping. Tests cover the head tags on every page, the published PNG's size, line wrapping, SVG escaping, and the overflow error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI only ran the build, so the link, SEO and docs tests ran only where a contributor ran them by hand. It now runs `npm run lint` and `npm test` before the build, which makes the redirect check a merge gate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The lockfile listed only the darwin-arm64 builds of @biomejs/biome, rolldown (Vitest's bundler) and lightningcss. `npm ci` on Linux therefore installed no Biome or Rolldown binary, and `npm run lint` and `npm test` failed there. CI passed only because it ran nothing but the build. The entries for those three packages were re-resolved with `npm install --package-lock-only`. Biome (2.5.15) and Rolldown (1.0.2) keep their versions and gain their other platform builds. lightningcss moves from 1.32.0 to 1.33.0, within Vite's ^1.32.0 range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Titles come from each page's H1, so these H1s now use the words people search for: - mcp: "MCP — Model Context Protocol" becomes "Wikipedia & MediaWiki revision-history MCP server". The server's tools analyze any MediaWiki page's revisions. - tutorials/wikipedia-history: "Tutorial: Track changes on a Wikipedia page" becomes "Track changes to a Wikipedia article over time". - compare: "Refract vs. Wikipedia's page history" becomes "Wikipedia history tools compared". The intro names the tools the page compares and the question each answers. Each claim about another tool was checked against that tool's documentation, and the page now links it: - page history: the history page links WikiBlame for finding text; reverts are tagged; each revision has a permanent link and an API SHA-1; the watchlist can send email. The page had said "manual", "screenshots are the only record" and "no" for these; - XTools and Who Wrote That? rows added; - WikiBlame split from WhoColor: it searches revisions for the one that added or removed a text, not "visual diff highlighting"; - WikiWho is token-level provenance, including deletions and reinsertions; - Wikimedia Enterprise sells access to a service, not a licence, and has free access. The <title> element is now escaped like the other head values, since the MCP title contains "&". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
zz-plant
marked this pull request as ready for review
October 8, 2026 21:53
This was referenced Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Follow-up to #30. A crawl of the published site found three problems:
og:image;This PR fixes all three. It also makes CI run lint and tests, so the redirect check gates merges. For those to run on Linux, the lockfile had to record the Linux builds of three native packages.
Changes
Open Graph card (
social-card.mjs,build.mjs)dist/social-card.png, 1200×630, about 49 KB. The PNG is a build output, not a committed file; after deploy it is at https://refract-org.github.io/refract-docs/social-card.png.--bg-deepbackground (#07090f):--accentteal, then "Refract" in bold white;--text, word-wrapped to three lines;--border-strongrule, thenrefract-org.github.io/refract-docsin--text-muted.SITE_NAMEandSITE_DESCRIPTION, so it changes when the positioning line changes. A description too long for the card fails the build instead of being clipped.system-ui, which resolves to the reader's OS face (SF Pro, Segoe UI); neither may be redistributed in an image. The card uses Roboto, the stack's OFL-licensed face. It is loaded from@expo-google-fonts/roboto, and system fonts are never loaded, so every machine renders the same PNG.@resvg/resvg-jsturns an SVG into the PNG in about 70 ms per build. Both new packages are devDependencies.npm test. Platforms also printog:titlebeside the image.Trailing-slash links (
build.mjsrewriteLink)GitHub Pages serves
dist/<slug>/index.htmlat<slug>/and 301-redirects<slug>. The resolver added the slash only to links ending in.md, so these seven links redirected:mcp[CLI reference](cli)schema,sdk(./cli)downstream(schema#version-compatibility)index(python-sdk),(visualizer)visualizer(tutorials/refract-ui)rewriteLinknow resolves every relative link to a page (cli,./cli,cli/,cli.md,../index.md) to the page's trailing-slash URL..svg,.png,.ipynb) is an asset and keeps its form.mailto:, are left as written. Before, onlyhttp(s)links were.Retitles
Each
<title>comes from the page's H1, so these H1s changed:/mcp//tutorials/wikipedia-history//compare/analyzeandexporttools take anapiparameter, the base URL of any MediaWiki API. That makes "Wikipedia & MediaWiki" accurate. The description is unchanged: it still comes from the first paragraph.Corrections on the compare page
Each claim about another tool was checked against that tool's documentation, and the page links it.
The closing line no longer says the page history lacks hashed exports and monitoring.
CI and lockfile
ci.ymlran onlynpm run build. It now runsnpm run lintandnpm testfirst.Cannot find module '@biomejs/cli-linux-x64/biome'. On main,package-lock.jsonlists only the darwin-arm64 builds of@biomejs/biome,rolldown(Vitest's bundler) andlightningcss. Sonpm cion Linux installs no Biome or Rolldown binary, and lint and tests cannot run there.npm install --package-lock-only, and the lockfile now lists every platform's build.lightningcssmoves from 1.32.0 to 1.33.0 (released 2026-07-20), within Vite's^1.32.0range.Tests
28 new tests; 103 in total, up from 75.
tests/links.test.ts). Fails if any internal link in the built site points at a directory without the trailing slash. Absolute links to the published site, such as the canonical URL, count as internal.rewriteLink: unit tests for page, asset and external links.build.mjsnow builds only when run as a script, so tests can import it.tests/seo.test.ts):og:image, its width, height and alt, andtwitter:cardon every page.<title>element is now escaped (the MCP title contains&); every&in the head outside scripts starts a character reference.<title>;twitter:cardset tosummary;og:image;Verification
npm run lint: no errors. The 3 warnings are the existingnoDescendingSpecificityones inassets/style.css.npm test: 4 files, 103 tests pass.npm ci, lint, tests and build on Ubuntu, and all pass.npm run build: 53 pages, plusdist/social-card.png(PNG, 1200×630, 8-bit RGBA, 49,509 bytes). Rebuilding produces the same bytes.href,srcandcontentURLs. None redirects or is missing./refract-docs/clireturns 301 to/refract-docs/cli/.Not in this PR
refract-docs-*.pngscene images indocs/assets/are still there, along withsource.svg,scripts/generate-scenes.tsandcheck-assets.ts. No page references them, and removing them is a separate decision.🤖 Generated with Claude Code