remix
remix copied to clipboard
ESLint v9 doesn't work with .eslintrc.cjs config
Reproduction
I've installed ESlint v9.12.0 and would like to update the old eslint config (.eslintrc.js file). It looks like this:
module.exports = {
extends: [
'@remix-run/eslint-config',
'@remix-run/eslint-config/node',
'@remix-run/eslint-config/jest-testing-library',
'prettier',
],
ignorePatterns: [
'**/*.test.ts',
'**/*.test.js',
'**/*.test.tsx',
'**/*.test.jsx',
'**/*.spec.ts',
'**/*.spec.js',
'**/*.spec.tsx',
'**/*.spec.jsx',
],
settings: {
jest: {
version: 27,
},
},
rules: {
'react/display-name': 'off',
},
};
So I wonder if there any examples of configs in a new format like eslint.config.js, eslint.config.mjs or eslint.config.cjs specifically for Remix framework.
I've seen this file - templates/remix/.eslintrc.cjs. Can it be considered as default eslint config for now?
System Info
System:
OS: macOS 13.6.7
CPU: (10) arm64 Apple M1 Pro
Memory: 118.58 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 18.18.2 - ~/.nvm/versions/node/v18.18.2/bin/node
npm: 9.8.1 - ~/.nvm/versions/node/v18.18.2/bin/npm
Browsers:
Safari: 18.0
npmPackages:
@remix-run/dev: 2.11.2 => 2.11.2
Used Package Manager
npm
Expected Behavior
A new eslint config is present for Eslint v9 (eslint.config.js, eslint.config.mjs or eslint.config.cjs)
Actual Behavior
Existing eslint config is not adapted to the latest version of ESlint
As of Eslint v9 the old .eslintrc.js style config is deprecated and disabled by default. If you still want to use it you need to set a ESLINT_USE_FLAT_CONFIG env var to false. Source -> https://eslint.org/docs/latest/use/configure/configuration-files-deprecated
Since @remix-run/eslint-config uses the old eslintrc format, the config can't be reused in the new flat config format. The rules and settings are re-usable, but you'd need to import them directly and you'd also need to manually add the plugins.
Like this:
// eslint.config.mjs
import remixCore from '@remix-run/eslint-config/rules/core.js'
import remixImport from '@remix-run/eslint-config/rules/import.js'
import remixJsxA11y from '@remix-run/eslint-config/rules/jsx-a11y.js'
import remixReact from '@remix-run/eslint-config/rules/react.js'
import remixReactSettings from '@remix-run/eslint-config/settings/react.js'
import pluginImport from 'eslint-plugin-import'
import pluginJsxA11y from 'eslint-plugin-jsx-a11y'
import pluginReact from 'eslint-plugin-react'
import pluginReactHooks from 'eslint-plugin-react-hooks'
const config = [{
settings: {
...remixReactSettings
},
plugins: {
'jsx-a11y': pluginJsxA11y,
import: pluginImport,
react: pluginReact,
'react-hooks': pluginReactHooks
},
rules: {
...remixCore,
...remixImport,
...remixReact,
...remixJsxA11y
}
}]
export default config
Keep in mind this example doesn't take into account the overrides, globals, or ignored files used in @remix-run/eslint-config.
If it's cool with the Remix team I would be happy to dive into this further and open a PR to add a flat config alternative to @remix-run/eslint-config
@HW13 The team has deprecated @remix-run/eslint-config basically right after releasing Remix v2, hence the update to the separate configs in the templates in #7597
Thanks @MichaelDeBoey, I was not aware of that - my bad 😅
Well, If you guys are interested in migrating the templates to the new flat config format I'd be happy to contribute!
@HW13 I'm currently working on doing exactly that: migrating the templates to the new flat config format
Once I have a PR, I'll link to this issue
That's what I was able to configure, not sure that's 100% correct variant:
// eslint.config.mjs
/** @type {import('eslint').Linter.FlatConfig[]} */
import js from "@eslint/js";
import typescriptEslint from "@typescript-eslint/eslint-plugin";
import typescriptParser from "@typescript-eslint/parser";
import globals from "globals";
import importPlugin from "eslint-plugin-import";
import reactPlugin from "eslint-plugin-react";
import jsxA11yPlugin from "eslint-plugin-jsx-a11y";
import reactHooksPlugin from "eslint-plugin-react-hooks";
const __dirname = new URL(".", import.meta.url).pathname;
export default [
js.configs.recommended,
importPlugin.flatConfigs.recommended,
{
ignores: [
"build/*",
"build/**/*",
"**/build/**/*",
"eslint.config.mjs",
"coverage/*",
"coverage/**/*",
"node_modules/*",
"node_modules/**/*",
"global.d.ts",
"**/*.test.ts",
"**/*.test.js",
"**/*.test.tsx",
"**/*.test.jsx",
"**/*.spec.ts",
"**/*.spec.js",
"**/*.spec.tsx",
"**/*.spec.jsx",
],
},
{
files: ["**/*.{js,jsx,ts,tsx}"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "module",
globals: {
...globals.browser,
...globals.commonjs,
...globals.es6,
...globals.jest,
process: "readonly",
},
},
plugins: {
react: reactPlugin,
"jsx-a11y": jsxA11yPlugin,
"react-hooks": reactHooksPlugin,
},
rules: {
...reactHooksPlugin.configs.recommended.rules,
...reactPlugin.configs.recommended.rules,
...jsxA11yPlugin.configs.recommended.rules,
"react/no-unescaped-entities": "off",
"react/display-name": "off",
"react/prop-types": "off",
"no-prototype-builtins": "off",
},
settings: {
react: {
version: "detect",
},
jest: {
version: 27,
},
formComponents: ["Form"],
linkComponents: [
{ name: "Link", linkAttribute: "to" },
{ name: "NavLink", linkAttribute: "to" },
],
"import/resolver": {
typescript: {
alwaysTryTypes: true,
project: "./tsconfig.json",
},
},
"import/ignore": [".(css)$"],
},
},
// TypeScript configuration
{
files: ["**/*.{ts,tsx}"],
languageOptions: {
parser: typescriptParser,
parserOptions: {
tsconfigRootDir: __dirname,
project: ["./tsconfig.json"],
},
globals: {
...globals.node,
React: "readonly",
NodeJS: "readonly",
},
},
plugins: {
"@typescript-eslint": typescriptEslint,
},
rules: {
...typescriptEslint.configs.recommended.rules,
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-require-imports": "off",
"@typescript-eslint/no-empty-object-type": "off",
"@typescript-eslint/ban-ts-comment": "off",
},
},
// Node environment for eslint.config.mjs
{
files: ["eslint.config.mjs"],
env: {
node: true,
},
},
];
I'm currently working on doing exactly that: migrating the templates to the new flat config format Once I have a PR, I'll link to this issue
@MichaelDeBoey Do you happen to have any updates on this?
Thank you for opening this issue, and our apologies we haven't gotten around to it yet!
With the release of React Router v7 we are sun-setting continued development/maintenance on Remix v2. If you have not already upgraded to React Router v7, we recommend you do so. We've tried to make the upgrade process as smooth as possible with our Future Flags. We are now in the process of cleaning up outdated issues and pull requests to improve the overall hygiene of our repositories.
We plan to continue to address 2 types of issues in Remix v2:
- Bugs that pose security concerns
- Bugs that prevent upgrading to React Router v7
If you believe this issue meets one of those criteria, please respond or create a new issue.
For all other issues, ongoing maintenance will be happening in React Router v7, so:
- If this is a bug, please reopen this issue in that repo with a new minimal reproduction against v7
- If this is a feature request, please open a new Proposal Discussion in React Router, and if it gets enough community support it can be considered for implementation
If you have any questions you can always reach out on Discord. Thanks again for providing feedback and helping us make our framework even better!