From 7f363f170173a3a69b216b560063ffdf1d0faec5 Mon Sep 17 00:00:00 2001 From: hectahertz Date: Thu, 12 Feb 2026 20:47:12 +0100 Subject: [PATCH 1/3] chore: add eslint-plugin-react-compiler for lint-time compiler validation - Install eslint-plugin-react-compiler as a dev dependency - Add react-compiler/react-compiler rule as 'warn' in eslint.config.mjs - Disable the rule for files not yet migrated to React Compiler - Export unsupportedPatterns from react-compiler.mjs so both the Babel plugin (build-time) and ESLint plugin (lint-time) share a single source of truth for excluded files --- eslint.config.mjs | 17 +++++++ package-lock.json | 58 ++++++++++++++++++++++-- package.json | 3 +- packages/react/script/react-compiler.mjs | 30 ++++++------ 4 files changed, 89 insertions(+), 19 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index bc5b452bd94..d4f5d7c967d 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -10,6 +10,8 @@ import githubPlugin from 'eslint-plugin-github' import storybook from 'eslint-plugin-storybook' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' +import reactCompiler from 'eslint-plugin-react-compiler' +import {unsupportedPatterns as reactCompilerUnsupported} from './packages/react/script/react-compiler.mjs' import playwright from 'eslint-plugin-playwright' import prettierRecommended from 'eslint-plugin-prettier/recommended' import primerReact from 'eslint-plugin-primer-react' @@ -62,6 +64,21 @@ const config = defineConfig([ react.configs.flat['jsx-runtime'], reactHooks.configs.flat['recommended-latest'], + // React Compiler + { + plugins: {'react-compiler': reactCompiler}, + rules: { + 'react-compiler/react-compiler': 'warn', + }, + }, + // Disable react-compiler rule for files not yet migrated + { + files: reactCompilerUnsupported.map(p => `packages/react/${p}`), + rules: { + 'react-compiler/react-compiler': 'off', + }, + }, + github.browser, github.recommended, github.react, diff --git a/package-lock.json b/package-lock.json index a8504a0d680..bb4bd722f6b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-primer-react": "^8.5.1", "eslint-plugin-react": "^7.35.5", + "eslint-plugin-react-compiler": "^19.1.0-rc.2", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-ssr-friendly": "1.3.0", "eslint-plugin-storybook": "^10.2.0", @@ -81,7 +82,7 @@ "react-dom": "^18.3.1" }, "devDependencies": { - "@primer/react": "38.10.0", + "@primer/react": "38.11.0", "@primer/styled-react": "1.0.3", "@types/react": "^18.3.11", "@types/react-dom": "^18.3.0", @@ -95,7 +96,7 @@ "name": "example-nextjs", "version": "0.0.0", "dependencies": { - "@primer/react": "38.10.0", + "@primer/react": "38.11.0", "@primer/styled-react": "1.0.3", "next": "^16.1.5", "react": "^19.2.0", @@ -138,7 +139,7 @@ "version": "0.0.0", "dependencies": { "@primer/octicons-react": "^19.21.0", - "@primer/react": "38.10.0", + "@primer/react": "38.11.0", "@primer/styled-react": "1.0.3", "clsx": "^2.1.1", "next": "^16.1.5", @@ -822,6 +823,24 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz", + "integrity": "sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==", + "deprecated": "This proposal has been merged to the ECMAScript standard and thus this plugin is no longer maintained. Please use @babel/plugin-transform-private-methods instead.", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-proposal-private-property-in-object": { "version": "7.21.0-placeholder-for-preset-env.2", "dev": true, @@ -13819,6 +13838,37 @@ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" } }, + "node_modules/eslint-plugin-react-compiler": { + "version": "19.1.0-rc.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.1.0-rc.2.tgz", + "integrity": "sha512-oKalwDGcD+RX9mf3NEO4zOoUMeLvjSvcbbEOpquzmzqEEM2MQdp7/FY/Hx9NzmUwFzH1W9SKTz5fihfMldpEYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/plugin-proposal-private-methods": "^7.18.6", + "hermes-parser": "^0.25.1", + "zod": "^3.22.4", + "zod-validation-error": "^3.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.0.0 || >= 18.0.0" + }, + "peerDependencies": { + "eslint": ">=7" + } + }, + "node_modules/eslint-plugin-react-compiler/node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "node_modules/eslint-plugin-react-debug": { "version": "1.52.6", "dev": true, @@ -27004,7 +27054,7 @@ }, "packages/react": { "name": "@primer/react", - "version": "38.10.0", + "version": "38.11.0", "license": "MIT", "dependencies": { "@github/mini-throttle": "^2.1.1", diff --git a/package.json b/package.json index 87287a04928..597862771d6 100644 --- a/package.json +++ b/package.json @@ -51,11 +51,11 @@ "@eslint/compat": "^2.0.1", "@eslint/eslintrc": "^3.3.3", "@eslint/js": "^9.39.2", + "@github-ui/storybook-addon-performance-panel": "0.1.2", "@github/axe-github": "0.7.0", "@github/markdownlint-github": "^0.8.0", "@github/mini-throttle": "2.1.1", "@github/prettier-config": "0.0.6", - "@github-ui/storybook-addon-performance-panel": "0.1.2", "@mdx-js/react": "1.6.22", "@playwright/test": "^1.56.1", "@prettier/sync": "0.5.5", @@ -77,6 +77,7 @@ "eslint-plugin-prettier": "^5.5.5", "eslint-plugin-primer-react": "^8.5.1", "eslint-plugin-react": "^7.35.5", + "eslint-plugin-react-compiler": "^19.1.0-rc.2", "eslint-plugin-react-hooks": "^7.0.1", "eslint-plugin-ssr-friendly": "1.3.0", "eslint-plugin-storybook": "^10.2.0", diff --git a/packages/react/script/react-compiler.mjs b/packages/react/script/react-compiler.mjs index b365d389ed2..21ebf9756dd 100644 --- a/packages/react/script/react-compiler.mjs +++ b/packages/react/script/react-compiler.mjs @@ -11,20 +11,22 @@ const files = glob .map(match => { return path.join(PACKAGE_DIR, match) }) +const unsupportedPatterns = [ + 'src/ActionList/**/*.tsx', + 'src/ActionMenu/**/*.tsx', + 'src/AvatarStack/**/*.tsx', + 'src/Button/**/*.tsx', + 'src/ConfirmationDialog/**/*.tsx', + 'src/Pagehead/**/*.tsx', + 'src/Pagination/**/*.tsx', + 'src/SelectPanel/**/*.tsx', + 'src/SideNav.tsx', + 'src/internal/components/CheckboxOrRadioGroup/**/*.tsx', + 'src/TooltipV2/**/*.tsx', +] + const unsupported = new Set( - [ - 'src/ActionList/**/*.tsx', - 'src/ActionMenu/**/*.tsx', - 'src/AvatarStack/**/*.tsx', - 'src/Button/**/*.tsx', - 'src/ConfirmationDialog/**/*.tsx', - 'src/Pagehead/**/*.tsx', - 'src/Pagination/**/*.tsx', - 'src/SelectPanel/**/*.tsx', - 'src/SideNav.tsx', - 'src/internal/components/CheckboxOrRadioGroup/**/*.tsx', - 'src/TooltipV2/**/*.tsx', - ].flatMap(pattern => { + unsupportedPatterns.flatMap(pattern => { if (glob.isDynamicPattern(pattern)) { const matches = glob.sync(pattern, {cwd: PACKAGE_DIR}) if (matches) { @@ -43,4 +45,4 @@ function isSupported(filepath) { const notMigrated = Array.from(unsupported) -export {files, notMigrated, isSupported} +export {files, notMigrated, isSupported, unsupportedPatterns} From 65fac174a92cef75ce3b00ebcf9b7d672b8e50d4 Mon Sep 17 00:00:00 2001 From: hectahertz Date: Sat, 14 Feb 2026 13:27:36 +0100 Subject: [PATCH 2/3] changeset --- .changeset/react-compiler-linting.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/react-compiler-linting.md diff --git a/.changeset/react-compiler-linting.md b/.changeset/react-compiler-linting.md new file mode 100644 index 00000000000..9c79cf1d2b4 --- /dev/null +++ b/.changeset/react-compiler-linting.md @@ -0,0 +1,5 @@ +--- +'@primer/react': patch +--- + +chore: add eslint-plugin-react-compiler for lint-time compiler validation From a6ff82bad054d4ef2a53ae7cc0888b601041cd8d Mon Sep 17 00:00:00 2001 From: hectahertz Date: Sat, 14 Feb 2026 13:35:06 +0100 Subject: [PATCH 3/3] fix: add missing files to react-compiler unsupported patterns --- packages/react/script/react-compiler.mjs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/react/script/react-compiler.mjs b/packages/react/script/react-compiler.mjs index 21ebf9756dd..8de6af2b943 100644 --- a/packages/react/script/react-compiler.mjs +++ b/packages/react/script/react-compiler.mjs @@ -14,14 +14,33 @@ const files = glob const unsupportedPatterns = [ 'src/ActionList/**/*.tsx', 'src/ActionMenu/**/*.tsx', + 'src/Autocomplete/**/*.tsx', 'src/AvatarStack/**/*.tsx', + 'src/Banner/**/*.tsx', 'src/Button/**/*.tsx', + 'src/Checkbox/**/*.tsx', 'src/ConfirmationDialog/**/*.tsx', + 'src/Dialog/**/*.tsx', + 'src/Heading/**/*.tsx', + 'src/Link/**/*.tsx', 'src/Pagehead/**/*.tsx', + 'src/PageLayout/**/*.tsx', 'src/Pagination/**/*.tsx', + 'src/Portal/**/*.tsx', 'src/SelectPanel/**/*.tsx', 'src/SideNav.tsx', + 'src/UnderlineNav/**/*.tsx', + 'src/experimental/SelectPanel2/**/*.tsx', + 'src/hooks/useAnchoredPosition.ts', + 'src/hooks/useFocusTrap.ts', + 'src/hooks/useFocusZone.ts', + 'src/hooks/useMenuInitialFocus.ts', + 'src/hooks/useOnEscapePress.ts', + 'src/hooks/useResizeObserver.ts', + 'src/hooks/useSafeTimeout.ts', + 'src/hooks/useScrollFlash.ts', 'src/internal/components/CheckboxOrRadioGroup/**/*.tsx', + 'src/internal/hooks/useMergedRefs.ts', 'src/TooltipV2/**/*.tsx', ]