node.js - Necesito ayuda para configurar eslint en un monorepo usando Yarn 3 y TypeScript
He estado rascándome la cabeza sin parar tratando de configurar una configuración de ESLint en mi monorepo. Estoy usando Yarn 3.2.4 como el gestor de paquetes. Aquí hay un repositorio de GitHub que contiene un proyecto de ejemplo. Aquí está la estructura del proyecto:
/monorepo
├── /configs
│ ├── /eslint
│ │ ├── index.js
│ │ └── package.json
│ ├── /jest
│ │ ├── index.js
│ │ └── package.json
│ ├── /prettier
│ │ ├── index.js
│ │ └── package.json
│ └── /typescript
│ ├── tsconfig.json
│ └── package.json
├── /packages
│ └── /mypackage
│ ├── .eslintrc.js
│ └── package.json
└── package.json
Con lo siguiente :
/monorepo/package.json(package.json raíz)
{
...,
"workspaces": [
"configs/*",
"packages/*"
],
"scripts": {
"lint": "yarn workspaces foreach -pt run lint"
}
}
/monorepo/configs/eslint/package.json
{
...,
"name": "@monorepo/eslint-config",
"main": "index.js",
"peerDependencies": {
"eslint": "^8.27.0",
...
* other eslint plugins / configs *
...
}
}
/monorepo/configs/eslint/index.jses simplemente mi archivo normal de configuración de eslint, extendiendo y utilizando los paquetes de configuración de eslint mencionados arriba/monorepo/packages/mypackage/package.json
{
...,
"devDependencies": {
"@monorepo/eslint-config": "workspace:*",
"eslint": "^8.27.0",
...
* other eslint plugins / configs *
...
}
}
/monorepo/packages/mypackage/.eslintrc.js
module.exports = {
extends: ['@monorepo/eslint-config']
};
Ahora con esta configuración, FUNCIONA. Sin embargo, lo que encuentro realmente molesto es que necesito especificar las dependencias de configuraciones/plugins de eslint en CADA paquete de mi monorepo. Si intento colocar estas dependencias en las devDependencies del paquete eslint-config, y eliminarlas del paquete mypackage (dejando solo eslint como dependencia de desarrollo), recibo el siguiente mensaje de error:
Error: Failed to load plugin '@typescript-eslint' declared in '.eslintrc.js » @monorepo/eslint-config': Your application tried to access @typescript-eslint/eslint-plugin, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.
Required package: @typescript-eslint/eslint-plugin
Required by: /path/to/monorepo/packages/mypackage/
Require stack:
- /path/to/monorepo/packages/mypackage/__placeholder__.js
Referenced from: /path/to/monorepo/.yarn/__virtual__/@monkvision-eslint-config-virtual-abbbf308a5/1/configs/eslint/index.js
at Function.require$$0.Module._resolveFilename (/path/to/monorepo/.pnp.cjs:16089:13)
at Function.resolve (node:internal/modules/cjs/helpers:108:19)
at Object.resolve (/path/to/monorepo/.yarn/cache/@eslint-eslintrc-npm-1.3.3-9e3a462140-f03e9d6727.zip/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:2325:46)
at ConfigArrayFactory._loadPlugin (/path/to/monorepo/.yarn/cache/@eslint-eslintrc-npm-1.3.3-9e3a462140-f03e9d6727.zip/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3392:33)
at ConfigArrayFactory._loadExtendedPluginConfig (/path/to/monorepo/.yarn/cache/@eslint-eslintrc-npm-1.3.3-9e3a462140-f03e9d6727.zip/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3212:29)
at ConfigArrayFactory._loadExtends (/path/to/monorepo/.yarn/cache/@eslint-eslintrc-npm-1.3.3-9e3a462140-f03e9d6727.zip/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3133:29)
at ConfigArrayFactory._normalizeObjectConfigDataBody (/path/to/monorepo/.yarn/cache/@eslint-eslintrc-npm-1.3.3-9e3a462140-f03e9d6727.zip/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3074:25)
at _normalizeObjectConfigDataBody.next (<anonymous>)
at ConfigArrayFactory._normalizeObjectConfigData (/path/to/monorepo/.yarn/cache/@eslint-eslintrc-npm-1.3.3-9e3a462140-f03e9d6727.zip/node_modules/@eslint/eslintrc/dist/eslintrc.cjs:3019:20)
at _normalizeObjectConfigData.next (<anonymous>)
Así que mi pregunta es: ¿Hay alguna manera de declarar las dependencias del plugin ESlint SOLO UNA VEZ (en el proyecto de configuración) y no en cada paquete de mi monorepo?
Perdón por el largo mensaje y gracias de antemano.
Respuesta #1
Vale, así que después de unos días leyendo sobre este tema, creo que tengo una visión bastante buena de este tema.
Este es en realidad un problema relacionado con ESlint, y no tiene nada que ver con los espacios de trabajo de yarn. En realidad, es una limitación de ESlint que obliga a las configuraciones compartidas a usar dependencias pares. Sin embargo, existen algunas soluciones alternativas/soluciones futuras. Para las personas interesadas, copiaré/pegaré el mensaje que escribí para mi equipo aquí en el trabajo:
Debido a las limitaciones de cómo funciona ESlint actualmente, las configuraciones compartidas de ESlint necesitan especificar sus dependencias (como otras configuraciones, plugins, etc.) como dependencias pares. Esto obliga a los desarrolladores que quieren usar nuestra configuración a descargar manualmente cada una de nuestras dependencias. Esto es, obviamente, muy engorroso y en cierto modo pierde el objetivo principal de una configuración compartida. Esto es aún más cierto cuando se trata de monorrepos como el repositorio oficial de [MY COMPANY], en el que cada paquete tiene la misma enorme lista de dependencias de ESlint, a pesar de que tenemos, justo al lado de ellos, una única configuración compartida de ESlint. Existen formas de eludir esta limitación (@rushstack/eslint-patch, etc.), pero vienen con sus propias limitaciones y se consideran como "parches" más que como funciones reales.
Sin embargo, en agosto de 2022, el equipo de ESlint ideó un nuevo sistema de configuración llamado ESlint Flat Config. Este nuevo sistema de configuración permite (entre otras cosas) que una configuración compartida declare sus dependencias como dependencias de desarrollo (o normales), e incluirlas en el archivo de configuración (importándolas como un paquete de node). Esto es obviamente una gran noticia para nosotros, ya que básicamente significa que todos los problemas enumerados en el párrafo anterior serán resueltos. Sin embargo, necesitamos darle tiempo a los paquetes de configuraciones y plugins de Eslint para adaptarse a este nuevo sistema de configuración, al menos por ahora. Por ejemplo, el paquete typescript-eslint creó un issue el 08/11 para actualizar su sistema de configuración.
Esto significa que, por ahora, necesitamos ceñirnos a la configuración antigua y sus dependencias entre pares, y estar atentos a las actualizaciones del paquete hasta que el nuevo sistema de configuración de ESlint sea lo suficientemente maduro para que podamos migrar a él.
Algunas referencias para leer más sobre este tema:
- https://github.com/eslint/eslint/issues/3458
- https://eslint.org/blog/2022/08/new-config-system-part-1/
- https://eslint.org/blog/2022/08/new-config-system-part-2/
- https://eslint.org/blog/2022/08/new-config-system-part-3/
- https://eslint.org/docs/latest/user-guide/configuring/configuration-files-new