Skip to content

feat: rebuild dedede.ro in Astro 6 (parity-locked migration from Elde…#81

Open
ViorelMocanu wants to merge 2 commits into
mainfrom
feat/astro-rebuild
Open

feat: rebuild dedede.ro in Astro 6 (parity-locked migration from Elde…#81
ViorelMocanu wants to merge 2 commits into
mainfrom
feat/astro-rebuild

Conversation

@ViorelMocanu

Copy link
Copy Markdown
Owner

Summary

Re-platforms the live dedede.ro marketing site from Elder.js 1.7.5 + Svelte 3.57 + Rollup 2 to Astro 6 (SSG-first, TypeScript strictest, SCSS via sass-embedded, pnpm). This is a re-platform, not a redesign — the goal was pixel-, function-, and SEO-fidelity to production, proven by an automated parity oracle. Deploys to Cloudflare Workers (Static Assets) with the contact form as an Astro SSR endpoint backed by Resend.

Delivery is PR-only; nothing is auto-deployed. Full evidence is committed under parity/, and every check reproduces offline against the committed baseline (no live crawls).

Parity — all 6 Definition-of-Done criteria pass

Criterion Result
Route inventory 9/9 public URLs resolve identically (3 articles at root level); getStaticPaths pinned to exactly 3 slugs; 0 redirects
Visual parity 27/27 views ≤ 0.1% at mobile / tablet / desktop (max diff 0.082%)
Functional E2E 43 Playwright tests — nav hamburger, dark-mode (persist + no-flash), back-to-top, UTM population, contact form (success / validation / honeypot / dataLayer)
SEO / meta 0 regressions vs the live <head> (24 changes — all approved waivers); robots.txt identical; sitemap 9 URLs match
Quality gates pnpm verify 5/5 (format · lint · typecheck · 44 unit · e2e) · knip 0 unused · pnpm audit 0 high
Lighthouse + a11y rebuilt ≥ live on every route & category (perf 100, a11y 99, best-practices 100/96, SEO 100); axe 0 violations (live had 1 serious — fixed)

Full report + before/after/diff gallery: parity/REPORT.md.

What changed

  • Framework: Elder.js + Svelte + Rollup → Astro 6 (.astro components, zero UI-framework islands — no @astrojs/svelte, no @astrojs/mdx). All interactivity stays vanilla JS in public/resources/script.js.
  • Routing: 6 static .astro pages + index.astro + one [slug].astro catch-route whose getStaticPaths() allow-lists exactly the 3 root-level articles. trailingSlash: 'always', build.format: 'directory'.
  • Content: typed blog content collection; the bare date frontmatter is kept as z.string() (no coerce) to preserve article:published_time byte-for-byte.
  • Contact form: legacy sideform.php + SendGrid → Astro SSR endpoint src/pages/api/contact.ts (prerender = false) + Resend, with zod validation + a hidden honeypot. The form UI, AJAX flow, UTM hidden fields, GDPR box, and dataLayer events are preserved exactly (only the POST target changes).
  • Deploy: Cloudflare Workers + Static Assets via @astrojs/cloudflare (wrangler deploynot Pages).
  • Styling / assets: the deployed CSS ported to SCSS verbatim; legacy images copied byte-for-byte (passthroughImageService).
  • Harness: pnpm verify gate orchestrator, the offline parity oracle under parity/tools/, ESLint flat + Prettier + Vitest + Playwright + axe + Lighthouse + knip + husky/commitlint, plus AGENTS.md / CODING_PRINCIPLES.md / CONTEXT.md and ADRs under docs/.

Dependencies (pinned, security-vetted)

Runtime (5): astro · @astrojs/cloudflare · @astrojs/sitemap · resend · sass-embedded. (zod ships via astro:content / astro/zod.)
Dev (~20): typescript, @astrojs/check, eslint + plugins, prettier-plugin-astro, vitest, @playwright/test, @axe-core/playwright, sharp (build-host OG image only), wrangler, husky, commitlint, knip, @lhci/cli.

pnpm audit --audit-level=high is clean — a transitive tmp HIGH was remediated via a pnpm override (→ 0.2.7); 2 dev-only moderates remain, off the production graph.

Redirects

None — all 9 public URLs are byte-identical between the legacy site and the rebuild. (Any future URL change requires its own ADR + a 301.)

Approved deviations (7 waivers)

The rebuild is byte/pixel-exact except for these intentional, documented changes (register: parity/WAIVERS.md):

  • SEO-01..05 — drop the placeholder @TODO twitter handles · absolute article og:image · og:type=article on articles · normalize /cookies/ og:description to name= · sitemap <lastmod> + drop deprecated rel=prev/next + manifest start_url.
  • ASSET-01 — replace the 0-byte og-image.jpg with a real branded 1200×630 image (fixes broken social sharing on home + the 3 legal pages).
  • VISUAL-01 — fix the homepage .ServiceText .Highlight WCAG-AA contrast violation (scheme-aware; stays ≤ 0.1% so it needs no pixel-threshold exception).

How to verify locally

pnpm install
pnpm verify                 # 5/5 gates: format · lint · typecheck · unit · e2e
pnpm build                  # -> dist/client/ (+ the Worker in dist/server)

# offline parity oracle (no live crawl, diffs against the committed baseline):
node parity/tools/serve-static.mjs --root dist/client --port 4321 &
node parity/tools/capture-baseline.mjs --base http://localhost:4321 --out parity/after --label after
node parity/tools/diff-screens.mjs --a parity/baseline/screenshots --b parity/after/screenshots   # 27/27 <= 0.1%
node parity/tools/diff-meta.mjs   --a parity/baseline/meta        --b parity/after/meta            # 0 regressions
node scripts/lh-compare.mjs        # Lighthouse: rebuilt vs the live /livesite snapshot

Before merge / deploy (out-of-repo prerequisites)

  • Bind RESEND_API_KEY / RESEND_FROM / CONTACT_TO in Cloudflare (Preview and Production) and verify the Resend sender domain. A missing binding is a runtime 500 on the contact form, not a build error.
  • Deploy with wrangler deploy (Workers), not wrangler pages deploy. astro preview is unsupported by the Cloudflare adapter — serve dist/client/ via parity/tools/serve-static.mjs for local preview.

Out of scope (deliberately deferred to protect parity)

A cookie-consent banner (confirmed absent on the live site — analytics fire unconditionally on the 6 non-legal routes, matching live) and SVGO optimization of the large servicii.svg / hero SVG.


Built in 36 hours via Claude Opus 4.8 Ultracode on semi-auto mode.

@ViorelMocanu ViorelMocanu self-assigned this Jun 2, 2026
@ViorelMocanu ViorelMocanu added bug Something isn't working documentation Improvements or additions to documentation enhancement New feature or request dependencies Pull requests that update a dependency file labels Jun 2, 2026
Comment thread parity/tools/blocked-hosts.mjs Fixed
Comment thread parity/tools/blocked-hosts.mjs Fixed
Comment thread parity/tools/blocked-hosts.mjs Fixed
Comment thread parity/tools/blocked-hosts.mjs Fixed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants