turbo icon indicating copy to clipboard operation
turbo copied to clipboard

Add Typescript ESLint plugin to the examples

Open la55u opened this issue 3 years ago • 6 comments

Describe the feature you'd like to request

I'd like to request some sort of guide on how to setup Typescript ESlint plugin.

I am unable to set up Typescript ESlint following this guide with the monorepo structure detailed in the Turborepo examples because it's not clear how to use it when both eslint and tsconfig files are inside packages. My preferred setup would be to extend plugin:@typescript-eslint/recommended-requiring-type-checking to leverage the power of Typescript in linting.

Here's what I tried: https://github.com/la55u/turborepo-kitchen-sink

  1. Start from the kitchen-sink example
  2. Added @typescript-eslint/parser and @typescript-eslint/eslint-plugin to the eslint-config-custom/package.json
  3. Modified eslint-config-custom/index.js to:
index.js ```module.exports = { extends: [ "next", "turbo", "prettier", "plugin:@typescript-eslint/recommended", "plugin:@typescript-eslint/recommended-requiring-type-checking", ], parser: "@typescript-eslint/parser", plugins: ["@typescript-eslint"], parserOptions: { tsconfigRootDir: __dirname, project: ["**/packages/**/tsconfig.json"], }, settings: { react: { version: "detect", }, }, }; ```
  1. Run yarn run lint

I get the following error which I am unable to solve (I already because I already added this option).

Error: Error while loading rule '@typescript-eslint/await-thenable': You have used a rule which requires parserServices to be generated. You must therefore provide a value for the "parserOptions.project" property for @typescript-eslint/parser.

It seems like a common usecase to incude this plugin yet there is no docs on it how to use it, I think it would be nice to add it.

Describe the solution you'd like

Add plugin:@typescript-eslint/recommended-requiring-type-checking, to all the examples or create a separate example for it or just make a guide in the docs for how to use them in a monorepo setup where the tscondig and eslint configs are both in a shared package.

Describe alternatives you've considered

Leave it to the user to figure out which is obviously not ideal in my opinion.

la55u avatar Sep 22 '22 15:09 la55u

Please read this for information about how to setup typescript-eslint with a monorepo: https://typescript-eslint.io/docs/linting/typed-linting/monorepos/#one-tsconfigjson-per-package-and-an-optional-one-in-the-root

iduuck avatar Sep 22 '22 22:09 iduuck

I've read it as you can see in my example I tried to add parserOptions to the lint config but it doesn't work. What am I doing wrong? Thank you

la55u avatar Sep 23 '22 07:09 la55u

@la55u I am facing the same problem.

When using plugins in extensions, ESLint does not use the package context of the extension. It uses a package from where the lint is being executed. That means I must add all plugins to every package that uses my custom extension.

I'd be interested in a solution for that as well

raphaelluchini avatar Oct 19 '22 14:10 raphaelluchini

This is blocking from adopting turborepo also. I wonder what other people are doing that this isn't a problem!

georgiosd avatar Oct 29 '22 09:10 georgiosd

@la55u @raphaelluchini I think I figured it out, with the help of @itsUndefined

Don't define the parserOptions inside the custom package, do it inside the library using it!

EDIT: If you're using yarn 3 like me, it seems to require nodeLink: node-modules

georgiosd avatar Oct 29 '22 10:10 georgiosd

Custom is provided as a plugin, so I try adding it with a relative path. it works.

/** @type {import('@typescript-eslint/utils').TSESLint.Linter.Config} */
module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    project: [
      './tsconfig.json'
    ],
  },
  // others..

gracefullight avatar Nov 20 '22 06:11 gracefullight

I installed kitchen-sink from scratch in order to tackle this problem and found a solution. But you're not going to like it.

It assumes that each monorepo has only one Next app. Do this in the app's .eslintrc.js:

module.exports = {
  root: true,
  extends: ['custom'],
  settings: {
    next: {
      rootDir: '.',
    },
  },
  parserOptions: {
    project: ['./tsconfig.json'],
  },
};

And do this in the .eslintrc.js of each React library that the app uses:

module.exports = {
  root: true,
  extends: ['custom'],
  settings: {
    next: {
      rootDir: '../../apps/storefront',
    },
  },
  parserOptions: {
    project: ['./tsconfig.json'],
  },
};

Here's packages/eslint-config-custom/package.json:

{
  "name": "eslint-config-custom",
  "version": "0.0.0",
  "private": true,
  "license": "MIT",
  "main": "index.js",
  "dependencies": {
    "@typescript-eslint/eslint-plugin": "^5.53.0",
    "@typescript-eslint/parser": "^5.53.0",
    "eslint-config-next": "latest",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-react": "7.28.0",
    "eslint-config-turbo": "latest"
  },
  "publishConfig": {
    "access": "public"
  }
}

And here's packages/eslint-config-custom/index.js:

module.exports = {
  extends: [
    'next',
    'turbo',
    'prettier',
    'plugin:@typescript-eslint/recommended-requiring-type-checking',
  ],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  settings: {
    react: {
      version: 'detect',
    },
  },
  parserOptions: {
    babelOptions: {
      presets: [require.resolve('next/babel')],
    },
  },
};

jtlapp avatar Mar 14 '23 22:03 jtlapp

Oh wait! @gracefullight's solution was sufficient. I was also trying to get rid of the following linting errors, WHICH ALSO OCCUR IN THE VANILLA EXAMPLE:

logger:lint: Pages directory cannot be found at /Users/joe/repos/kitchen-sink/packages/logger/pages or /Users/joe/repos/kitchen-sink/packages/logger/src/pages. If using a custom path, please configure with the `no-html-link-for-pages` rule in your eslint config file.
logger:lint: Warning: React version was set to "detect" in eslint-plugin-react settings, but the "react" package is not installed. Assuming latest React version for linting.
ui:lint: Pages directory cannot be found at /Users/joe/repos/kitchen-sink/packages/ui/pages or /Users/joe/repos/kitchen-sink/packages/ui/src/pages. If using a custom path, please configure with the `no-html-link-for-pages` rule in your eslint config file.

jtlapp avatar Mar 15 '23 01:03 jtlapp

Hey, folks! If anyone has the configuration and wants to make a PR to add it to kitchen-sink, that would be great!

anthonyshew avatar Mar 15 '23 02:03 anthonyshew

@anthonyshew, I can do this, but it requires modifying every .estlintrc.js in every example that uses TypeScript. I want to double check that it must be done on a per-workspace basis before proceeding.

jtlapp avatar Mar 15 '23 09:03 jtlapp

Looking into this again, I wonder if we should document this solution rather than change all the configuration files. The change is only needed when using @typescript-eslint plugins. Why complicate configuration unnecessarily?

jtlapp avatar Mar 21 '23 19:03 jtlapp

We're in the process of updating both our internal lint configs and our example lint configs to have TS lint configured by default. All of our internal packages and most of our example (soon to be all) now extend from the @vercel/style-guide which makes configuring TS super simple.

Check out the basic example (npx create-turbo@latest <dir> <package-manager>), or the Vercel style guide.

tknickman avatar Aug 31 '23 14:08 tknickman