Xo: TypeScript 3.9.2: Error: Failed to load config "xo-typescript" to extend from

Created on 12 May 2020  路  7Comments  路  Source: xojs/xo

This might be an issue with the XO CLI, not sure though.

Error: Failed to load config "xo-typescript" to extend from.
Referenced from: BaseConfig
    at configMissingError (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:265:9)
    at ConfigArrayFactory._loadExtendedShareableConfig (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:826:23)
    at ConfigArrayFactory._loadExtends (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:731:25)
    at ConfigArrayFactory._normalizeObjectConfigDataBody (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:660:25)
    at _normalizeObjectConfigDataBody.next (<anonymous>)
    at ConfigArrayFactory._normalizeObjectConfigData (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:596:20)
    at _normalizeObjectConfigData.next (<anonymous>)
    at createConfigArray (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:340:25)
    at ConfigArrayFactory.create (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/config-array-factory.js:395:16)
    at createBaseConfigArray (/home/runner/work/bot/bot/node_modules/eslint/lib/cli-engine/cascading-config-array-factory.js:86:48)

Most helpful comment

Reason is this:

When ESLint loads an extended shareable config it does so relative to the file it is imported from:

  1. new CLIEngine() sets up the baseConfig
  2. The baseConfig is forwarded to createBaseConfigArray()
  3. createBaseConfigArray() calls configArrayFactory.create()](https://github.com/eslint/eslintrc/blob/4440df8237a127e15cbde5c697353e1224f12ec1/lib/cascading-config-array-factory.js#L91-L101), but [forwards _only_ aname`
  4. Within create() a context (ctx), containing the name and filePath, is created is created and the config data gets normalized using [_normalizeConfigData()]

Within _normalizeConfigData() the data eventually arrives at *_normalizeObjectConfigDataBody() where it loads the extends and as part of that tries to load eslint-config-xo-typescript (as the extended shareable config that it is).

And here's the core:

In _loadExtendedShareableConfig() the config is loaded relative to the provided filePath (the one that was missing in step 3. above), and if no filePath is set, then relative to a placeholder file within cwd.

It loads using resolver.resolve](moduleName, relativeToPath) which essentially is a wrapper around the Node.js core Module.createRequire(relativeToPath).resolve(moduleName).

So what happens is:

  1. xo creates a virtual ESLint config, a baseConfig, and tells ESLint CLIEngine to run that from the cwd of the main project.
  2. The main project doesn't have any of the extended shareable configs as dependencies to it.
  3. xo has the extended shareable configs as dependencies to itself.
  4. ESLint can therefore only find the extended shareable config if they have been hoisted to the top level of node_modules and through that hoisting becomes require:able from the top project.
  5. Neither npm or yarn makes any guaranties that any dependencies other than the ones defined in the top project will be possible to require from there.
  6. Due to the nature of this modules they will likely get hosted most of the time, but eg. I ran into a case (https://github.com/sindresorhus/type-fest/issues/137) where yarn 1.x wouldn't hoist eslint-config-xo-typescript while npm would. This only happens because of the incorrect reliance on hoisting.

Solution?

Not really sure. Maybe one of:

  • Try to set the cwd to the xo folder, as require() will find modules higher up in the folder hierarchy, so it will find the hoisted modules.
  • There is a resolvePluginsRelativeTo option for CLIEngine, maybe one could make xo provide the config through a plugin instead and point resolvePluginsRelativeTo to the folder of xo itself?
  • Convince the ESLint team to add a resolveExtendedShareableConfigsRelativeTo that mimics resolvePluginsRelativeTo? (Which they may be reluctant as CLIEngine is deprecated, #474)

All 7 comments

Getting this error with XO v0.32.0 and TypeScript v3.8.3.

Upgrading to TypeScript v3.9.3 fixed the error.

I was having this issue with Typescriot v3.8.3, upgrading to v3.9.7 now gives the same error but with:

Error: Failed to load plugin 'react' declared in 'BaseConfig 禄 /home/rsa/go/src/brewery.doctype.se/skyfall/frontend/node_modules/eslint-config-xo-react/index.js': Cannot find module 'eslint-plugin-react'

Getting this same error with TypeScript v4.0.2

This is almost certainly the same root cause as why having a different Prettier version breaks. However XO is importing or using other modules isn't resilient to version changes and seems to force you to use whatever version is specified in the XO package.json.

I'm also having this issue with TypeScript v4.0.2

EDIT: resolved temporarily adding packages manually as suggested from this comment https://github.com/xojs/xo/issues/454#issuecomment-609485873

yarn add --dev eslint-config-xo-typescript fixes it for me.

Reason is this:

When ESLint loads an extended shareable config it does so relative to the file it is imported from:

  1. new CLIEngine() sets up the baseConfig
  2. The baseConfig is forwarded to createBaseConfigArray()
  3. createBaseConfigArray() calls configArrayFactory.create()](https://github.com/eslint/eslintrc/blob/4440df8237a127e15cbde5c697353e1224f12ec1/lib/cascading-config-array-factory.js#L91-L101), but [forwards _only_ aname`
  4. Within create() a context (ctx), containing the name and filePath, is created is created and the config data gets normalized using [_normalizeConfigData()]

Within _normalizeConfigData() the data eventually arrives at *_normalizeObjectConfigDataBody() where it loads the extends and as part of that tries to load eslint-config-xo-typescript (as the extended shareable config that it is).

And here's the core:

In _loadExtendedShareableConfig() the config is loaded relative to the provided filePath (the one that was missing in step 3. above), and if no filePath is set, then relative to a placeholder file within cwd.

It loads using resolver.resolve](moduleName, relativeToPath) which essentially is a wrapper around the Node.js core Module.createRequire(relativeToPath).resolve(moduleName).

So what happens is:

  1. xo creates a virtual ESLint config, a baseConfig, and tells ESLint CLIEngine to run that from the cwd of the main project.
  2. The main project doesn't have any of the extended shareable configs as dependencies to it.
  3. xo has the extended shareable configs as dependencies to itself.
  4. ESLint can therefore only find the extended shareable config if they have been hoisted to the top level of node_modules and through that hoisting becomes require:able from the top project.
  5. Neither npm or yarn makes any guaranties that any dependencies other than the ones defined in the top project will be possible to require from there.
  6. Due to the nature of this modules they will likely get hosted most of the time, but eg. I ran into a case (https://github.com/sindresorhus/type-fest/issues/137) where yarn 1.x wouldn't hoist eslint-config-xo-typescript while npm would. This only happens because of the incorrect reliance on hoisting.

Solution?

Not really sure. Maybe one of:

  • Try to set the cwd to the xo folder, as require() will find modules higher up in the folder hierarchy, so it will find the hoisted modules.
  • There is a resolvePluginsRelativeTo option for CLIEngine, maybe one could make xo provide the config through a plugin instead and point resolvePluginsRelativeTo to the folder of xo itself?
  • Convince the ESLint team to add a resolveExtendedShareableConfigsRelativeTo that mimics resolvePluginsRelativeTo? (Which they may be reluctant as CLIEngine is deprecated, #474)
Was this page helpful?
0 / 5 - 0 ratings

Related issues

pizzafox picture pizzafox  路  5Comments

sindresorhus picture sindresorhus  路  8Comments

sindresorhus picture sindresorhus  路  5Comments

EdJoPaTo picture EdJoPaTo  路  3Comments

sindresorhus picture sindresorhus  路  6Comments