Skip to content

chore(web): upgrade docs site to astro 7 - #59845

Open
rekram1-node wants to merge 1 commit into
devfrom
docs-astro-7
Open

rekram1-node wants to merge 1 commit into
devfrom
docs-astro-7

Conversation

@rekram1-node

Copy link
Copy Markdown
Contributor

I moved the docs site (packages/web) from Astro 5 to Astro 7, matching packages/posts and services/www.

Versions

Package Before After
astro 5.7.13 7.3.8 (now in the root catalog, shared with posts and www)
@astrojs/starlight 0.34.3 0.41.11 (catalog)
@astrojs/cloudflare 12.6.3 14.1.4 (same as posts and www)
@astrojs/solid-js 5.1.0 7.1.0
@astrojs/markdown-remark 6.3.1 7.3.2 (same as www)
@astrojs/check 0.9.6 0.9.11

Starlight stays on 0.41.11 on purpose. 0.42 makes Tabs, Steps and FileTree parse HTML with Sätteri at render time, and Sätteri can't run in workerd, so the server bundle fails to build. The Starlight maintainers recommend staying on 0.41.11 for Cloudflare until that's fixed: withastro/starlight#4194

Config and code changes

  • markdown.rehypePlugins → markdown.processor: unified({ rehypePlugins }). Astro 7 uses Sätteri for Markdown by default, so remark/rehype plugins need the unified processor.
  • content.config.ts imports z from astro/zod; Astro 6 deprecated z from astro:content.
  • Cloudflare adapter:
    • configPath: process.env.SST_WRANGLER_PATH. SST's cloudflare.Astro component checks for this line on Astro 6+ and won't deploy without it. During sst deploy it points the build at the wrangler config SST generates, with nodejs_compat and the worker vars.
    • prerenderEnvironment: "node". Adapter 13+ prerenders in workerd by default. The theme hands its headerLinks option to its components through globalThis, which only works if pages prerender in the same Node process as the config. Without this, the header links disappear from every page. This also matches how Astro 5 prerendered.
  • config.json and tui.json are now written to dist/client/, the new assets directory, so they're still served at /config.json and /tui.json.
  • s/[id].astro: the share page's page-wide is:global styles ended up in a stylesheet shared with 91 docs pages (all the ones that use Tabs). The rule that hides the first content panel then removed the page title on those pages. I moved the styles into an inline <style is:inline> inside the page. I also reset the top margin that Starlight 0.36+ adds before client islands, so the share page stays where it was.
  • Hero.astro uses entry.id instead of entry.slug, which is no longer on Starlight's entry type. No page sets hero, so this doesn't change any output.
  • .wrangler/ is gitignored; the adapter now creates it during builds.

Theme

toolbeam-docs-theme@0.4.8 is the latest release. Its peer ranges are still astro ^5.7.13 and @astrojs/starlight ^0.34.3. Its code works unchanged with Astro 7 and Starlight 0.41: it uses the config:setup hook, astro/zod and Starlight's virtual modules, and its mobile menu CSS still matches 0.41's markup. Because the peers don't match, bun recorded a nested Astro 5 and Starlight 0.34 tree for it in bun.lock. I added astro and @astrojs/starlight to the root catalog and to overrides (the same pattern as solid-js), so the theme's peers resolve to the workspace versions. posts and www now use astro: "catalog:" too, so the version lives in one place. A patch wouldn't help: bun resolves peers from the registry manifest, not from patched files.

Deploy

The docs still deploy via sst.cloudflare.x.Astro in infra/app.ts, and I didn't change anything there. Adapter 14 produces dist/server/entry.mjs, dist/server/wrangler.json and dist/client/ instead of dist/_worker.js and dist. SST 4.13.1 already detects this layout: it reads dist/server/wrangler.json and deploys entry.mjs with dist/client as the assets. _routes.json is gone. SST ignored it before because Workers static assets don't use it, so routing doesn't change. The first real check is the dev deploy after merge.

Verification

  • bun run build in packages/web succeeds, both plain and with SST_WRANGLER_PATH pointing at a wrangler config shaped like the one SST writes (nodejs_compat, vars). Warnings match the old build apart from one new info-level Starlight warning (Entry docs → 404 was not found), and the 404 page renders the same.
  • I bundled dist/server/entry.mjs with esbuild using the conditions SST uses for workers (workerd, worker, browser). It resolves everything; the only imports left unbundled are node built-ins and cloudflare:workers.
  • Routes: the old and new builds produce the same 595 HTML pages and the same static files. The only differences are _routes.json (dropped), _headers and .assetsignore (added by the adapter).
  • HTML text of all 595 pages compared after stripping scripts and styles. Remaining differences come from Starlight or Expressive Code updates: localized "Terminal window" labels, new Thai UI strings, updated de/es/tr strings, an x-default hreflang link, tab IDs like tab-0-1, and one French heading ID that now keeps a trailing hyphen. Nothing links to that heading.
  • I served the old build with wrangler dev and the new one with astro preview, and compared them with Playwright screenshots at 1440px and 390px:
    • pages: home, config, a Japanese page with tabs, providers, an Arabic page, 404, the mobile menu open, and a share page backed by a mock API
    • all are pixel-identical except a few pixels of CJK/kerning shift on two lines, from Starlight's new font stack
  • /docs/config.md, /config.json and /tui.json return 200 on the preview; /docs/s/<id> renders through the worker.
  • astro dev serves /docs/, /docs/config/, /docs/ja/ and /docs/config.md.
  • astro check: 17 errors before, 17 after. The new Hero.astro type error is fixed; the rest already existed.
  • bun install --frozen-lockfile passes. In the lockfile, the only packages added or removed belong to the docs site's dependency tree. The other changed lines are bun moving shared packages up or down a level after Astro 5's dependencies left; each consumer resolves the same version as before.
  • bun run build in packages/posts still passes with astro: "catalog:".

@opencodejr opencodejr Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The upgrade looks sound. I ran bun install and bun run build in packages/web on the PR head and both succeed. The build writes the new dist/server + dist/client layout that SST reads, and config.json and tui.json end up in dist/client/. I also checked that the share page's hide-first-panel rule no longer appears in any shared _astro stylesheet, and that the theme's header links still render with prerenderEnvironment: "node". I didn't test an actual deploy; as you note, the dev deploy after merge is the real check.

Public API: unchanged. This is a docs-site build change, and the SST_WRANGLER_PATH it reads is set by SST's own Astro component.

One small point inline: the Hero.astro check can never match the home page now.

import Lander from './Lander.astro';

const { slug } = Astro.locals.starlightRoute.entry;
const { id } = Astro.locals.starlightRoute.entry;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

entry.id is the collection ID, so the root page's ID is "index", never "" ([...slug].md.ts also looks up the root as "index"). If a page ever sets hero, the Lander won't render. Starlight's route slug is Astro.locals.starlightRoute.id, which is "" for the root, so that's probably the right replacement for the old slug. Nothing uses hero today, so the output doesn't change.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Starlight normalizes this one: Astro.locals.starlightRoute.entry goes through normalizeCollectionEntry(), which maps an ID of "index" to "" (utils/routing/index.ts, normalizeIndexSlug). So for the root page entry.id is "", the same as the old entry.slug. [...slug].md.ts sees "index" because it calls getCollection directly and skips that step. entry.id also keeps the old behavior for localized roots (ja/index.mdx gives "ja") and for fallback pages, where route.id would be the localized slug. So I left it as is.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tabs / Steps / FileTree parse HTML at render time via Sätteri, breaking non-Node SSR runtimes (Cloudflare workerd)

1 participant