Skip to content

Latest commit

 

History

History
359 lines (277 loc) · 16.5 KB

File metadata and controls

359 lines (277 loc) · 16.5 KB

WordPress To Astro Migration

This document records the business and engineering case for moving jseverino.com from WordPress to Astro. The migration was not only a visual or framework change. It changed the operating model of the site: fewer moving parts, less public attack surface, lower transfer weight, and a repository that can be reviewed as the source of truth for what ships.

Executive Summary

The WordPress version proved that the content model worked: project writeups, portfolio taxonomy, images, and SEO metadata were already valuable. The issue was the platform overhead required to serve mostly static content.

Astro was selected because the public site does not need runtime page rendering, database-backed routing, comments, uploads, a public admin panel, or visitor accounts. Static output gives the same reader experience with a smaller operational surface.

The result is a site that is easier to operate and easier to audit:

Decision Drivers

Driver WordPress Site Astro Site
Public runtime PHP, WordPress, theme, plugins, database Static files on Cloudflare Pages
Admin surface Public WordPress admin path unless externally protected No public admin application
Plugin risk Plugin/theme code executes in the public origin No production plugin runtime
Content source Database plus theme/plugin behavior Markdown snapshot generated from the private vault
Image delivery Large PNG screenshots from uploads Responsive AVIF/WebP plus optimized fallbacks
Reviewability Runtime behavior spread across WordPress, plugins, database, and theme Public repo contains the build source and generated content snapshot
Deployment Origin application and database must remain healthy Static deploy artifact can be rebuilt and redeployed

Architecture Change

Before:

Browser -> Cloudflare -> WordPress origin -> PHP runtime -> database -> theme/plugins -> uploaded media

After:

Private vault -> sync script -> Astro static build -> Cloudflare Pages -> browser

Cloudflare still sits at the edge, but its role is narrower. It serves static assets, applies headers, runs a small HTML middleware for CSP nonces and reporting, and handles the contact form endpoint plus the CSP report endpoint. Non-production Pages deployments also carry a read-only sitedrift review layer for visual and SEO comparison against the live site. It no longer fronts a public WordPress page renderer.

May 2026 Migration Comparison

On May 24, 2026, a focused migration comparison was conducted between the production Astro site and the legacy WordPress origin. The goal was not to prove that every synthetic score improved. The goal was to verify the migration decision with measurable signals: transferred bytes, request count, response time, security posture, and codebase reviewability.

Measurements used:

  • Safari Network panel captures for real browser transfer behavior.
  • Lighthouse 13.3.0 JSON output for repeatable lab metrics.
  • curl timing for document-level response checks.
  • A locally captured legacy HAR for historical worst-case WordPress transfer.

Synthetic Lighthouse scores are treated as supporting evidence only. They are sensitive to Cloudflare challenge scripts, analytics behavior, cache state, viewport, and network conditions.

Case Study: Custom Detection Engine Writeup

This case study compares the live load performance of the same article on both platforms.

  • Legacy: https://wp.jseverino.com/portfolio/architecting-a-custom-detection-engine/
  • Current: https://jseverino.com/portfolio/architecting-a-custom-detection-engine/
Measurement Legacy WordPress Current Astro
Lighthouse requests 19 13
Lighthouse total byte weight 1.16 MB 476 KB
Dominant payload PNG screenshots AVIF screenshots
Largest Lighthouse image 343 KB PNG 42.5 KB AVIF
First-party failures 0 0

This Lighthouse article run showed approximately a 58.9% total byte-weight reduction:

(1.16 MB - 476 KB) / 1.16 MB = 58.9%

The historical HAR benchmark below represents a larger worst-case legacy load, where the WordPress page pulled many full-size PNG screenshots. The live Lighthouse comparison is the more conservative number; the HAR comparison shows why the image pipeline was still an important architecture decision.

Historical Worst-Case Benchmark

The old HAR contained 20 PNG image transfers totaling 18.42 MB. That represents the uncached cost of the legacy site:

Legacy asset Transfer
vigilant-2048x1464.png 1.97 MB
main_file-2-2048x1362.png 1.53 MB
phptest-2048x1312.png 1.46 MB
SEM_hardening-2048x1362.png 1.35 MB
install-2-2048x1424.png 1.32 MB

Case Study: Homepage Migration Baseline

The homepage serves as the primary entry point and showcases the site's core identity. The May 24, 2026 migration baseline already showed the Astro homepage shipping less JavaScript, less total payload, faster first paint, stronger accessibility, and better SEO than the legacy WordPress homepage.

Measurement Legacy WordPress Astro migration baseline
Lighthouse requests 25 16
Lighthouse total byte weight 1.15 MB 610 KB
Lighthouse First Contentful Paint 1.1 s 0.8 s
Lighthouse Accessibility 96 100
Lighthouse SEO 85 92

That baseline was before the final homepage polish. The current PageSpeed snapshot below shows the homepage after those fixes: 100 Performance, 100 Accessibility, 100 Best Practices, and 100 SEO on both mobile and desktop. The WordPress homepage remains useful as a comparison point, but the article comparison is more representative of the migration's asset-pipeline win because portfolio writeups carry the largest image payloads.

Codebase Profile

The Astro site maintains a lean footprint, making the entire system easy to audit and maintain. Unlike the legacy WordPress site—where the "code" is distributed across a database, plugins, and a theme—the current application and infrastructure source is concentrated in a small set of repository files.

Layer Language / Type Lines of Code
Business Logic TypeScript / MJS ~1,600
Templating Astro ~700
Styles Vanilla CSS ~1,300
Infrastructure SQL / Config ~500
Generated Data JSON (Image Manifest) ~4,900

The majority of the project's "weight" is actually deterministic metadata generated by the image pipeline. The handwritten logic is compact, focusing entirely on content rendering, responsive assets, and edge security.

Server Response and Security

Beyond asset weight, the migration improved raw delivery speed and security posture by removing the PHP/database dependency.

Metric Legacy WordPress Current Astro
Document TTFB, homepage (curl) ~0.83 s ~0.26 s
Document TTFB, article (curl) ~0.96 s ~0.34 s
Script Security 'unsafe-inline' required Nonce-based CSP
Origin Surface Public PHP/MySQL Static Edge

The observed TTFB improvement comes from replacing dynamic PHP/database page rendering with static edge delivery. Exact response timing varies with cache state, Cloudflare routing, and client network conditions, so these numbers should be treated as a snapshot rather than a permanent guarantee. Additionally, the move to a nonce-based Content Security Policy significantly reduces the site's script-injection risk, a level of protection that was difficult to maintain with WordPress's dependency on inline scripts.

Lighthouse Notes

Lighthouse is useful for the current Astro site, but it is sensitive to the deployment environment. A common pitfall when measuring either the legacy WordPress site or a protected Astro staging environment is Cloudflare Access. If Access is active for the target origin, Lighthouse will measure the performance and weight of the Access login challenge rather than the actual site content.

Use Lighthouse for current-site regression checks:

lighthouse \
  https://jseverino.com/portfolio/architecting-a-custom-detection-engine/ \
  --output=json \
  --output-path=/tmp/jseverino-astro-lighthouse.json \
  --quiet \
  --chrome-flags="--headless --disable-gpu"

Measurement Caveats

When performing automated measurements, verify that the origin is reachable without a challenge. During the May 24, 2026 audit, Cloudflare Access was temporarily disabled to ensure the results reflected the actual site content rather than the login challenge. An "Access-blocked" measurement typically shows:

  • Inaccurate LCP: The login challenge scripts can push Largest Contentful Paint well beyond 5 seconds.
  • Payload mismatch: The byte weight and request count will reflect the Cloudflare Access application, not the Astro build.
  • False signals: Accessibility and SEO scores will be based on the login template.

The May 24, 2026 Astro article baseline reported:

Metric Value
Accessibility 98
SEO 100
First Contentful Paint 1.0 s
Largest Contentful Paint 5.2 s
Cumulative Layout Shift 0
First-viewport total byte weight 476 KiB
First-viewport network requests 13

This article baseline is intentionally kept as a migration artifact: it records the payload reduction at the time the WordPress-to-Astro decision was validated. Later homepage-specific PageSpeed results are stronger, but they measure a different surface. Read together, the evidence is cleaner: the migration made the heavy writeup pages dramatically smaller, and subsequent homepage polish brought the primary entry point to perfect PageSpeed category scores.

Current PageSpeed Snapshot

After the post-migration polish, Google PageSpeed Insights reported perfect category scores for the live homepage on May 27, 2026 at 9:14 PM CDT. This is the current headline benchmark for the production site:

Mode Performance Accessibility Best Practices SEO FCP LCP TBT CLS Speed Index
Mobile, emulated Moto G Power / Slow 4G 100 100 100 100 0.9 s 1.8 s 0 ms 0 1.4 s
Desktop, emulated desktop / custom throttling 100 100 100 100 0.3 s 0.5 s 0 ms 0 0.4 s

The PageSpeed run used Lighthouse 13.3.0 against https://jseverino.com/. The Best Practices panel passed the trust-and-safety checks for effective CSP, strong HSTS, and Trusted Types mitigation, which confirms the security headers did not come at the cost of Lighthouse-visible UX or compatibility regressions. Compared with the May 24 homepage baseline, the current run raises SEO from 92 to 100 while keeping Accessibility at 100 and adding 100 Best Practices and 100 Performance scores on both throttled mobile and desktop profiles.

Security And Operations Impact

The migration removes entire classes of work from production operations:

  • no WordPress core update window for the public site;
  • no public plugin/theme execution path;
  • no database-backed page rendering for ordinary readers;
  • no public upload endpoint;
  • no public comment or account surface;
  • no live admin panel required for publishing.

The remaining dynamic pieces are narrow and explicit:

Operational Shift

The most significant change is the move from a "Live Admin" model to a "Private-First" content model. In WordPress, content was authored and stored within the public origin's database. In the Astro architecture, the public site is a read-only snapshot of a private editorial system.

  • Content Isolation: The Vault Workflow ensures that only sanitized, public-ready content is synced to the repository. Sensitive metadata and draft content remain entirely outside the public surface.
  • Tooling Independence: Editorial work is performed in a local vault using native tools (VS Code, Obsidian) rather than a browser-based CMS, removing latency and session-management overhead.
  • Atomic Deploys: Because the site is built from a deterministic content snapshot, every deploy is a verifiable artifact that can be rolled back or audited in the repository history.

Pre-flight Validation

The migration replaced manual WordPress maintenance (plugin updates, theme checks, security scanning) with automated quality gates. Before any content update is published, the site is validated against the project's engineering standards.

The publish:check script acts as the final gate:

npm run publish:check

On a typical run (observed May 24, 2026), this validates:

  • Integrity: Zero TypeScript errors and zero Astro check warnings.
  • Scale: Successful build of 70+ pages and 500+ optimized images.
  • Optimization: Image weight limits (ensuring no individual asset exceeds 1.5 MB).

This shift moves the operational burden from "monitoring a live runtime" to "verifying a static build," resulting in a more resilient and predictable site.

Business Outcome

The business decision is that the site should optimize for trust, speed, maintainability, and auditability rather than CMS convenience. WordPress was a reasonable starting point while the content model was evolving. Astro is a better fit now that the site is primarily a polished portfolio and technical writing archive.

The migration improves the reader experience while reducing operational complexity. It also turns the site itself into a portfolio artifact: the public repo demonstrates static architecture, secure headers, CSP handling, content sync design, responsive image processing, and measurable performance gains.

Measurement Artifacts

The legacy HAR used for the comparison was captured locally as:

/Users/josephseverino/Desktop/wp.jseverino.com.har

It is not committed to the repo because HAR files can contain response bodies, tokens, cookies, headers, and local browsing context. The summarized values in this document are the public-safe output of that measurement.

Useful local extraction commands:

jq '.log.entries | length' /path/to/file.har

jq '[.log.entries[] | (.response._transferSize // .response.bodySize // 0) | select(. > 0)] |
  {known_transfer_bytes: add, known_transfer_mb: (add/1048576), counted_entries: length}' \
  /path/to/file.har

jq -r '.log.entries[] |
  select((.response._transferSize // .response.bodySize // 0) > 0) |
  [((.response._transferSize // .response.bodySize) | tostring), .response.content.mimeType, .request.url] |
  @tsv' /path/to/file.har | sort -nr | head -15

Related Documentation