Skip to content

Scaffold Next.js app with content pipeline and core pages#12

Open
BenWard wants to merge 10 commits intomainfrom
claude/jekyll-to-nextjs-migration-gLQbz
Open

Scaffold Next.js app with content pipeline and core pages#12
BenWard wants to merge 10 commits intomainfrom
claude/jekyll-to-nextjs-migration-gLQbz

Conversation

@BenWard
Copy link
Copy Markdown
Owner

@BenWard BenWard commented Mar 27, 2026

Summary

This PR establishes the foundation for migrating benward.uk from Jekyll to Next.js (App Router) with TypeScript. The new Next.js application reads content directly from the existing Jekyll _posts/ directory without duplication, implements a complete content rendering pipeline, and includes core pages and components with comprehensive test coverage.

Key Changes

Project Structure

  • Created new nextjs/ directory alongside existing jekyll/ directory
  • Configured TypeScript, Jest, and Next.js with App Router
  • Set up CSS modules and global styles with design tokens

Content Pipeline (lib/)

  • content.ts: Post loading, YAML frontmatter parsing, and rendering (Markdown via unified/remark/rehype, Textile via textile-js)
  • posts.ts: Post enrichment (clean URLs, GitHub source links, excerpt generation, title auto-generation for Tumblr imports)
  • archives.ts: Archive index generation with year/month grouping and navigation
  • dates.ts: Timezone-preserving date formatting (keeps ISO 8601 strings to preserve original offsets)
  • base60.ts: NewBase60 encoding for shortlink generation
  • shortlinks.ts: Shortlink resolution mapping base60 IDs back to post URLs
  • tag-id.ts: RFC 4151 tag URI generation for Atom feed
  • romans.ts: Roman numeral conversion for archive headers

Pages & Routes

  • app/page.tsx: Homepage with recent posts
  • app/blog/[slug]/page.tsx: Individual blog post pages
  • app/[year]/page.tsx: Year archive pages
  • app/[year]/[month]/page.tsx: Month archive pages
  • app/about/page.tsx, app/feeds/page.tsx, app/network/page.tsx: Static pages
  • app/feed.atom/route.ts: Atom feed generation
  • app/s/[id]/route.ts: Shortlink redirect handler
  • app/humans.txt/route.ts, app/robots.txt/route.ts, app/sitemap.xml/route.ts: SEO/metadata routes

Components

  • BlogPostLayout: Blog post template with metadata, sharing, and navigation
  • ArchiveYearLayout, ArchiveMonthLayout: Archive page templates
  • PostSummary: Post preview card
  • ArchiveNavigation: Previous/next period navigation
  • Cover, ArticleLayout: Page templates
  • Share, TwitterMeta, Identity, Profiles, Scripts: Metadata and utility components

Testing

  • Comprehensive test suites for all utility functions (dates, base60, archives, posts, content parsing)
  • Component tests for React components (Cover, PostSummary, ArchiveNavigation)
  • Rendering comparison tests verifying Next.js output matches Jekyll expectations
  • All new TypeScript code has colocated tests

Static Assets

  • Copied static files from Jekyll (images, CSS, project files like TCP Header diagram)
  • Configured public directory structure

Notable Implementation Details

  • No content duplication: Next.js reads directly from ../jekyll/_posts/ at runtime
  • Timezone preservation: Dates stored as ISO 8601 strings to maintain original timezone offsets (never converted to JS Date objects for display)
  • Server-side rendering: JIT (on-demand) rendering with dynamic = "force-dynamic" — no static export
  • Jekyll compatibility: Ports Jekyll plugins (jekyl_post.rb, archives.rb, liquid_standard_filters.rb, tag_id.rb, romans.rb) to TypeScript
  • Microformats support: h-entry, h-feed, h-card markup for semantic web compatibility
  • Shortlink system: Base60-encoded Unix timestamps resolve to post URLs

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA

claude added 10 commits March 26, 2026 18:09
Comprehensive plan covering content pipeline, app router structure,
component architecture, CSS modules strategy, and testing approach.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
Each component gets its own directory with colocated .tsx, .module.css,
.test.tsx, and index.ts barrel export.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
Complete migration of benward.uk from Jekyll to Next.js 15 with App Router.

Library layer (lib/):
- content.ts: Post loading from Jekyll _posts, Markdown + Textile rendering
- posts.ts: Post enrichment (clean URLs, GitHub links, auto-titles)
- archives.ts: Year/month archive grouping with pagination
- base60.ts: NewBase60 encoding for shortlinks
- romans.ts: Roman numeral conversion for footer copyright
- dates.ts: Timezone-preserving date formatting
- tag-id.ts: RFC 4151 tag URI generation for Atom feed

Components (components/):
- Each in own subdirectory with colocated .tsx, .module.css, .test.tsx, index.ts
- BlogPostLayout, ArchiveYearLayout, ArchiveMonthLayout, ArticleLayout
- Cover, PostSummary, Share, ArchiveNavigation, TwitterMeta, Scripts, etc.
- Full microformat fidelity (h-entry, h-card, h-feed, h-geo)

Routes (app/):
- /blog/[slug]: Blog posts with prev/next navigation
- /[year] and /[year]/[month]: Archive pages
- /about, /network, /feeds: Static pages from Jekyll content
- /feed.atom: Atom feed route handler with shortlinks
- /robots.txt, /sitemap.xml, /humans.txt: Metadata route handlers
- .html -> clean URL redirects in next.config.ts

CSS decomposed from single sixthree.css into:
- lib/global.css: Variables, resets, typography, microformat classes
- Per-component CSS Modules

Config in config/site.ts, not lib/.
77 tests passing across 11 test suites.
Next.js build compiles successfully.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
- Markdown post (top-5-2017): verifies frontmatter parsing, canonical URL,
  geo data, tags, enriched properties, date formatting matching Jekyll
  strftime, shortlink generation, tag URI, and rendered HTML (including
  raw HTML passthrough for iframes/figures)
- Textile post (simple_microformats): verifies textile rendering, atomid
  preservation, pre-2018 domain switching, timezone preservation
- humans.txt: line-by-line structure match against Jekyll template

128 tests passing across 13 suites.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
Replaces the Jekyll-generated short.yaml mapping file with a native
Next.js route that resolves base60-encoded shortlink IDs to post URLs.

- lib/shortlinks.ts: decodeBase60, buildShortlinkMap, resolveShortlink
- app/s/[id]/route.ts: redirects to canonical or clean URL
- Posts with canonical URLs (e.g. bff.fm) redirect there directly

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
- Replace jest, ts-jest, ts-node, jest-environment-jsdom with vitest
- Add @vitejs/plugin-react for JSX support in tests
- Replace jest.config.ts and tsconfig.test.json with vitest.config.ts
- Remove CSS mock files (vitest handles CSS modules natively)
- Update all 14 test files with vitest imports
- 135 tests passing across 14 suites

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
Runs vitest suite in the nextjs directory on pull requests
and pushes to main.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
Install npm-check-updates with upgrade scripts for dependency management.
Upgrade major versions: @types/node ^22→^25, typescript ^5→^6, next ^15→^16.
All 135 tests pass.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
@types/node@25 targets Node 25 which isn't LTS. Our runtime and CI
both use Node 22, so the types should match.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
Update @types/node to ^24 and CI workflow to node-version: 24.

https://claude.ai/code/session_01R5awpyXidcUMHNPPVAsLvA
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