Skip to content

Commit

Permalink
chore(eslint): upgrade eslint to v9 (#2716)
Browse files Browse the repository at this point in the history
<!--
  How to write a good PR title:
  - Start with a verb, for example: Add, Delete, Improve, Fix…
  - Give as much context as necessary and as little as possible
-->

### WHY are these changes introduced?

Fixes #191

<!--
  Context about the problem that this PR is addressing. If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you did and what alternatives you considered.
-->

### WHAT is this pull request doing?
This PR:
- upgrades eslint to v9 and its corresponding plugins, packages and configs
- removes individual eslint from all of our packages, except `templates/skeleton`
- unifies our basic lint configuation to be in the root of the monorepo (it was empty until now)
- fixes our `lint-staged` script to run on the changed files
- removes deprecated dependencies of remix-run lint plugin and hydrogen lint plugin (not maintained)

### The relevant files in the PR are:

- **eslint.config.js** - this is the base eslint config for linting our codebase
- **templates/skeleton/eslint.config.js** - this is the skeleton-specific configuration, and it can be removed by the skeleton users if they want.
- the rest are (stylistic only) lint fixes

I tried to find the best subset of rules so that we will be able to have even minimal linting over our codebase, but at the same time not to flood many warnings over packages that weren't linted until now. If in the future we will want to add/enable a new rule, we can do it and fix its errors.

<!-- ℹ️ Delete the following for small / trivial changes -->

### HOW to test your changes?
1. `npm i && npm run lint` from the root folder
2. `npm i && npm run lint` from the `templates/skeleton` folder

#### Checklist

- [x] I've read the [Contributing Guidelines](https://github.com/Shopify/hydrogen/blob/main/CONTRIBUTING.md)
- [x] I've considered possible cross-platform impacts (Mac, Linux, Windows)
- [x] I've added a [changeset](https://github.com/Shopify/hydrogen/blob/main/CONTRIBUTING.md#changesets) if this PR contains user-facing or noteworthy changes
- [ ] I've added [tests](https://github.com/Shopify/hydrogen/blob/main/CONTRIBUTING.md#testing) to cover my changes
- [ ] I've added or updated the documentation

<!--
 THANK YOU for your pull request! Members from the Hydrogen team will review these changes and provide feedback as soon as they are available.
-->
  • Loading branch information
liady authored Feb 6, 2025
1 parent 3ea2582 commit cd65685
Show file tree
Hide file tree
Showing 57 changed files with 2,651 additions and 2,290 deletions.
7 changes: 7 additions & 0 deletions .changeset/forty-badgers-wonder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@shopify/hydrogen-react': patch
'skeleton': patch
'@shopify/hydrogen': patch
---

Upgrade eslint to version 9 and unify eslint config across all packages (with the exception of the skeleton, which still keeps its own config)
9 changes: 0 additions & 9 deletions .eslintignore

This file was deleted.

14 changes: 0 additions & 14 deletions .eslintrc.js

This file was deleted.

2 changes: 1 addition & 1 deletion docs/preview/app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {PassThrough} from 'node:stream';
import type {AppLoadContext, EntryContext} from '@remix-run/node';
import {createReadableStreamFromReadable} from '@remix-run/node';
import {RemixServer} from '@remix-run/react';
import isbot from 'isbot';
import {isbot} from 'isbot';
import {renderToPipeableStream} from 'react-dom/server';

const ABORT_DELAY = 5_000;
Expand Down
4 changes: 1 addition & 3 deletions docs/preview/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,19 @@
"@remix-run/react": "^2.15.3",
"@remix-run/serve": "^2.15.3",
"he": "^1.2.0",
"isbot": "^3.8.0",
"isbot": "^5.1.21",
"marked": "^9.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-syntax-highlighter": "^15.5.0"
},
"devDependencies": {
"@remix-run/dev": "^2.15.3",
"@remix-run/eslint-config": "^2.15.3",
"@tailwindcss/vite": "4.0.0-beta.8",
"@types/he": "^1.2.1",
"@types/react": "^18.2.20",
"@types/react-dom": "^18.2.7",
"@types/react-syntax-highlighter": "^15.5.7",
"eslint": "^8.38.0",
"typescript": "^5.2.2",
"vite": "^5.1.8",
"vite-tsconfig-paths": "^4.3.1"
Expand Down
2 changes: 1 addition & 1 deletion docs/shopify-dev/analytics-setup/js/app/entry-server.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {RemixServer} from '@remix-run/react';
import isbot from 'isbot';
import {isbot} from 'isbot';
import {renderToReadableStream} from 'react-dom/server';
import {createContentSecurityPolicy} from '@shopify/hydrogen';

Expand Down
2 changes: 1 addition & 1 deletion docs/shopify-dev/analytics-setup/ts/app/entry-server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type {
// [END csp]
} from '@shopify/remix-oxygen';
import {RemixServer} from '@remix-run/react';
import isbot from 'isbot';
import {isbot} from 'isbot';
import {renderToReadableStream} from 'react-dom/server';
import {createContentSecurityPolicy} from '@shopify/hydrogen';

Expand Down
318 changes: 318 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,318 @@
const {fixupConfigRules, fixupPluginRules} = require('@eslint/compat');
const js = require('@eslint/js');
const {FlatCompat} = require('@eslint/eslintrc');
const eslintComments = require('eslint-plugin-eslint-comments');
const react = require('eslint-plugin-react');
const reactHooks = require('eslint-plugin-react-hooks');
const jsxA11Y = require('eslint-plugin-jsx-a11y');
const tsdoc = require('eslint-plugin-tsdoc');
const jest = require('eslint-plugin-jest');
const simpleImportSort = require('eslint-plugin-simple-import-sort');
const tsParser = require('@typescript-eslint/parser');
const globals = require('globals');

const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended,
allConfig: js.configs.all,
});

const lintedTSPackages = [
'packages/hydrogen-react',
'examples/express',
'templates/skeleton',
'docs/previews',
];

module.exports = [
// Global ignores
{
ignores: [
'**/node_modules/',
'**/build/',
'**/*.graphql.d.ts',
'**/*.graphql.ts',
'**/storefront-api-types.d.ts',
'**/customer-account-api-types.d.ts',
'**/codegen.ts',
'**/dist/**/*',
'**/coverage/**/*',
'**/docs/**/*',
'**/.eslintrc.cjs',
'**/src/**/*.example.tsx',
'**/src/**/*.example.ts',
'**/src/**/*.example.jsx',
'**/src/**/*.example.js',
'**/eslint.config.cjs',
'**/scripts/**/*',
'bin/',
'*.d.ts',
'**/codegen.ts',
'**/vite.config.ts',
'**/vitest.setup.ts',
'**/vitest.config.ts',
'**/tsup.config.ts',
'**/src/storefront-api-response.types.ts',
'**/storefrontapi.generated.d.ts',
],
},

// Base configurations
...fixupConfigRules(
compat.extends(
'plugin:node/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'eslint:recommended',
'plugin:eslint-comments/recommended',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
),
),

// Core configuration with plugins and general rules
{
plugins: {
'eslint-comments': fixupPluginRules(eslintComments),
react: fixupPluginRules(react),
'react-hooks': fixupPluginRules(reactHooks),
'jsx-a11y': fixupPluginRules(jsxA11Y),
},
settings: {
'import/resolvers': {
typescript: {
project: [
'packages/*/tsconfig.json',
'templates/*/tsconfig.json',
'examples/*/tsconfig.json',
'docs/*/tsconfig.json',
],
},
},
react: {version: 'detect'},
jest: {version: 28},
},
languageOptions: {
parser: tsParser,
parserOptions: {
ecmaFeatures: {jsx: true},
},
globals: {
...globals.browser,
...globals.node,
},
ecmaVersion: 2020,
sourceType: 'module',
},
linterOptions: {
reportUnusedDisableDirectives: false,
},
rules: {
// React rules
'react/display-name': 'off',
'react/no-array-index-key': 'warn',
'react/prop-types': 'off',
'react/react-in-jsx-scope': 'off',
'react/no-children-prop': 'off',
'react/no-unescaped-entities': 'off',
'react/jsx-no-target-blank': 'off',
'react-hooks/exhaustive-deps': 'error',

// Node rules
'node/shebang': 'off',
'node/no-unpublished-require': 'off',
'node/no-unsupported-features/es-syntax': 'off',
'node/no-missing-import': 'off',
'node/no-extraneous-import': 'off',
'node/no-unpublished-import': 'off',
'node/no-unsupported-features/es-builtins': [
'error',
{version: '>=14.0.0', ignores: []},
],
'node/no-unsupported-features/node-builtins': [
'error',
{version: '>=14.0.0', ignores: []},
],

// TypeScript rules
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/no-non-null-asserted-optional-chain': 'off',

// General rules
'object-shorthand': ['error', 'always', {avoidQuotes: true}],
'prefer-const': ['warn', {destructuring: 'all'}],
'no-prototype-builtins': 'off',
'no-use-before-define': 'off',
'no-warning-comments': 'off',
'no-empty': 'off',
'no-control-regex': 'off',
'no-async-promise-executor': 'off',
'eslint-comments/no-unused-disable': 'off',
'jest/no-disabled-tests': 'off',
'jest/no-export': 'off',
'no-console': 'off',
'no-ex-assign': 'off',
'no-constant-condition': 'off',
'no-useless-escape': 'off',
'no-case-declarations': 'off',
'no-process-exit': 'off',

// Import rules
'import/extensions': 'off',
'import/no-unresolved': 'off',
},
},

// Test files configuration
...compat.extends('plugin:jest/recommended').map((config) => ({
...config,
files: ['**/*.test.*'],
})),
{
files: ['**/*.test.*'],
plugins: {jest},
languageOptions: {
globals: {
...globals.node,
...globals.jest,
},
},
},

// TypeScript files configuration
{
files: ['**/*.ts', '**/*.tsx'],
settings: {
'import/resolvers': {
typescript: {
project: [
'packages/*/tsconfig.json',
'templates/*/tsconfig.json',
'examples/*/tsconfig.json',
'docs/*/tsconfig.json',
],
},
},
},
languageOptions: {
parser: tsParser,
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
ecmaFeatures: {jsx: true},
},
},
rules: {
'no-unused-vars': 'off',
'no-undef': 'off',
'prefer-const': 'off',
},
},

// Server files configuration
{
files: ['**/*.server.*'],
rules: {
'react-hooks/rules-of-hooks': 'off',
},
},

// Linted TypeScript packages configuration
{
files: [
...lintedTSPackages.flatMap((pkg) => [
`${pkg}/**/*.ts`,
`${pkg}/**/*.tsx`,
]),
],
rules: {
'no-undef': 'off',
'no-unused-vars': 'off',
'tsdoc/syntax': 'error',
'react/jsx-no-target-blank': 'error',
'node/no-extraneous-import': [
'error',
{
allowModules: [
'@shopify/hydrogen',
'@shopify/react-testing',
'@remix-run/web-fetch',
'@total-typescript/ts-reset',
],
},
],
'node/no-extraneous-require': [
'error',
{
allowModules: ['@shopify/hydrogen'],
},
],
},
plugins: {tsdoc},
},

// TypeScript strict configuration for linted packages
...fixupConfigRules(
compat.extends(
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:jsx-a11y/recommended',
),
).map((config) => ({
...config,
files: [
...lintedTSPackages.flatMap((pkg) => [
`${pkg}/**/*.ts`,
`${pkg}/**/*.tsx`,
]),
],
languageOptions: {
parser: tsParser,
parserOptions: {
projectService: true,
tsconfigRootDir: __dirname,
ecmaFeatures: {jsx: true},
},
},
rules: {
'jsx-a11y/control-has-associated-label': 'off',
'jsx-a11y/label-has-for': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
},
})),

// Example files configuration
{
files: [
'**/*.example.ts',
'**/*.example.js',
'**/*.example.tsx',
'**/*.example.jsx',
],
rules: {
'node/no-extraneous-import': 'off',
'node/no-extraneous-require': 'off',
'no-unused-vars': 'off',
'no-undef': 'off',
'import/no-duplicates': 'off',
'react-hooks/exhaustive-deps': 'off',
'prefer-const': 'off',
'import/no-named-as-default': 'off',
'node/no-missing-require': 'off',
},
},

// Index files configuration
{
files: ['**/src/index.ts'],
plugins: {'simple-import-sort': simpleImportSort},
rules: {'simple-import-sort/exports': 'error'},
},

// Hydrogen package configuration
{
files: ['packages/hydrogen/**/*.tsx', 'packages/hydrogen/**/*.ts'],
rules: {'react-hooks/exhaustive-deps': 'off'},
},
];
Loading

0 comments on commit cd65685

Please sign in to comment.