eslint-plugin-import
eslint-plugin-import copied to clipboard
Error when importing images using aliases
Hello all,
Recently I have updated my project and my eslint has started complaining when I import an image using an alias (extraneous dependency error). In order to get rid of this error I added:
"import/ignore": ["/*.png/", "/*.jpg/"]
Which made my webpack build is ok as expected. However, VSCode highlights my "import myimage from @Images/my_image.png" as red due to "import/no-extraneous-dependencies".
On the other hand if I have:
"import/ignore":["*.png", "*.jpg"]
Then the highlight red error from VSCode goes away but my webpack build throws:
ERROR in Invalid regular expression: *.png: Nothing to repeat
Occurred while linting blabla\index.js:2
It looks like VSCode ESLint plugin and webpack eslint stuff do not use the same patterns for import/ignore.
I have created the following repo where I get the same result: https://github.com/javierguzman/eslint-error
You may need to do npm install --force for the node_modules.
In order to reproduce the error:
- Open Header.tsx and you will see no error highlights
- Run "npm run build:production"
- You get the invalid regular expression
- Change the expression of import/ignore
- Run "npm run build:production" and it is ok
- However if you go to Header.tsx you will see the import marked as red due to extraneous dependencies
I hope my configuration is not that bad :smile: I have two eslint configuration, one for development and one for production. build:production as well as vscode uses the production es lint configuration. This can be seen in the vscode configuration folder under the repository I have created.
Please, let me know if you need something else from me.
Thank you in advance for the help and regards
p.s. the lint configuration to be looked at is .eslintrc.json, ignore the development one
Why is webpack running eslint at all? The build process should be entirely separate from testing.
I’m also very confused why you’d have two linting configurations. Production code is the build output, this is never linted.
I come from embedded software and I have learned everything about web apps, etc. on my own so I might not be doing stuff properly.
Having said that, the package called "eslint-webpack-plugin" has 2m downloads on npm and if I am not mistaken its purpose is to run eslint when running webpack, if I have not missed anything, I am not the only one. Or am I mistaken?
I have two configurations because when I am in develop mode I am more flexible as I usually play around a ton. But let's stick with .eslintrc.json as is the one I am using when calling build:production and the one used in the vscode configuration. I think I forgot to mention that.
You’re not the only one, of course, but that doesn't mean it’s the right way to do it :-)
So with the production config, which theoretically runs in the cli, vscode, and así webpack, you’re getting different results? Note that the CLI is the source of truth.
How can I run eslint cli directly? Now I think about it, the import/ignore should be a glob, shouldn't it? That means VSCode plugin has the correct behavior as when I type '*png', the red hightline goes away, as expected. However, if I leave like that, it is webpack the one complaining saying "invalid regular expression when I am building. So it must be eslint-webpack-plugin the one reading wrongly the field. Does this make sense?
Yes, that makes perfect sense to me.
to run eslint directly, make sure it’s installed as a dev dep (it shouldn’t ever be global), and then run npx eslint .. You can put eslint . in an npm run-script as well - i usually make one called “lint” and then another called “pretest” that runs npm run lint.
This is interesting, I got the same "webpack" error while running eslint cli:
❯ npx eslint ./src/* -c ./config/.eslintrc.json
Oops! Something went wrong! :(
ESLint: 7.32.0
SyntaxError: Invalid regular expression: /*.png/: Nothing to repeat
Occurred while linting MYHIDDENPATH\client\src\index.js:2
at new RegExp (<anonymous>)
at ignore (MYHIDDENPATH\client\node_modules\eslint-module-utils\ignore.js:47:19)
at Function.ExportMap.for (MYHIDDENPATH\client\node_modules\eslint-plugin-import\lib\ExportMap.js:739:31)
at Function.ExportMap.get (MYHIDDENPATH\client\node_modules\eslint-plugin-import\lib\ExportMap.js:734:463)
at checkSpecifiers (MYHIDDENPATH\client\node_modules\eslint-plugin-import\lib\rules\named.js:42:46)
at MYHIDDENPATH\client\node_modules\eslint\lib\linter\safe-emitter.js:45:58
at Array.forEach (<anonymous>)
at Object.emit (MYHIDDENPATH\client\node_modules\eslint\lib\linter\safe-emitter.js:45:38)
at NodeEventGenerator.applySelector (MYHIDDENPATH\client\node_modules\eslint\lib\linter\node-event-generator.js:293:26)
at NodeEventGenerator.applySelectors (MYHIDDENPATH\client\node_modules\eslint\lib\linter\node-event-generator.js:322:22)
ok, that's great - it means it's reproducible.
What are the contents of that eslint config?
Did you miss my link in my first message? I thought you knew already it was reproducible as I created a repository having the same issue. The content of the eslint config is in that repository: https://github.com/javierguzman/eslint-error/blob/main/client/config/.eslintrc.json
oh sorry, i'll try to use that repo.
got it reproduced, thanks :-)
@javierguzman ok so turns out import/ignore is actually a regexp pattern, and "*.png" isn't a valid one because of both the star and the dot. Changing it to ["\\.png$", "\\.jpg$"] seems to make it correctly produce a lint warning.
yes, I got that behavior using "import/ignore": ["/*.png/", "/*.jpg/"] However, if you open Header.tsx file you should get a red line over import LOGO from '@Images/facebook.png';
https://github.com/javierguzman/eslint-error/blob/main/client/src/Features/Header/Header.tsx
So if the correct one is a regexp, then it is the vscode eslint plugin the one not behaving properly...as it hightlights the import of a png file as red when we have specified to ignore those ones.
["/*.png/", "/*.jpg/"] is incorrect as well, since new RegExp strings are not supposed to be bounded by forward slashes.
Change it to ["\\.png$", "\\.jpg$"] and it should be fine.
The current warning is because it thinks @Images/facebook.png is a package - because that's a valid package name. While aliases are best when they can't be a valid package name, either way, you need a custom resolver to be able to resolve @Images/ so that this plugin can know where it points.
Then that is a bug, isn't? I mean if I use ["/*.png/", /*.jpg/"] the behavior I see is the same as with ["\\.png$", "\\.jpg$"]
On the other hand, I resolve my images in the webpack-common.js file: https://github.com/javierguzman/eslint-error/blob/main/client/config/webpack-common.js
Here I have:
const resolve = {
modules: [srcPath, 'node_modules'],
alias: {
'@Header': path.resolve(srcPath, 'Features', 'Header'),
'@Common': path.resolve(rootPath, '..', 'common'),
'@Images': path.resolve(rootPath, '..', 'common', 'assets', 'images')
},
extensions: ['.ts', '.js', '.tsx', '.jsx'],
fallback: { path: false }
};
no - /*.png/ in a regex means "a slash, 0 or more times, then any character, then png, then a slash".
If you're resolving those with webpack, then you must use the webpack resolver for eslint-plugin-import: https://github.com/import-js/eslint-plugin-import#resolvers
Oh I see, I thought you were saying ["/.png/", /.jpg/"] is not a valid regex, but you meant it is a valid regex but not the one I was looking for 😄
I have the webpack resolver as well:
"settings": {
"import/resolver": {
"node" : {},// due to https://github.com/benmosher/eslint-plugin-import/issues/1396
"webpack": {
"config" : "config/webpack-prod.js",
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
You should always have the node resolver - not just due to that closed issue - but the webpack resolver should be listed first.
I had always node first and it has been working fine. Just in case I have placed webpack stuff first and eslint becomes "crazy" as it tries to look for webpack-prod.js under the node_modules, I guess tue to the filepath.toLowerCase message ( I have even restarted eslint server & vscode without success):
[Info - 8:37:45] ESLint library loaded from: blabla\client\node_modules\eslint\lib\api.js
[Info - 8:37:48] filepath.toLowerCase is not a function Occurred while linting blabla\client\config\webpack-common.js:1
Error resolving webpackConfig Error: Cannot find module 'blabla\client\node_modules\react-bootstrap\config\webpack-prod.js'
Require stack:
- blabla\client\node_modules\eslint-import-resolver-webpack\index.js
- blabla\client\node_modules\eslint-module-utils\resolve.js
- blabla\client\node_modules\eslint-plugin-import\lib\rules\no-unresolved.js
- blabla\client\node_modules\eslint-plugin-import\lib\index.js
- blabla\client\node_modules\@eslint\eslintrc\lib\config-array-factory.js
- blabla\client\node_modules\@eslint\eslintrc\lib\index.js
- blabla\client\node_modules\eslint\lib\cli-engine\cli-engine.js
- blabla\client\node_modules\eslint\lib\cli-engine\index.js
- blabla\client\node_modules\eslint\lib\api.js
- c:\Users\javie\.vscode\extensions\dbaeumer.vscode-eslint-2.1.25\server\out\eslintServer.js
at Function.Module._resolveFilename (internal/modules/cjs/loader.js:934:15)
at Module._load (internal/modules/cjs/loader.js:779:27)
at Function.f._load (electron/js2c/asar_bundle.js:5:12913)
at Module.require (internal/modules/cjs/loader.js:1006:19)
at require (internal/modules/cjs/helpers.js:88:18)
at Object.exports.resolve (blabla\client\node_modules\eslint-import-resolver-webpack\index.js:86:25)
at v2 (blabla\client\node_modules\eslint-module-utils\resolve.js:117:23)
at withResolver (blabla\client\node_modules\eslint-module-utils\resolve.js:122:14)
at fullResolve (blabla\client\node_modules\eslint-module-utils\resolve.js:139:22)
at Function.relative (blabla\client\node_modules\eslint-module-utils\resolve.js:84:10) {
code: 'MODULE_NOT_FOUND',
requireStack: [
'blabla\\client\\node_modules\\eslint-import-resolver-webpack\\index.js',
'blabla\\client\\node_modules\\eslint-module-utils\\resolve.js',
'blabla\\client\\node_modules\\eslint-plugin-import\\lib\\rules\\no-unresolved.js',
'blabla\\client\\node_modules\\eslint-plugin-import\\lib\\index.js',
'blabla\\client\\node_modules\\@eslint\\eslintrc\\lib\\config-array-factory.js',
'blabla\\client\\node_modules\\@eslint\\eslintrc\\lib\\index.js',
'blabla\\client\\node_modules\\eslint\\lib\\cli-engine\\cli-engine.js',
'blabla\\client\\node_modules\\eslint\\lib\\cli-engine\\index.js',
'blabla\\client\\node_modules\\eslint\\lib\\api.js',
'myuser\\.vscode\\extensions\\dbaeumer.vscode-eslint-2.1.25\\server\\out\\eslintServer.js'
]
}
Try ./config/webpack-prod.js? (note the leading dot)
It seems better but the message "[Info - 9:32:30] filepath.toLowerCase is not a function Occurred while linting " still appears and makes no difference in the whole behavior. The alias image import is still hightlighted as red. Bear in mind other imports do not have this problem. Right now, it is like the import/ignore is not read properly by vscode eslint plugin. I am going to open an issue in plugin repo as well to check if they can add something.
I have run again npx eslint ./src/features/Header/Header.tsx -c ./config/.eslintrc.json and still complains about the extraneous dependency, so it is not the plugin I believe.
Hello @ljharb do you any other ideas? I am still facing the same issue. When I mentioned before "is not the plugin I believe" I meant the VSCode plugin.
I don't yet have any other ideas; I'll keep playing with the repo.
Any news about this @ljharb ?
Hello @ljharb , is there someone else who might be able to give a hand? or any other channels? I would not like to see this issue forgotten in the darkness. Thank you in advance.
Anyone who wants can help; there’s no other maintainers in practical terms. It remains on my list.
And is there any Discord or Slack channels for ESLint? I am just asking because I imagine you might be overwhelmed being the only one around here trying to help everybody. Being ESLint such a popular ecosystem does not help either :smile:
I have continued looking at this and I believe the problem could be summarized to "How to make an alias to an outside project folder".
If I import a TS file from @Common then I get a similar error. However, if I remove the alias and use relative paths ( a ton of ../../) then it works ok.
From the tests I have made, I think the trick is to have properly webpack configuration resolve.alias section (https://github.com/javierguzman/eslint-error/blob/main/client/config/webpack-common.js) AND tsconfig.json(https://github.com/javierguzman/eslint-error/blob/main/client/tsconfig.json). However, for now I have not discovered what it is missing.
If someone can spot the problem I am all ears.
Yes, webpack aliases should work if you’re using the webpack resolver and webpack is configured correctly. If you’re using TS then tsconfig also has to have the same info.