Skip to content

Migrate to ESLint flat config and modernize tooling#13

Open
amcdnl wants to merge 2 commits intomain-react-queryfrom
claude/update-dependencies-D2WFY
Open

Migrate to ESLint flat config and modernize tooling#13
amcdnl wants to merge 2 commits intomain-react-queryfrom
claude/update-dependencies-D2WFY

Conversation

@amcdnl
Copy link
Contributor

@amcdnl amcdnl commented Feb 24, 2026

Summary

This PR modernizes the project's linting and build tooling by migrating from the legacy ESLint configuration format to the new flat config system, removing unnecessary dependencies, and updating to newer versions of core libraries.

Key Changes

ESLint Migration

  • Migrated from .eslintrc.cjs to new eslint.config.js flat config format
  • Removed vite-plugin-eslint from Vite configuration (linting now handled separately)
  • Updated lint scripts to target src/ directory directly
  • Simplified lint-staged configuration to remove redundant --ext flags
  • Consolidated ESLint ignore patterns into the flat config

Dependency Updates

  • React ecosystem: Updated React and React DOM to v19.1.0
  • Build tools: Updated Vite to v7.3.1, Vitest to v4.0.18
  • Storybook: Updated to v9.1.19 with simplified addon configuration
  • TypeScript: Updated to v5.9.3 and typescript-eslint to v8.56.1
  • Other libraries: Updated motion, reablocks, react-router, and various dev dependencies

Configuration Cleanup

  • Removed react-helmet-async dependency and replaced with native <title> elements
  • Updated Prettier config: jsxBracketSameLinebracketSameLine
  • Updated Storybook imports to use new package paths (storybook/manager-api, storybook/theming)
  • Updated Storybook addon imports to use @storybook/addon-docs/blocks
  • Simplified Storybook addon configuration (removed deprecated addons)
  • Updated TypeScript config: target ES2022, moduleResolution to "Bundler"
  • Updated Node version requirement to v22.22.0

Code Formatting

  • Applied consistent formatting across multiple files
  • Simplified JSX and component structures
  • Removed unnecessary blank lines and improved code organization

Notable Implementation Details

  • The new ESLint flat config uses tseslint.config() for better TypeScript support
  • Vite configuration simplified by removing the ESLint plugin and consolidating config structure
  • Husky pre-commit hook simplified to just run npx lint-staged
  • .eslintignore file removed as ignore patterns are now in eslint.config.js

https://claude.ai/code/session_01Wa78iFDCc7pT4C1RjMY2EN

Major dependency updates:
- React 18 → 19 (with native <title> tag support, replacing react-helmet-async)
- ESLint 8 → 9 (migrated from legacy .eslintrc.cjs to flat config eslint.config.js)
- TypeScript 5.3 → 5.9
- Vite 7.1 → 7.3
- Vitest 3.2 → 4.0
- Storybook 9 alpha/mixed → 9.1.19 stable
- Tailwind CSS 4.1 → 4.2
- Node.js 18 → 22 (.nvmrc)

Breaking change fixes:
- react-error-boundary v6: error type changed from Error to unknown
- Storybook 9: consolidated packages (@storybook/blocks → @storybook/addon-docs/blocks,
  @storybook/theming → storybook/theming, @storybook/manager-api → storybook/manager-api)
- Storybook 9: import Preview type from @storybook/react-vite instead of @storybook/react
- Storybook 9: removed merged addons (essentials, storysource, interactions, mdx-gfm)
- ESLint flat config: removed vite-plugin-eslint (abandoned), @typescript-eslint/parser,
  @typescript-eslint/eslint-plugin (replaced by typescript-eslint v8)
- Prettier: renamed deprecated jsxBracketSameLine → bracketSameLine
- Prettier: renamed deprecated --loglevel → --log-level
- TSConfig: moduleResolution Node → Bundler
- Husky: updated prepare script for v9 format
- Removed unused PostCSS plugins (autoprefixer, postcss-nested, postcss-preset-env)

https://claude.ai/code/session_01Wa78iFDCc7pT4C1RjMY2EN
Remove deprecated shebang and husky.sh sourcing that will fail in Husky v10.

https://claude.ai/code/session_01Wa78iFDCc7pT4C1RjMY2EN
Copilot AI review requested due to automatic review settings February 24, 2026 14:34
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR comprehensively modernizes the project's development tooling by migrating from legacy ESLint configuration to the new flat config system and updating numerous dependencies to their latest versions. The changes simplify the build configuration, remove deprecated tooling, and adopt React 19's native metadata handling.

Changes:

  • Migrated ESLint from .eslintrc.cjs to flat config format (eslint.config.js) with consolidated ignore patterns
  • Updated major dependencies: React 19.1.0, ESLint 9.39.3, Vitest 4.0.18, @hookform/resolvers 5.2.2, and TypeScript 5.9.3
  • Replaced react-helmet-async with React 19's native <title> tag hoisting capability
  • Simplified Vite configuration by removing vite-plugin-eslint and consolidating CSS module configuration
  • Updated Storybook to 9.1.19 with new import paths and simplified addon configuration
  • Modernized TypeScript configuration with ES2022 target and "Bundler" module resolution
  • Updated Husky to v9 with simplified pre-commit hook
  • Improved error handling with proper type guards for unknown error types

Reviewed changes

Copilot reviewed 26 out of 28 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
eslint.config.js New ESLint flat config with TypeScript, React, and Storybook plugins
.eslintrc.cjs Removed legacy ESLint configuration file
.eslintignore Removed as ignore patterns moved to flat config
package.json Updated dependencies (React 19, ESLint 9, Vitest 4, etc.) and simplified lint scripts
vite.config.ts Removed ESLint plugin, simplified configuration structure, consolidated CSS module config
tsconfig.json Updated to ES2022 target and Bundler module resolution
tsconfig.node.json Updated to Bundler module resolution
src/index.tsx Removed react-helmet-async, replaced with native <title> tag
src/App/NotFound/NotFound.tsx Replaced Helmet with native <title> tag
src/shared/utils/ErrorBoundary/ErrorBoundary.tsx Changed error type from Error to unknown (safer typing)
src/shared/utils/ErrorBoundary/ErrorComponent.tsx Added type guard for error instanceof Error
.storybook/main.ts Removed addon-essentials, addon-storysource, addon-interactions; kept addon-themes and addon-docs
.storybook/preview.tsx Updated imports to new Storybook package paths
.storybook/manager.ts Updated imports to use storybook/manager-api
.storybook/theme.ts Updated imports to use storybook/theming
src/assets/**.mdx Updated imports to @storybook/addon-docs/blocks
.prettierrc.json Replaced deprecated jsxBracketSameLine with bracketSameLine
.husky/pre-commit Simplified to Husky 9 format
.nvmrc Updated Node version to v22.22.0
Multiple files Code formatting and cleanup (removed blank lines, simplified JSX)

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

</HelmetProvider>
<ThemeProvider theme={theme}>
<ErrorBoundary>
<title>Starter</title>
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The <title> tag should be placed in the document head, not as a child within the component tree. React 19 does support rendering metadata tags like <title> in components and will automatically hoist them to the document head, but placing it inside ErrorBoundary could cause issues if the error boundary catches an error before the title is rendered. Consider placing this at a higher level in the component tree (e.g., directly under React.StrictMode) or using a more robust solution for managing document metadata across routes.

Copilot uses AI. Check for mistakes.
js.configs.recommended,
...tseslint.configs.recommended,
{
files: ['src/**/*.{js,ts,tsx}'],
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The ESLint configuration only targets files in 'src/**/*.{js,ts,tsx}', but there are TypeScript configuration files in the .storybook directory and root directory (like vite.config.ts, tsconfig.json) that won't be linted. Consider adding a separate configuration block to include these files, or explicitly add them to the files pattern if linting them is desired.

Suggested change
files: ['src/**/*.{js,ts,tsx}'],
files: ['src/**/*.{js,ts,tsx}', '.storybook/**/*.{js,ts,tsx}', 'vite.config.ts', 'tsconfig.json'],

Copilot uses AI. Check for mistakes.
addons: [
'@storybook/addon-storysource',
'@storybook/addon-essentials',
'@storybook/addon-themes',
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The removal of '@storybook/addon-essentials' removes several commonly used addons (actions, controls, docs, viewport, backgrounds, toolbars, measure, outline). While '@storybook/addon-docs' is explicitly added, other essential addons like actions and controls are no longer included. Verify that this is intentional and that the removed addons are not needed for the project's Storybook stories.

Suggested change
'@storybook/addon-themes',
'@storybook/addon-themes',
'@storybook/addon-essentials',

Copilot uses AI. Check for mistakes.
Comment on lines 22 to +68
"dependencies": {
"@hookform/resolvers": "^3.10.0",
"@tanstack/react-query": "^5.87.1",
"@hookform/resolvers": "^5.2.2",
"@tanstack/react-query": "^5.90.21",
"classnames": "^2.5.1",
"date-fns": "^4.1.0",
"motion": "^12.23.12",
"nanoid": "^5.1.5",
"reablocks": "^9.2.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"react-error-boundary": "^6.0.0",
"react-helmet-async": "^2.0.5",
"react-hook-form": "^7.62.0",
"react-router": "^7.8.2",
"motion": "^12.34.3",
"nanoid": "^5.1.6",
"reablocks": "^9.4.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-error-boundary": "^6.1.1",
"react-hook-form": "^7.71.2",
"react-router": "^7.13.1",
"react-use": "^17.6.0",
"yup": "^1.7.0"
"yup": "^1.7.1"
},
"devDependencies": {
"@7nohe/openapi-react-query-codegen": "^1.6.2",
"@eslint/js": "^10.0.0",
"@storybook/addon-actions": "^9.0.8",
"@storybook/addon-docs": "^9.1.5",
"@storybook/addon-essentials": "^9.0.0-alpha.12",
"@storybook/addon-interactions": "^9.0.0-alpha.10",
"@storybook/addon-mdx-gfm": "^9.0.0-alpha.13",
"@storybook/addon-onboarding": "^9.1.5",
"@storybook/addon-storysource": "^9.0.0-alpha.14",
"@storybook/addon-themes": "^9.1.5",
"@storybook/blocks": "^9.0.0-alpha.17",
"@storybook/manager-api": "^9.0.0-alpha.1",
"@storybook/preview-api": "^9.0.0-alpha.1",
"@storybook/react": "^9.1.5",
"@storybook/react-vite": "^9.1.5",
"@storybook/test": "^9.0.0-alpha.2",
"@storybook/theming": "^9.0.0-alpha.1",
"@tailwindcss/postcss": "^4.1.13",
"@types/eslint": "^9.6.1",
"@types/react": "^18.3.24",
"@types/react-dom": "^18.3.7",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^5.0.2",
"@vitest/coverage-v8": "^3.2.4",
"autoprefixer": "^10.4.21",
"eslint": "^8.57.1",
"eslint-config-prettier": "^10.1.5",
"@eslint/js": "^9.39.3",
"@storybook/addon-docs": "^9.1.19",
"@storybook/addon-themes": "^9.1.19",
"@storybook/react-vite": "^9.1.19",
"@tailwindcss/postcss": "^4.2.1",
"@types/react": "^19.1.0",
"@types/react-dom": "^19.1.0",
"@vitejs/plugin-react": "^5.1.4",
"@vitest/coverage-v8": "^4.0.18",
"eslint": "^9.39.3",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-storybook": "^9.1.5",
"globals": "^16.3.0",
"eslint-plugin-storybook": "^9.1.19",
"globals": "^17.3.0",
"husky": "^9.1.7",
"jsdom": "^26.1.0",
"lint-staged": "^16.1.6",
"jsdom": "^28.1.0",
"lint-staged": "^16.2.7",
"postcss": "^8.5.6",
"postcss-nested": "^7.0.2",
"postcss-preset-env": "^10.3.1",
"prettier": "^3.6.2",
"storybook": "^9.1.5",
"tailwindcss": "^4.1.13",
"typescript": "^5.3.3",
"typescript-eslint": "^8.43.0",
"vite": "^7.1.5",
"vite-plugin-checker": "^0.10.3",
"vite-plugin-eslint": "^1.8.1",
"prettier": "^3.8.1",
"storybook": "^9.1.19",
"tailwindcss": "^4.2.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.56.1",
"vite": "^7.3.1",
"vite-plugin-checker": "^0.12.0",
"vite-plugin-svgr": "^4.5.0",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^3.2.4"
"vite-tsconfig-paths": "^6.1.1",
"vitest": "^4.0.18"
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

Multiple major version updates are included in this PR (React 18→19, @hookform/resolvers 3→5, Vitest 3→4, ESLint 8→9). While these updates are valuable for modernization, each major version typically includes breaking changes. Ensure that:

  1. React 19 breaking changes have been tested (e.g., new ref handling, changes to Context, etc.)
  2. @hookform/resolvers v5 breaking changes are compatible with the existing form implementations
  3. Vitest 4 test configurations and assertions still work correctly
  4. The codebase has been thoroughly tested after these updates

Consider splitting major version updates into separate PRs to make it easier to identify and fix any issues that arise from specific version bumps.

Copilot uses AI. Check for mistakes.
tsconfigPaths(),
react(),
checker({
typescript: true,
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

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

The vite-plugin-eslint has been removed from the Vite configuration, which means ESLint errors will no longer be displayed in the browser during development. While this simplifies the configuration and improves build performance, developers will need to rely on their IDE or running the lint command separately to catch linting issues. Ensure this change is communicated to the team and that the development workflow accounts for this change.

Suggested change
typescript: true,
typescript: true,
eslint: {
lintCommand: 'eslint "./src/**/*.{ts,tsx,js,jsx}"',
},

Copilot uses AI. Check for mistakes.
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.

3 participants