eslint-plugin-import: eslint-import-resolver-webpack don't work for resolved paths

.eslintrc

{
  "parser": "babel-eslint",
  "extends": "airbnb",
  "plugins": ["import"],
  "settings": {
    "import/resolver": "webpack"
  },
  "env": {
    "browser": true
  }
}

webpack.config.js

...
  resolve: {
    root: path.resolve('src'),
    extensions: ['', '.js', '.scss'],
    modulesDirectories: ['node_modules'],
  },
...

src/index.js

import routes from 'routes';
import 'scss/index.scss';

in console:

Error - Unable to resolve path to module 'routes'. (import/no-unresolved)
Error - Unable to resolve path to module 'scss/index.scss'. (import/no-unresolved)

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Comments: 80 (35 by maintainers)

Most upvoted comments

I solved that problem providing absolute path for webpack config file:

'import/resolver': {
  webpack: {
    config: path.join(__dirname, 'webpack.config.js')
  }
}

Notice that this solution forces to use js format for eslint.

@zhanghaowx

    "settings": {
        "import/resolver": {
            "webpack": "webpack.config.js"
        }
    },

should be

    "settings": {
        "import/resolver": {
            "webpack": {
                "config": "webpack.config.js"
            }
        }
    },

For those who have an ES6 webpack config and don’t want to change it back to ES5, you can create a file webpack.config.eslint.js (or any other name actually) with the following content:

// this will compile all the subsequent required files to ES5 on the fly
require('babel-register'); 

module.exports = require('./webpack.config.js');
"settings": {
    "import/resolver": {
      "webpack": {
        "config": "webpack.config.eslint.js"
      }
    }
  }

I was having this same issue when upgrading webpack to v2, updating eslint-import-resolver-webpack to 0.8.1 fixed it. Here is the list of my eslint related package versions:

"webpack": "^2.2.1",
"eslint": "^3.15.0",
"babel-eslint": "^7.1.1",
"eslint-import-resolver-webpack": "^0.8.1",
"eslint-plugin-import": "^2.2.0"

For those who still have this issue, @sompylasar and @ChristianHersevoort solutions solve the problem.

package.json:

"webpack": "^2.2.1",
"eslint": "^3.17.0",
"babel-eslint": "^7.1.1",
"eslint-import-resolver-webpack": "^0.8.1",
"eslint-plugin-import": "^2.2.0"

.eslintrc.js:

module.exports = {
  parser: 'babel-eslint',
  ...
  extends: ['airbnb-base', 'airbnb-base/legacy'],
  plugins: ['react'],
  settings: {
    'import/resolver': {
      webpack: {
        config: 'webpack/config/default.js'
      }
    }
  },
  rules: { .. }

webpack/config/default.js: The previous ES5 implementation:

import { resolve } from 'path';
import { CWD, JS_BASE } from '../config';

export default {
  entry: '',
  output: {
    path: '',
    publicPath: '',
    filename: ''
  },
  resolve: {
    alias: {
      routes: resolve(config.CWD, `${config.JS_BASE}/routes`),
      pages: resolve(config.CWD, `${config.JS_BASE}/pages`),
      components: resolve(config.CWD, `${config.JS_BASE}/components`),
      reducers: resolve(config.CWD, `${config.JS_BASE}/store/reducers`),
      utilities: resolve(config.CWD, `${config.JS_BASE}/utilities`)
    },
    extensions: ['/index.jsx', '.jsx', '.js']
  }
};

should be rewritten to:

const resolve = require('path').resolve;
const config = require('../config');

module.exports = {
  entry: '',
  output: {
    path: '',
    publicPath: '',
    filename: ''
  },
  resolve: {
    alias: {
      routes: resolve(config.CWD, `${config.JS_BASE}/routes`),
      pages: resolve(config.CWD, `${config.JS_BASE}/pages`),
      components: resolve(config.CWD, `${config.JS_BASE}/components`),
      reducers: resolve(config.CWD, `${config.JS_BASE}/store/reducers`),
      utilities: resolve(config.CWD, `${config.JS_BASE}/utilities`)
    },
    extensions: ['/index.jsx', '.jsx', '.js']
  }
};

Why this is happening? The reason for ESLint resolver is failing on Webpack config written in ES6 syntax, as far as I understood, is that the configuration file should be valid (it gets validated by Webpack once pointed in .eslintrc’s settings: { 'import/resolver' }. There is no conversion from ES6->commonJS, therefore configuration file is not considered valid, and resolving fails. Rewriting the configuration file solved the problem for me. Note: if by any chance your Webpack config requires JS files written in ES6 syntax, it will fail as well (you would need to set those files to Webpack’s exclude properly).

How to know if this is your issue Use the command suggested by @benmosher:

DEBUG=eslint-plugin-import:* $(npm bin)/eslint src/path/to/your/file.js

The output should include the whole Webpack configuration object if it is valid (and therefore will be used by eslint import resolver):

...
eslint-plugin-import:resolver:webpack Config path from settings: ./webpack/config/default.js +53ms
  eslint-plugin-import:resolver:webpack Config path resolved to: /Users/.../project/webpack/config/default.js +1ms
  eslint-plugin-import:resolver:webpack Using config:  { entry: '', // <-- if this line is absent, probably Webpack config is invalid
  output: { path: '', publicPath: '', filename: '' },
  resolve: 
   { alias: 
      { routes: '/Users/.../project/src/app/routes',
        pages: '/Users/.../project/src/app/pages',
        components: '/Users/.../project/src/app/components',
        reducers: '/Users/.../project/src/app/store/reducers',
        utilities: '/Users/.../project/src/app/utilities' },
     extensions: [ '/index.jsx', '.jsx', '.js' ] } } +2ms
...

Thank you for the great tips, guys!

npm install --save-dev eslint-import-resolver-webpack - resolved the issue!

I’ve had issues with this plugin, but finally figured out the problem: don’t write webpack config in es6 format.

Still experiencing the same issues here with webpack 2.2.0 eslint 3.14.0 eslint-config-airbnb 13.0.0 eslint-plugin-import 2.2.0 eslint-import-resolver-webpack 0.7.1

I actually moved towards defining the config directly inside .eslintrc:

"settings": {
    "import/resolver": {
      "webpack": {
        "config": {
          "resolve": {
            "modules": ["apps", "node_modules"],
            "alias": {
              "shared" : "shared"
            }
          }
        }
      }
    }
  }

neither the alias shared, nor any of the directories inside apps are resolved, node modules, however, do work now.

running DEBUG=eslint-plugin-import:* node_modules/.bin/eslint apps/news/redux/sagas/feed.js gives me (only including one of the no-unresolved errors):

...
eslint-plugin-import:resolver:node Resolving: +2ms news/redux/actions/feed from: /Users/irisschaffer/Sites/someProject/apps/news/redux/sagas/feed.js
  eslint-plugin-import:resolver:node resolve threw error: +2ms Error: Cannot find module 'news/redux/actions/feed' from '/Users/irisschaffer/Sites/someProject/apps/news/redux/sagas'
    at Function.module.exports [as sync] (/Users/irisschaffer/Sites/someProject/node_modules/resolve/lib/sync.js:36:11)
    at Object.exports.resolve (/Users/irisschaffer/Sites/someProject/node_modules/eslint-import-resolver-node/index.js:19:28)
    at v2 (/Users/irisschaffer/Sites/someProject/node_modules/eslint-module-utils/resolve.js:79:23)
    at withResolver (/Users/irisschaffer/Sites/someProject/node_modules/eslint-module-utils/resolve.js:84:16)
    at fullResolve (/Users/irisschaffer/Sites/someProject/node_modules/eslint-module-utils/resolve.js:101:22)
    at relative (/Users/irisschaffer/Sites/someProject/node_modules/eslint-module-utils/resolve.js:46:10)
    at resolve (/Users/irisschaffer/Sites/someProject/node_modules/eslint-module-utils/resolve.js:172:12)
    at resolveImportType (/Users/irisschaffer/Sites/someProject/node_modules/eslint-plugin-import/lib/core/importType.js:73:65)
    at reportIfMissing (/Users/irisschaffer/Sites/someProject/node_modules/eslint-plugin-import/lib/rules/no-absolute-path.js:14:32)
    at EventEmitter.handleImports (/Users/irisschaffer/Sites/someProject/node_modules/eslint-plugin-import/lib/rules/no-absolute-path.js:27:9)
  eslint-plugin-import:resolver:webpack Config path from settings: +67ms { resolve:
   { modules: [ 'apps', 'node_modules' ],
     alias: { shared: 'shared' } } }
  eslint-plugin-import:resolver:webpack Using config:  +1ms { resolve:
   { modules: [ 'apps', 'node_modules' ],
     alias: { shared: 'shared' } } }
  eslint-plugin-import:resolver:webpack enhanced-resolve version: +0ms 3.0.3
  eslint-plugin-import:resolver:webpack Error during module resolution: +3ms { Error: Can't resolve 'undefined' in 'news/redux/actions/feed'
    at onResolved (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:66:16)
    at loggingCallbackWrapper (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)
    at afterInnerCallback (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:138:10)
    at loggingCallbackWrapper (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)
    at Resolver.applyPluginsAsyncSeriesBailResult1 (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/tapable/lib/Tapable.js:181:46)
    at innerCallback (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:125:19)
    at loggingCallbackWrapper (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)
    at Resolver.applyPluginsParallelBailResult1 (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/tapable/lib/Tapable.js:266:46)
    at beforeInnerCallback (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/Resolver.js:112:19)
    at loggingCallbackWrapper (/Users/irisschaffer/Sites/someProject/node_modules/webpack/node_modules/enhanced-resolve/lib/createInnerCallback.js:31:19)
  details: 'resolve \'undefined\' in \'news/redux/actions/feed\'',
  missing: [] }

/Users/irisschaffer/Sites/someProject/apps/news/redux/sagas/feed.js
  (excluding the 5 other ones)
  18:8   error  Unable to resolve path to module 'news/redux/actions/feed'         import/no-unresolved

✖ 6 problems (6 errors, 0 warnings)

Any idea what the problem could be??

Also having this problem with version 0.3.0 and airbnb rules.

I tried jsdf’s recommendation of removing any path.resolve references from the config and that didn’t work for me.

Here’s what my resolve looks like in my webpack.config.js file:

config.resolve = {
  root: [client],
  alias: {
    'css': join(client, 'styles'),
    'containers': join(client, 'containers'),
    'components': join(client, 'components'),
    'utils': join(client, 'utils')
  }
};

And here’s my .eslintrc:

{
  "extends": "airbnb",
  "settings": {
    "import/resolver": "webpack"
  },
  "env": {
    "browser": true
  }
}

I encountered an issue like this due to the fact that our webpack config was building some absolute paths using path.resolve, which implicitly uses process.cwd().

I fixed the issue by ensuring that the webpack config could resolve all necessary paths regardless of what process.cwd was (by resolving them relative to __dirname).

@bramschulting I use it this way in my .eslintrc.js:

  "settings": {
    "import/ignore": [
      "node_modules",
      "\\.(scss|less|css)$",
    ],
    "import/resolver": {
      "node": {
        "moduleDirectory": [
          "./src/webapp",
          "./src/api",
          "./src/server",
          "./src/common",
        ],
      },
      "webpack": {
        "config": "./webpack/configForEslintImportResolver.js",
      },
    },
  },

resolved by adding the webpack resolver plugin to the eslintrc config and CHANGING in the webpack config files require path in ES5 style.

// webpack.config.dev.js
const path = require('path'); // instead of import path from 'path'

// .eslintrc
"settings": {
      "import/resolver": {
        "webpack": {
          "config": "webpack.config.dev.js"
        }
      }
    }

// package.json
"eslint-import-resolver-webpack": "^0.8.2",

Actually, just published v0.3.1(tag “next”) that has debug logging built in (ref: #300), try calling ESLint from a terminal as follows:

DEBUG=eslint-plugin-import:* $(npm bin)/eslint src/jsx/redux/store.js

I would try linting a single file; the output is pretty verbose but hopefully will identify the issue (or at least disqualify bad config).

@alicerocheman The issue is that your webpack config that you provide to eslint is written not in ES5 (with imports and arrow functions), but eslint only understands ES5. https://github.com/benmosher/eslint-plugin-import/issues/352#issuecomment-284216693

There are two ways to make this work:

  • Rewrite webpack config and all of its dependencies in your app to ES5.
  • Make Babel do the same (transpile = translate + compile) for you.

I used the second option by having a separate file provided to eslint that requires babel-register to plug in the transpilation and the webpack config and is written in ES5.

@asdine your solution works! Thanks!

@sompylasar SOLVED! finally ^^

I changed my json .eslintrc into an ES5 .eslintrc.js, and changed the name of the webpack config file into path.resolve(__dirname,“webpack.config.dev.js”).

Here's the file (click to open)
const path = require('path');

module.exports = {
  "root": true,
  "extends": [
    "eslint:recommended",
    "plugin:import/errors",
    "plugin:import/warnings"
  ],
  "plugins": [
    "babel",
    "react",
  ],
  "settings": {
    "import/resolver": {
      "webpack": {
        "config": path.resolve(__dirname,"webpack.config.dev.js")
      }
    }
  },
  "parser": "babel-eslint",
  "parserOptions": {
    "ecmaVersion": 6,
    "sourceType": "module",
    "ecmaFeatures": {
      "jsx": true,
      "experimentalObjectRestSpread": true
    }
  },
  "env": {
    "es6": true,
    "browser": true,
    "node": true,
    "jquery": true,
    "mocha": true,
    "commonjs": true
  },
 ...
};

MARK

Managed to get this working with the following .eslintrc:

...
"settings": {
  "import/resolver": "webpack"
}
...

Using the following package versions:

webpack: 1.12.14 eslint: 2.11.1 eslint-import-resolver-webpack: 0.8.1

Hope this helps somebody!

What did it for me was to move extensions: ['*', '.js', '.jsx'] from module.rules[0].resolve to the root resolve field (in webpack.config.js). .jsx files were problematic.

Before:

  resolve: {
    alias: {
      component: path.resolve(__dirname, 'frontend/component/'),
      store: path.resolve(__dirname, 'frontend/store/'),
      lib: path.resolve(__dirname, 'frontend/lib/'),
      context: path.resolve(__dirname, 'frontend/context/'),
    },
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: ['@babel/plugin-proposal-object-rest-spread'],
          },
        },
        resolve: {
          extensions: ['*', '.js', '.jsx'], // <-- This has to be moved up
        },
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },

After:

  resolve: {
    alias: {
      component: path.resolve(__dirname, 'frontend/component/'),
      store: path.resolve(__dirname, 'frontend/store/'),
      lib: path.resolve(__dirname, 'frontend/lib/'),
      context: path.resolve(__dirname, 'frontend/context/'),
    },
    extensions: ['*', '.js', '.jsx'], // <-- Here, it works 
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx)$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'],
            plugins: ['@babel/plugin-proposal-object-rest-spread'],
          },
        },
      },
      {
        test: /\.css$/i,
        use: ['style-loader', 'css-loader'],
      },
    ],
  },

clarification: eslint-import-resolver-webpack implements the aforementioned magic.

So: Atom Linter => ESlint => eslint-plugin-import => eslint-import-resolver-webpack => ✨magic✨

There is no other way to configure eslint resolver I know about than to pass the file path. If there is, please tell me. Anyway, for the text editor to use eslint, we have to have a eslintrc (luckily this can be in executable JavaScript, not just static JSON). That file path passed to eslint resolver config is not used by the build pipeline (except for linting), the webpack compiler is called as a function from the build pipeline, and a generated webpack config is passed there.

I also have the same problem when running eslint from command line. (In Atom I use linter-eslint plugin and everything works fine)

@jsdf 's solutions doesn’t work for me either.


Here is what I do

By change

    "settings": {
        "import/resolver": "webpack"
    },

to

    "settings": {
        "import/resolver": {
            "webpack": "webpack.config.js"
        }
    },

I solved some import/no-unresolved on dependencies installed inside node_modules. But still all resolved paths are not recognized.

Finally I tried the local eslint instead of the global one and everything works fine now. Both in v3.3.0. So instead of

eslint --config .eslintrc.js .

do

./node_modules/eslint/bin/eslint.js --config .eslintrc.js .

The cause may still be what @jsdf described, but I have to work around in another way.

If you name the file with.babel.js as its extension, the plugin will use the nearest Babel to pre-compile your config. This should match Webpack’s behavior.