Skip to content

Update README.md to highlight the fix of compatibility with next.js 15 + turbopack - #86

Open
fawzy0z wants to merge 1 commit into
timlrx:mainfrom
fawzy0z:patch-1
Open

Update README.md to highlight the fix of compatibility with next.js 15 + turbopack#86
fawzy0z wants to merge 1 commit into
timlrx:mainfrom
fawzy0z:patch-1

Conversation

@fawzy0z

@fawzy0z fawzy0z commented Jun 12, 2025

Copy link
Copy Markdown

Update README.md to highlight the fix of compatibility with next.js 15 + turbopack

JasonSooter added a commit to JasonSooter/jasonsooter.com that referenced this pull request Aug 16, 2026
Replaces contentlayer2 with velite. This unblocks Next 16 and removes a
dependency that has been abandoned twice.

## Why now

contentlayer2 is unmaintained:

- **no commits since 2025-05-03** (15 months)
- 24 open issues, no maintainer replies
- PR `timlrx/contentlayer2#86` — *"fix of compatibility with next.js 15
+ turbopack"* — open since June 2025
- issue #89 (Jan 2026) reports a critical production build failure,
unanswered
- the upstream template (same maintainer) is **active** yet still pinned
to Next 15 + contentlayer2 0.5.8

It had become a hard ceiling: **Next 16 blocked** (#266), **eslint v10
blocked transitively** (#256), and the OpenTelemetry advisories in `npm
audit` reachable only through its tree. This is the second abandonment
in this lineage — #240 moved off contentlayer 0.3.4 for the same reason.

## pliny is kept

Its contentlayer2 dependency is **types-only** —
`node_modules/pliny/utils/contentlayer.js` has no contentlayer import;
only the `.d.ts` references its types. pliny operates on plain objects,
so the search palette, newsletter, comments and utils all stay.

## Shape is preserved deliberately

`body` stays `{ raw, code }` rather than being flattened. **pliny's
`coreContent()` omits `body` wholesale** — hoisting `code` to the top
level would serialise every post's compiled MDX into every listing page.
`_id` and `_raw` are reproduced for the same reason: `coreContent` omits
and types against them.

## MDXLayoutRenderer could not be reused

It builds the component with `new Function('React', 'ReactDOM',
'_jsx_runtime', code)`, passing React first — contentlayer's format.
Velite emits:

```js
const { Fragment, jsx, jsxs } = arguments[0]
...
return { default: Component }
```

`components/MDXContent.tsx` does that instead, and **stays a server
component** like pliny's was. Marking it `'use client'` puts an RSC
boundary between the page and the `components` map, which React refuses
to serialise (*"Functions cannot be passed directly to Client
Components"*).

## Two behaviours the build would not have caught

Both were caught by the regression bar, not by compilation:

**Citations silently vanished.** Velite parses frontmatter itself, so
`remarkExtractFrontmatter` never populates `vfile.data` and
`rehype-citation` could not discover the per-post `bibliography` field.
The rendering check from #271 failed on `.csl-entry` — the exact class
of failure it was written for. The single site-wide bibliography is now
passed directly.

**Drafts leaked into tag counts.** Velite runs *before* `next build`, so
`NODE_ENV` was unset and the production draft filter did not apply —
`software-development` came out as 2 instead of 1. The build now runs
velite with `NODE_ENV=production`.

## A pre-existing broken image, surfaced

Velite resolves linked assets and failed on
`you-are-the-local-source-for-gratitude-reminders.mdx`, which referenced
`./Sooter_Family_3.jpg` relatively while the file lives under
`public/static/images/`. **contentlayer passed it through unresolved**,
so the deployed page has been shipping `src="./Sooter_Family_3.jpg"` and
404ing that image. The other four images in that post were already
absolute. Fixed.

## The payoff

Removing `withContentlayer` — plus the dead `@svgr/webpack` loader and
its `next.config.js` webpack block, since **nothing imports an SVG** —
clears the last webpack config:

```
▲ Next.js 15.5.23 (Turbopack)
✓ Compiled successfully in 4.3s
✓ Generating static pages (32/32)
```

That was *the* Next 16 blocker.

## Test Plan — verified against `main`

- [x] 32 static pages; 27 generated routes with a **byte-identical set**
- [x] `app/tag-data.json` differs from `main` by exactly one tag —
`software-development: 1 → 2` — because `700cc92` published the
rendering-reference fixture. Verified no other tag changed.
- [x] Rendering check green (9 features, 9 style couplings)
- [x] Draft handling verified both ways: while `draft: true` the fixture
404d and stayed out of listings, RSS and tag counts; after `700cc92` set
it live it renders, and appears in listings and RSS as expected
- [x] `npm run lint` and `npx prettier --check .` clean
- [x] `next build --turbopack` succeeds
- [x] Direct dependencies 44 → 42
- [x] Preview deploy reviewed — and now more useful, since `700cc92`
published the rendering fixture, so previews render math, code blocks
and citations directly
- [x] `npm run analyze` fixed to generate velite output first (review
feedback); `serve` deliberately unchanged

## Follow-ups

The Renovate hold on `next` (#273) can be revisited once this lands —
Next 16 still needs its own upgrade PR, but the blocker is gone. The
`pliny/*` tsconfig workaround from #270 may also be removable.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: functionalStoic <7215306+functionalStoic@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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.

1 participant