Skip to content

fix(eslint-plugin): respect pageExtensions in no-html-link-for-pages rule#91602

Open
wabalabudabdab wants to merge 1 commit intovercel:canaryfrom
wabalabudabdab:fix/no-html-link-page-extensions
Open

fix(eslint-plugin): respect pageExtensions in no-html-link-for-pages rule#91602
wabalabudabdab wants to merge 1 commit intovercel:canaryfrom
wabalabudabdab:fix/no-html-link-page-extensions

Conversation

@wabalabudabdab
Copy link

What?

The no-html-link-for-pages ESLint rule was ignoring pageExtensions configured in next.config.js, causing false negatives for projects using custom page file extensions.

Fixes #53473

Why?

In url.ts, parseUrlForPages and parseUrlForAppDir had a hardcoded regex /(\.( j|t)sx?)$/ with a TODO comment acknowledging the limitation. This fix resolves those TODOs.

How?

packages/eslint-plugin-next/src/utils/url.ts

  • Added optional pageExtensions parameter (default: ['js', 'jsx', 'ts', 'tsx']) to parseUrlForPages, parseUrlForAppDir, getUrlFromPagesDirectories, and getUrlFromAppDirectory
  • Builds extension regexes dynamically from the provided extensions

packages/eslint-plugin-next/src/rules/no-html-link-for-pages.ts

  • Added getPageExtensions() helper that resolves pageExtensions with the following priority:
    1. ESLint settings (settings.next.pageExtensions) — explicit user override, consistent with how rootDir is configured
    2. next.config.js / next.config.ts — auto-detected from the project root
    3. Next.js defaults['js', 'jsx', 'ts', 'tsx']

Testing

To test, create a Next.js project with:

// next.config.js
module.exports = { pageExtensions: ['page.tsx', 'page.ts', 'page.jsx', 'page.js'] }

Before this fix, the rule would not detect <a> links to .page.tsx pages.
After this fix, it correctly identifies them.

The no-html-link-for-pages rule was matching page files using a
hardcoded regex for .js, .jsx, .ts, .tsx extensions, ignoring any
custom pageExtensions configured in next.config.js.

This fix:
- Adds a pageExtensions parameter to parseUrlForPages,
  parseUrlForAppDir, getUrlFromPagesDirectories, and
  getUrlFromAppDirectory in url.ts (resolves the TODO comments)
- Adds getPageExtensions() in no-html-link-for-pages.ts that reads
  pageExtensions with the following priority:
  1. ESLint settings (settings.next.pageExtensions) — explicit override
  2. next.config.js / next.config.ts in the project root
  3. Next.js defaults: ['js', 'jsx', 'ts', 'tsx']

Fixes vercel#53473
@nextjs-bot
Copy link
Collaborator

Allow CI Workflow Run

  • approve CI run for commit: 7c3ff84

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

res.push(...parseUrlForPages(urlprefix + dirent.name + '/', dirPath))
res.push(
...parseUrlForPages(urlprefix + dirent.name + '/', dirPath, pageExtensions)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

In parseUrlForAppDir, the recursive call for subdirectories incorrectly calls parseUrlForPages instead of parseUrlForAppDir, causing nested app directory routes to be scanned with pages-directory logic.

Fix on Vercel

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.

@next/next/no-html-link-for-pages rule does not work with pageExtensions

2 participants