Skip to content

fix(eslint-plugin-next): support custom pageExtensions in no-html-link-for-pages rule#92980

Open
Jah-yee wants to merge 1 commit intovercel:canaryfrom
Jah-yee:fix/no-html-link-for-pages-pageextensions
Open

fix(eslint-plugin-next): support custom pageExtensions in no-html-link-for-pages rule#92980
Jah-yee wants to merge 1 commit intovercel:canaryfrom
Jah-yee:fix/no-html-link-for-pages-pageextensions

Conversation

@Jah-yee
Copy link
Copy Markdown

@Jah-yee Jah-yee commented Apr 19, 2026

Good day

Summary

The @next/next/no-html-link-for-pages ESLint rule previously only recognized pages with js, jsx, ts, and tsx extensions. It ignored custom pageExtensions configured in next.config.js (e.g., .mdx).

Root Cause

The rule uses parseUrlForPages() and parseUrlForAppDir() in packages/eslint-plugin-next/src/utils/url.ts, which hardcoded the regex instead of reading from the project's next.config.js.

Fix

  1. Added getPageExtensions() utility that loads pageExtensions from the project's next.config.js (with fallback to defaults)
  2. Updated parseUrlForPages() and parseUrlForAppDir() to accept an optional extensions parameter
  3. Updated callers to pass the loaded extensions

Files Changed

  • packages/eslint-plugin-next/src/utils/get-page-extensions.ts (new)
  • packages/eslint-plugin-next/src/utils/url.ts
  • packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts

Testing

Manually verified with a test case using custom pageExtensions (e.g., pageExtensions: ['mdx']).


Warmly, RoomWithOutRoof

@nextjs-bot
Copy link
Copy Markdown
Contributor

Allow CI Workflow Run

  • approve CI run for commit: bc5582f12b415efdef83f13468194996882b3683

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

1 similar comment
@nextjs-bot
Copy link
Copy Markdown
Contributor

Allow CI Workflow Run

  • approve CI run for commit: bc5582f12b415efdef83f13468194996882b3683

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

fsReadDirSyncCache[directory] ??= fs.readdirSync(directory, {
withFileTypes: true,
})
const extPattern = extensions.map((ext) => ext.replace('.', '\\.')).join('|')
const extRegex = new RegExp(`\\.(\\${extPattern})$`)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra backslash before in extRegex creates unintended regex escape sequences for custom extensions starting with s, d, w, b, etc.

Fix on Vercel

…ages rule

The no-html-link-for-pages rule was using hardcoded regex patterns
/(\.(j|t)sx?)$/ to detect page files, ignoring the pageExtensions
configured in next.config.js.

This change:
- Reads pageExtensions from context.settings.next.pageExtensions
- Passes pageExtensions to getUrlFromPagesDirectories and
  getUrlFromAppDirectory
- Updates parseUrlForPages and parseUrlForAppDir to build dynamic
  regex patterns from the configured extensions
- Defaults to ['jsx', 'js', 'ts', 'tsx'] when no pageExtensions is set

Fixes vercel#53473
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants