chore(deps): consolidate Dependabot updates - #986
Conversation
Folds 3 of the 4 open Dependabot PRs into one change: Next 16, eslint-config-next 16 and the postcss transitive. Next 16 removed 'next lint', so the lint script runs eslint directly against a flat config - eslint-config-next 16 provides one natively, replacing .eslintrc.json. eslint 10 (#984) stays open: eslint-plugin-react, via eslint-config-next, does not support it yet. Closes #985
Resolve manifest/lockfile conflicts from Dependabot PRs that auto-merged into master after this PR was opened (#987 @hono/node-server, #988 prettier, #990 @slidev/cli, #991 @next/bundle-analyzer). Took master's versions for all four (none was a target of this PR); kept the Next 16 major, eslint-config-next 16, the .eslintrc.json -> eslint.config.mjs migration and the 'next lint' -> 'eslint .' script change. Lockfile re-derived from master's. Also assign the flat config to a named const before exporting, so eslint.config.mjs no longer trips import/no-anonymous-default-export on itself. Lint output is now at parity with master (81 warnings, 0 errors). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
SociableSteve
left a comment
There was a problem hiding this comment.
The migration itself holds up. I reproduced it locally against the merge base (origin/master @ 7cdae00) and can confirm:
npm ciis clean, so the lockfile and the manifest agree. Resolved: next 16.3.1, eslint-config-next 16.3.1, eslint 9.39.2, react 19.2.8, top-level postcss 8.5.23.- No package in the tree is downgraded (I diffed every entry in both locks), and
npm audittotals go down, 16 to 13, with high going 9 to 6. npm run buildsucceeds on Turbopack, all 14 pages/routes build, andnpm run devserves/, the step-01, step-08, step-09 and step-10 solution pages and/api/movieswith 200s. The Next surface this repo touches is tiny (onlynext/documentand@next/bundle-analyzer), so nothing removed in Next 16 is actually used.- The flat-config migration does not silently drop rules. I ran
eslint --print-configon the same file on both sides (eslintrc withESLINT_USE_FLAT_CONFIG=falseon master, flat config here): 47 enabled rules before, 62 after. Nothing lost, no severity downgrades, and 15 rules gained (the react-hooks v6 set plus@next/next/no-location-assign-relative-destination). That is the outcome you want from this kind of migration and it is worth calling out explicitly. - Bonus:
eslint --cache --fixin the lint-staged hook was actually broken on master (eslint 9 could not find a flat config, so the pre-commit hook errored). This PR fixes that as a side effect.
Three things I would like addressed before merge, all consequences of the bump rather than mistakes in it.
| // "next/core-web-vitals". | ||
| const config = [ | ||
| { | ||
| ignores: ['.next/**', 'out/**'] |
There was a problem hiding this comment.
ignores is missing the slidev build output, and this makes npm run lint fail.
This is the one place where swapping next lint for eslint . changes what gets walked. next lint only ever descended into app, pages, components, lib and src. eslint . walks the whole tree, so anything generated at the repo root is now in scope unless it is listed here.
npm run slides:build writes to dist/ (vite's default build.outDir, and .github/workflows/deploy.yml publishes publish_dir: dist). dist is also absent from .gitignore, so it is neither git-ignored nor eslint-ignored. Reproduced on this branch:
$ npx eslint . ; echo $?
✖ 81 problems (0 errors, 81 warnings)
0
$ npm run slides:build && npx eslint . ; echo $?
dist/assets/modules/shiki-DeTF74yl.js
3:4441 error Component definition is missing display name react/display-name
✖ 82 problems (1 error, 81 warnings)
1
So any developer who builds the slides and then lints gets a hard lint failure inside a generated third-party bundle. CI happens to be safe because it lints a fresh npm ci tree that has no dist, which is exactly why this will not be caught until someone hits it locally.
Suggest:
ignores: ['.next/**', 'out/**', 'dist/**']Adding dist to .gitignore in the same pass would be worth it too, though that gap predates this PR.
There was a problem hiding this comment.
Fixed in 7cedc24. ignores is now ['.next/**', 'out/**', 'dist/**'], and dist added to .gitignore in the same commit (git check-ignore -v dist -> .gitignore:13:dist).
Reproduced your failure first, on this branch before the change:
$ npx eslint . ; echo $?
✖ 81 problems (0 errors, 81 warnings)
0
$ npm run slides:build && npx eslint . ; echo $?
/home/.../react-patterns-workshop/dist/assets/modules/shiki-DeTF74yl.js
3:4441 error Component definition is missing display name react/display-name
✖ 82 problems (1 error, 81 warnings)
1
Same file, same hash, same rule. git status also showed ?? dist/ and git check-ignore dist exited 1, confirming it was neither git-ignored nor eslint-ignored.
After the change, with dist/ present from a real npm run slides:build:
$ npm run slides:build ; echo $?
0
$ npm run lint ; echo $?
✖ 81 problems (0 errors, 81 warnings)
0
Back to 81/0 and exit 0. I also added a comment above the ignores array explaining why the array exists at all, since the reason (eslint . walking the whole tree where next lint did not) is not obvious from the file.
| "clsx": "^2.1.1", | ||
| "modern-normalize": "^3.0.1", | ||
| "next": "^15.5.21", | ||
| "next": "^16.3.0", |
There was a problem hiding this comment.
Next 16 makes next dev write two untracked files into every attendee's clone.
This is new behaviour in 16, not something 15.5.21 did. node_modules/next/dist/server/lib/generate-agent-files.js does not exist in next 15.5.21 and does in 16.3.1. I ran npm run dev on this branch and got:
✓ Generated AGENTS.md and CLAUDE.md for AI agents. Set `agentRules: false` in next.config to disable.
followed by git status showing:
?? AGENTS.md
?? CLAUDE.md
Neither is in .gitignore (git check-ignore returns nothing for both), and the same run on master produces a clean tree. That matters more here than in a normal app: this is a teaching repo, so every attendee who runs npm run dev gets two mystery files at the root, and the AGENTS.md preamble even tells the reader Next will keep re-adding the block and that committing it "keeps the tree clean", which is exactly the wrong instinct for a workshop repo.
Pick one and do it deliberately: set agentRules: false in next.config.js, or add AGENTS.md and CLAUDE.md to .gitignore, or commit them on purpose. Leaving it undecided is the bad option.
There was a problem hiding this comment.
Decided: agentRules: false in next.config.js, in 7cedc24. For a workshop repo that is the option that leaves nothing to explain to attendees — no mystery root files, and nothing gitignored that a reader then has to go looking for.
Confirmed the behaviour on both sides before changing it. node_modules/next/dist/server/lib/generate-agent-files.js exists in 16.3.1, and npm run dev on this branch printed:
⚠ `images.domains` is deprecated in favor of `images.remotePatterns`. ...
✓ Generated AGENTS.md and CLAUDE.md for AI agents. Set `agentRules: false` in next.config to disable.
with git status then showing:
?? AGENTS.md
?? CLAUDE.md
After the change, the same npx next dev run logs only ✓ Ready in 271ms — no "Generated AGENTS.md" line, no deprecation warning (that is the separate fix from your other comment) — and git status --short shows only the three files this commit modifies. Nothing generated, tree clean.
| "build": "next build", | ||
| "start": "next start", | ||
| "lint": "next lint", | ||
| "lint": "eslint .", |
There was a problem hiding this comment.
Nit, but it belongs in this PR since it is new noise introduced by the bump. Next 16 now emits on every dev and build:
⚠ `images.domains` is deprecated in favor of `images.remotePatterns`. Please update next.config.js to protect your application from malicious users.
I confirmed the warning is absent from the 15.5.21 build on master, so the migration is what surfaces it. next.config.js has images: { domains: ['image.tmdb.org'] }, which converts to:
images: {
remotePatterns: [{ protocol: 'https', hostname: 'image.tmdb.org' }]
}A persistent deprecation warning on a projector during a workshop is worth 3 lines to remove.
Separately, two small corrections for the PR description so it matches what actually resolves: top-level postcss lands at 8.5.23, not 8.5.26 (8.5.26 is the copy nested under vite, and it was already there on master), and the installed eslint-plugin-react is 7.37.2, not 7.37.5. Neither changes the conclusion about #984 being correctly deferred, the plugin still declares no eslint 10 support.
Also, "npm run lint: 0 problems on the new flat config" is not what it does: it is 81 warnings and 0 errors. That is identical to master's next lint output, so it is not a regression, but the claim as written is wrong.
There was a problem hiding this comment.
Migrated in 7cedc24, exactly as suggested:
images: {
remotePatterns: [{ protocol: 'https', hostname: 'image.tmdb.org' }]
}The warning is gone from both npm run dev and npm run build (grep for deprecat|⚠ over the dev log returns 0 matches; the build log has none either).
Verified images still work rather than just that the warning went away. Against a running dev server:
/api/movies -> 200 application/json, live TMDB payload
first poster: https://image.tmdb.org/t/p/w500//iPOn6DinuVyLY17YM9mKuPofV08.jpg
that poster fetched directly -> 200 image/jpeg, 105080 bytes
same poster via /_next/image -> 200 image/jpeg, 48538 bytes (optimised)
https://example.com/a.jpg via /_next/image -> 400
The 400 on the control host is the part that matters: it shows the allowlist is actually being enforced, so the 200 on image.tmdb.org is remotePatterns admitting it and not the optimizer waving everything through.
On the description corrections, all three verified and all three fixed in the body:
- postcss: top level goes 8.4.31 -> 8.5.23. The 8.5.26 copy is
node_modules/vite/node_modules/postcssand it is already 8.5.26 inmaster's lockfile, so this PR does not touch it. Table corrected, with a note. - eslint-plugin-react: installed is 7.37.2. Its
peerDependencies.eslintis^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7— no eslint 10. Body now cites 7.37.2 and notes that 7.37.5 declares the same range, so the conclusion on chore(deps-dev): bump eslint from 9.39.2 to 10.8.0 #984 is unchanged. - lint output: corrected from "0 problems" to 81 problems (0 errors, 81 warnings), with the explicit note that this matches
master'snext lintoutput and is therefore not a regression.
I also added the resolved-versus-manifest distinction to the table, since next and eslint-config-next resolve to 16.3.1 off ^16.3.0 after master merged #991, not the 16.3.0 the old table claimed.
…e images config - eslint.config.mjs: add dist/** to ignores. next lint only walked app/pages/components/lib/src; eslint . walks the whole tree, so a local npm run slides:build made npm run lint fail on generated slidev output. - .gitignore: add dist (gap predates this PR). - next.config.js: agentRules: false so next dev stops writing AGENTS.md and CLAUDE.md into every attendee's clone; images.domains -> images.remotePatterns to clear the Next 16 deprecation warning.
|
All three items addressed in 7cedc24, each answered inline with the reproduction and the after-state. Summary:
Description corrected on all three points you raised, quoting the right numbers: top-level postcss lands at 8.5.23 (8.5.26 is the One thing I found while committing, which I have deliberately not fixed here: the |
SociableSteve
left a comment
There was a problem hiding this comment.
All three points from the previous round are addressed, and I verified each against head (7cedc24) rather than taking the thread replies for it.
distis now in botheslint.config.mjsignoresand.gitignore(git check-ignore -v distresolves to.gitignore:13).npm run slides:build && npm run lintstays at 81 problems (0 errors, 81 warnings) withdist/present, where before it errored ondist/assets/modules/shiki-*.js.agentRules: falseis a real top-level Next 16 option, not experimental (next/dist/server/config-schema.js,agentRules: z.boolean().optional()), so it does not trip config validation.next devon this branch writes noAGENTS.mdorCLAUDE.mdand leavesgit statusclean.images.remotePatternsreplacesdomainswith no deprecation warning in thedevorbuildlogs, and the same hostname is allowed.
Also re-checked from a fresh npm ci on this branch:
- Lockfile matches the corrected description: top-level postcss 8.4.31 to 8.5.23, the
vite-nested copy already 8.5.26 on the merge base and untouched here,eslint-plugin-react7.37.2 on both sides. The deferral of eslint 10 (#984) stands on that plugin's peer range. npm run buildsucceeds on Next 16.3.1 across all 14 routes,next devserves/and/api/movieswith 200s.- No
.eslintrcornext lintreferences remain anywhere outside comments, andlint-staged'seslint --cache --fixpicks up the flat config.
One optional, non-blocking note, not a reason to hold this up.
@next/bundle-analyzer stops producing a report once next is on 16, because Turbopack is now the default builder. @next/bundle-analyzer@16.3.1 bails out when process.env.TURBOPACK is set, and Next 16 sets it to auto before next.config.js is evaluated. Measured both sides: on the merge base ANALYZE=true npm run build writes .next/analyze/{client,nodejs,edge}.html, on this branch it writes nothing and prints "The Next Bundle Analyzer is not compatible with Turbopack builds, no report will be generated". The build still exits 0, the warning names the fix (--webpack, or next experimental-analyze), and nothing in the repo actually invokes ANALYZE: no npm script, no workflow, no mention in README.md or the slides. So it is a latent capability regression rather than a broken path, and it is fine to pick up separately if anyone wants bundle analysis back.
Approving.
Consolidates 3 of the 4 open Dependabot PRs. The eslint 10 major is blocked upstream.
^16.3.0^16.3.0eslint-config-nextmoves withnext— they are released together and the config for Next 16expects the Next 16 plugin.
Note on postcss: the version that moves is the top-level copy, 8.4.31 → 8.5.23. The
8.5.26 copy is the one nested under
vite(node_modules/vite/node_modules/postcss) and it wasalready at 8.5.26 on
master, so this PR does not touch it.Migration Next 16 required
next lintis gone. Next 16 removed the command, so"lint": "next lint"became"lint": "eslint ."..eslintrc.json→eslint.config.mjs. The old config was just{ "extends": "next/core-web-vitals" }.eslint-config-next@16ships a native flat config, so thereplacement imports it directly:
Worth noting for anyone doing this elsewhere: routing it through
FlatCompatinstead — the usualeslintrc bridge — fails with
TypeError: Converting circular structure to JSONoneslint-config-next@16, because the config already is flat. Import it directly.dist/**had to be added toignores. This is the one place where swappingnext lintforeslint .changes what gets walked:next lintonly ever descended intoapp,pages,components,libandsrc, whereaseslint .walks the whole tree.npm run slides:buildwrites the slidev bundle to
dist/(vite's defaultbuild.outDir;deploy.ymlpublishespublish_dir: dist), so without the ignore, anyone who built the slides and then linted got ahard failure inside a generated third-party bundle:
CI never hit this because it lints a fresh
npm citree with nodist.distwas also missingfrom
.gitignore(a gap that predates this PR), so it has been added there too.Two further consequences of Next 16, both fixed here
agentRules: falseinnext.config.js. Next 16 addedserver/lib/generate-agent-files.js(absent from 15.5.21), sonext devwroteAGENTS.mdandCLAUDE.mdinto the project root and left them untracked and un-gitignored. This is a teachingrepo, so every attendee running
npm run devwould have found two unexplained files in theirclone. Disabling the feature is the deliberate choice here rather than gitignoring or committing
them.
npm run devnow leavesgit statusclean.images.domains→images.remotePatterns. Next 16 emits⚠ 'images.domains' is deprecated in favor of 'images.remotePatterns'on everydevandbuild. Migrated toremotePatterns: [{ protocol: 'https', hostname: 'image.tmdb.org' }], whichremoves the warning without changing which hosts are allowed. Verified against a running dev
server:
/api/moviesreturns 200 with live TMDB JSON, a poster URL fetched through the Next imageoptimizer returns
200 image/jpeg(48538 bytes, optimised), and a host that is not inremotePatternscorrectly returns 400 — so the allowlist is genuinely being enforced andimage.tmdb.orgis what it admits.Verification
npm ci: ✅ resolves cleanly (lockfile and manifest agree)npm run lint: ✅ 81 problems (0 errors, 81 warnings), exit 0 — including withdist/present after a slides build. This is identical to
master'snext lintoutput, so it is not aregression, but it is not "0 problems" either
npm run build: ✅ Next 16 production build, all routes, no deprecation warningsnpm run slides:build: ✅npm run dev: ✅ serves/and/api/movies, no warnings, clean git treenpm test: the script is a placeholder (echo … && exit 0), so there is nothing to run — thebuild and lint are the real signal here, and both are what CI runs
npm audit: 16 advisories (9 high / 2 moderate / 5 low) onmaster→ 13 (6 high / 2moderate / 5 low) on this branch. No package in the tree is downgraded.
Left for follow-up — #984 stays open
eslint9.39.2 → 10.8.1 is blocked byeslint-plugin-react, whicheslint-config-nextpulls in.On eslint 10, lint dies while loading its rules:
The installed
eslint-plugin-reactis 7.37.2 (not 7.37.5), and itspeerDependencies.eslintreads^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7— no eslint 10 at anypoint. 7.37.5, the latest release, declares the same range, so the version difference does not
change the conclusion. Since the plugin arrives transitively through
eslint-config-next, there isnothing to pin here: eslint 10 has to wait for that plugin (and for Next to pick it up). I applied
it, confirmed the failure, and reverted to eslint 9.
Unrelated pre-existing issue, not addressed here
The
commit-msghusky hook is broken onmasteras well as on this branch:commitlintthrowsERR_PACKAGE_PATH_NOT_EXPORTED: No "exports" main defined in node_modules/conventional-changelog-conventionalcommits.@commitlint/cli@21.0.2,@commitlint/config-conventional@21.2.0andconventional-changelog-conventionalcommits@10.2.1resolve to identical versions on both sides,so this PR neither causes nor fixes it. Flagging it rather than folding an unrelated fix into a
dependency consolidation.
Closes #985