Related
Having some strange behaviour when trying to configure ESlint(global install) and babel:
Editor(VSCode) showing error on top most import:
Resolve error: TypeError: Cannot read properties of undefined (reading 'ENV')
at module.exports (.....\client\webpack.config.js:29:44)
at Object.exports.resolve (.....\client\node_modules\eslint-import-resolver-webpack\index.js:107:21)
while running npm run lint on the whole project throws:
.......\client\webpack.config.js
0:0 error Parsing error: No Babel config file detected for .......\client\webpack.config.js. Either disable config file checking with requireConfigFile: false, or configure Babel so that it can find the config files
for every file it's trying to parse.
eslintrc.json
{
"globals": {
"graphql": true,
"theme": true,
"classes": true
},
"env": {
"browser": true,
"es6": true,
"node": true
},
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"plugin:jsx-a11y/recommended",
"plugin:import/recommended"
],
"parser": "#babel/eslint-parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true,
"globalReturn": false
},
"ecmaVersion": "latest",
"sourceType": "module",
"babelOptions": {
"root": "./client/"
}
},
"plugins": [
"react",
"unused-imports",
"#babel",
"react-hooks",
"jsx-a11y",
"import"
],
"rules": {
"indent": [
"error",
4
],
"linebreak-style": [
"error",
"windows"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"never"
],
"react/jsx-uses-react": "error",
"react/jsx-uses-vars": "error",
"react/jsx-pascal-case": [
2,
{
"allowAllCaps": true
}
],
"jsx-quotes": [
"error",
"prefer-single"
],
"react/jsx-closing-bracket-location": [
1,
"tag-aligned"
],
"react/jsx-closing-tag-location": 1,
"no-multi-spaces": [
"error",
{
"ignoreEOLComments": true
}
],
"react/jsx-tag-spacing": 2,
"react/jsx-boolean-value": [
2,
"never"
],
"react/self-closing-comp": [
"error",
{
"component": true,
"html": true
}
],
"react/prop-types": "off",
"import/no-unresolved": [
"error",
{
"caseSensitive": false
}
],
"no-unused-vars": ["error", { "vars": "local", "args": "after-used" }], // or "#typescript-eslint/no-unused-vars": "off",
"unused-imports/no-unused-imports": "off",
"unused-imports/no-unused-vars": [
"warn",
{
"vars": "all",
"varsIgnorePattern": "^_",
"args": "after-used",
"argsIgnorePattern": "^_"
}
],
"react/no-unknown-property": [
"error",
{
"ignore": [
"css"
]
}
],
"import/order": ["error", {
"newlines-between": "always",
"groups": ["builtin", "external", "internal", ["sibling", "parent"], "index"],
"alphabetize": {
"order": "asc"
}
}],
"import/namespace": "error",
"import/no-duplicates": "error",
"import/no-self-import": "error",
"react-hooks/exhaustive-deps": "error",
"object-curly-spacing": ["error", "always"],
"template-curly-spacing": ["error", "always"],
"react/jsx-curly-spacing": ["error", {"when": "always"}]
},
"settings": {
"react": {
"createClass": "createReactClass", // Regex for Component Factory to use,
// default to "createReactClass"
"pragma": "React", // Pragma to use, default to "React"
"fragment": "Fragment", // Fragment to use (may be a property of <pragma>), default to "Fragment"
"version": "detect", // React version. "detect" automatically picks the version you have installed.
// You can also use `16.0`, `16.3`, etc, if you want to override the detected value.
// default to latest and warns if missing
// It will default to "detect" in the future
"flowVersion": "0.53" // Flow version
},
"propWrapperFunctions": [
// The names of any function used to wrap propTypes, e.g. `forbidExtraProps`. If this isn't set, any propTypes wrapped in a function will be skipped.
"forbidExtraProps",
{
"property": "freeze",
"object": "Object"
},
{
"property": "myFavoriteWrapper"
},
// for rules that check exact prop wrappers
{
"property": "forbidExtraProps",
"exact": true
}
],
"componentWrapperFunctions": [
// The name of any function used to wrap components, e.g. Mobx `observer` function. If this isn't set, components wrapped by these functions will be skipped.
"observer", // `property`
{
"property": "styled"
}, // `object` is optional
{
"property": "observer",
"object": "Mobx"
},
{
"property": "observer",
"object": "<pragma>"
} // sets `object` to whatever value `settings.react.pragma` is set to
],
"formComponents": [
// Components used as alternatives to <form> for forms, eg. <Form endpoint={ url } />
"CustomForm",
{
"name": "Form",
"formAttribute": "endpoint"
}
],
"linkComponents": [
// Components used as alternatives to <a> for linking, eg. <Link to={ url } />
"Hyperlink",
{
"name": "Link",
"linkAttribute": "to"
}
],
"import/resolver": {
"node": {
"paths": [
"client/src",
"src"
],
"extensions": [
".js",
".jsx",
".ts",
".tsx"
]
},
"webpack": {
"config": "webpack.config.js"
}
}
}
}
babel.config.json
{
"presets": [
"#babel/env",
"#babel/react",
"#emotion/babel-preset-css-prop"
],
"plugins": [
"syntax-dynamic-import",
"react-hot-loader/babel",
"#babel/plugin-transform-react-jsx-source"
]
}
webpack.config.js
const path = require('path')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const dotenv = require('dotenv')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
const port = 3000
const host = '0.0.0.0'
module.exports = (env) => {
const currentPath = path.join(__dirname)
const envPath = currentPath + `/${ env.ENV }.env`
const fileEnv = dotenv.config({ path: envPath }).parsed
const envKeys = Object.keys(fileEnv).reduce((prev, next) => {
prev[`process.env.${ next }`] = JSON.stringify(fileEnv[next])
return prev
}, {})
const isProd = (env.ENV === 'prod')
return {
mode: isProd ? 'production': 'development',
entry: [
path.resolve('src', 'index.js')
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: isProd ? '[name].[chunkhash].js' : '[name].[hash:8].js',
chunkFilename: isProd ? '[id].[chunkhash].js' : '[id].[hash:8].js',
sourceMapFilename: isProd ? '[name].[chunkhash].map' : '[name].[hash:8].map',
},
module: {
rules: [
{
test: /\.(jpe?g|png|svg)$/i,
type: 'asset',
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ['babel-loader']
},
{
test:/\.css$/,
//include: path.resolve(__dirname, 'node_modules'),
use: ['style-loader', 'css-loader']
},
{
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
exclude: /node_modules/,
use: [{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'content/fonts/'
}
}]
}
]
},
resolve: {
extensions: ['.js', '.jsx', 'json'],
modules: [path.join(__dirname, 'src'), 'node_modules'],
alias: {
react: path.join(__dirname, 'node_modules', 'react'),
services: path.join(__dirname, 'src/services/'),
utils: path.join(__dirname, 'src/utils/'),
Redux: path.join(__dirname, 'src/redux/'),
scss: path.join(__dirname, 'src/scss/'),
hooks: path.join(__dirname, 'src/hooks/'),
config: path.join(__dirname, 'src/config/'),
components: path.join(__dirname, 'src/components/'),
modules: path.join(__dirname, 'src/modules/'),
locales: path.join(__dirname, 'src/locales/'),
routes: path.join(__dirname, 'src/routes/')
},
preferRelative: true,
roots: [path.resolve(__dirname), 'content']
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{
from:'src/content/images',
to: 'content/images',
globOptions: {
ignore: ['**/index.html']
}
}
],
}),
new HtmlWebpackPlugin({
template: './src/index.html',
filename: 'index.html',
inject: 'body',
//favicon: './content/favicon.ico'
}),
new webpack.DefinePlugin(envKeys)
],
devtool: 'eval-cheap-source-map',
devServer: {
hot: true,
host: host,
port: port,
historyApiFallback: true,
headers: { 'Access-Control-Allow-Origin': '*' },
static: {
directory: path.resolve(__dirname, 'content'),
publicPath: '/content'
}
}
}
}
Edit: I fixed the VSCode complaining with adding this to eslintrc's import-resolver rule:
"webpack": {
"config": "webpack.config.js",
"env":{
"ENV": "dev",
"production": false
}
}
TS is not inferring the type when using resolved imports, but it does when using relative imports. Any help would be appreciated.
useTheme has
"Unsafe call of an 'any' typed value."
This error does not show up if i use a relative import instead of '#theme/Theme'
My project structure is:
Here are my config files:
tsconfig.json
{
"extends": "../../tsconfig.json", // standard tsconfig params
"compilerOptions": {
"jsx": "react-native" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
"baseUrl": "." /* Base directory to resolve non-absolute module names. */,
"paths": {
"#components/*": ["./src/common/components/*"],
"#theme/*": ["./src/lib/theme/*"],
"#hooks/*": ["./src/common/hooks/*"],
"#features/*": ["./src/features/*"]
},
"typeRoots": [
"./typings",
"../../node_modules/#types"
] /* List of folders to include type definitions from. */
},
"include": ["../"],
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js"
]
}
babel.config.js
module.exports = {
presets: [
'module:metro-react-native-babel-preset',
'#babel/preset-typescript',
],
plugins: [
['#babel/plugin-proposal-optional-chaining'],
['#babel/plugin-proposal-nullish-coalescing-operator'],
['#babel/plugin-proposal-decorators', { legacy: true }],
[
'module:react-native-dotenv',
{
moduleName: '#env',
path: '.env',
},
],
[
'module-resolver',
{
alias: {
'#components': './src/common/components',
'#theme': ['./src/lib/theme'],
'#hooks': ['./src/common/hooks'],
'#features': ['./src/features'],
},
extensions: ['.js', '.jsx', '.ts', '.tsx'],
root: '.',
},
],
'react-native-reanimated/plugin',
],
};
.eslintrc
{
"root": true,
"extends": [
"airbnb-typescript", // React "airbnb-typescript/base" for just js. "airbnb","airbnb/base" for no TypeScript
"airbnb/hooks", // React
"plugin:#typescript-eslint/eslint-recommended",
"plugin:#typescript-eslint/recommended",
"plugin:#typescript-eslint/recommended-requiring-type-checking",
"#react-native-community" // React Native only
],
"parser": "#typescript-eslint/parser", // TypeScript only
"parserOptions": {
"project": "./tsconfig.json", // TypeScript only
"ecmaFeatures": { "jsx": true }
},
"settings": {
"import/resolver": {
"babel-module": {}
}
},
"plugins": ["import", "#typescript-eslint"],
"ignorePatterns": ["*.config.js"],
"overrides": [
{
/** Testing Files Extensions */
"files": ["*.{spec,test}.{js,ts,tsx}", "e2e/*.{js,ts,tsx}"],
"plugins": ["jest"],
"env": { "jest/globals": true },
"rules": {
"import/no-extraneous-dependencies": 0 // Allow dev-dependency imports
}
}
],
"rules": {
"no-unused-vars": [
"error",
{
"args": "none",
"caughtErrors": "none",
"ignoreRestSiblings": true,
"vars": "all"
}
],
// resolve "import/extensions"
"import/extensions": [
"error",
"ignorePackages",
{
"ts": "never",
"tsx": "never"
}
],
"curly": ["error", "multi-line"],
"no-void": ["error"], // Allow void as statement in order to ignore promise returns
"prettier/prettier": 0, // Disable Prettier
"import/no-cycle": 0, // Slows down all linting
"react/jsx-props-no-spreading": 0, // Enable Prop Spreading
"#typescript-eslint/no-empty-interface": 0, // Allow boilerplate empty interfaces for defining component props explicitly
"#typescript-eslint/no-unsafe-assignment": 0,
"#typescript-eslint/naming-convention": [
2,
{
"leadingUnderscore": "allow",
"format": ["camelCase", "PascalCase", "UPPER_CASE", "snake_case"],
"selector": "variable"
}
],
"#typescript-eslint/no-explicit-any": 0, // disabled to avoid using any type
"#typescript-eslint/no-use-before-define": "off",
"#typescript-eslint/restrict-template-expressions": 0,
"#typescript-eslint/no-floating-promises": [2, { "ignoreIIFE": true }], // Fixes issue where async await syntax wasn't being recognised.
"#typescript-eslint/explicit-function-return-type": [
0,
{ "allowExpressions": false }
],
"#typescript-eslint/no-unused-vars": [2, { "varsIgnorePattern": "^_" }],
// Fixes false-positives for enums in typescript https://github.com/typescript-eslint/typescript-eslint/issues/2484#issuecomment-687257773
"no-shadow": "off",
"#typescript-eslint/no-shadow": ["error"],
"max-len": [
"warn",
{
"code": 120,
"tabWidth": 2,
"ignoreComments": true,
"ignoreStrings": true,
"ignoreRegExpLiterals": true,
"ignoreTemplateLiterals": true
}
]
}
}
if you work in vscode, try use "TypeScript: Select TypeScript version" to select you workspace version
I do have an react-native project.
I've upgraded to recent react and react-native version, even as all other packages in the project.
As React 17 brings the JSX-Transform (https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#manual-babel-setup) I followed those steps to use it in my app.
But at least it doesn't work as expected.
I wonder if the new JSX-Transform feature doesn't be usable for react-native APP's, but only for general react webprojects?!
This is my babel.config.js:
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'#babel/plugin-proposal-decorators',
{
legacy: true,
},
],
[
'#babel/plugin-transform-react-jsx',
{
runtime: 'automatic',
},
],
'react-native-reanimated/plugin',
],
};
this my eslintrc.json:
{
"parser": "#babel/eslint-parser",
"env": {
"browser": true,
"react-native/react-native": true,
"es6": true,
"node": true
},
"extends": [
"#react-native-community",
"plugin:react/recommended",
"airbnb-base",
"prettier/react"
],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly"
},
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 2018,
"sourceType": "module"
},
"plugins": [
"react",
"react-native",
"prettier"
],
"rules": {
"react/jsx-uses-react": "off",
"react/react-in-jsx-scope": "off",
"object-curly-newline": 0,
"max-len": [
"error",
{
"code": 100,
"comments": 150,
"ignoreTrailingComments": true,
"ignoreUrls": true
}
],
"indent": [
"warn",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
2,
"single",
{
"avoidEscape": true,
"allowTemplateLiterals": true
}
],
"semi": [
"error",
"always"
],
"react-native/no-unused-styles": 2,
"react-native/split-platform-components": 2,
"react-native/no-inline-styles": 2,
"react-native/no-color-literals": 2,
"react-native/no-raw-text": 2,
"prettier/prettier": [
"warn",
{
"endOfLine": "auto",
"bracketSpacing": true
}
]
}
}
You can try this solution to make it work with react native
https://github.com/facebook/metro/issues/646#issuecomment-799174473
So by using both useTransformReactJSXExperimental and runtime settings in babel configuration file.
Case 1 (PrintWidth):
What happens in this case is the following, I have configured printWidth in the .prettierrc file, in the vscode settigns.json and in the .eslintrc.js. However, when reaching the max-length, which in this case is 120, the prettier does not apply its styling.
Case 2 (.prettierignore)
The prettier simply ignores this file and does not apply the rules it contains.
Desired resolution for Case 1:
When eslint verifies that the code is at the limit of the line size, which in this case is 120 and greater than the limit, it "breaks" the code, such as, for example, lowering the properties of the JSX components etc.
Desired resolution for Case 2:
That the prettier can use the .prettierignore file
MY VSCODE SETTINGS:
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.rulers": [120, 120]
MY PRETTIER CONFIG:
{
"printWidth": 120,
"tabWidth": 2,
"useTabs": true,
"semi": true,
"singleQuote": true,
"jsxSingleQuote": true,
"jsxBracketSameLine": false,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"quoteProps": "as-needed",
"trailingComma": "none"
}
MY ESLINTRC CONFIG:
module.exports = {
env: {
browser: true,
es2021: true
},
extends: [
'plugin:react/recommended',
'plugin:react-hooks/recommended',
'plugin:prettier/recommended',
'plugin:import/errors',
'plugin:import/warnings',
'react-app',
'react-app/jest',
'airbnb'
],
parser: '#typescript-eslint/parser',
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 5,
sourceType: 'module'
},
plugins: ['react', 'react-hooks', 'prefer-arrow', 'prettier', '#typescript-eslint'],
settings: {
react: {
version: 'detect'
},
'import/resolver': {
node: {
paths: ['src'],
moduleDirectory: ['node_modules', 'src/'],
extensions: ['.js', '.jsx', '.ts', '.tsx']
}
}
},
overrides: [
{
files: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
plugins: ['#typescript-eslint'],
rules: {
'no-use-before-define': 'off',
'#typescript-eslint/no-use-before-define': ['error']
}
}
],
ignorePatterns: ['src/assets/images/*', 'src/assets/fonts/*'],
rules: {
'#typescript-eslint/no-unused-vars': ['error'],
'prettier/prettier': 'error',
'arrow-body-style': 'off',
'arrow-parens': ['error', 'always'],
'object-curly-newline': 'off',
'no-tabs': 0,
indent: [2, 'tab', { SwitchCase: 1 }],
'comma-dangle': ['error', 'never'],
'max-len': ['error', { code: 120 }],
'jsx-quotes': ['error', 'prefer-single'],
'implicit-arrow-linebreak': 'off',
'operator-linebreak': [
'error',
'after',
{
overrides: {
':': 'before'
}
}
],
'react-hooks/rules-of-hooks': 'error', // Checks rules of Hooks
'react-hooks/exhaustive-deps': 'warn', // Checks effect,
'react/jsx-indent-props': 'off',
'react/react-in-jsx-scope': 'off',
'react/jsx-props-no-spreading': 'off',
'react/jsx-boolean-value': 'off',
'react/jsx-indent': ['error', 'tab', { checkAttributes: true, indentLogicalExpressions: true }],
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.ts', '.tsx'] }],
'react/jsx-wrap-multilines': [
'error',
{
declaration: 'parens-new-line',
assignment: 'parens-new-line',
return: 'parens-new-line',
arrow: 'parens-new-line',
condition: 'parens-new-line',
logical: 'parens-new-line',
prop: 'parens-new-line'
}
],
'prefer-arrow-callback': 'off',
'prefer-arrow/prefer-arrow-functions': [
'error',
{
disallowPrototype: true,
singleReturnOnly: false,
classPropertiesAllowed: false
}
],
'import/prefer-default-export': 'off',
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never'
}
]
}
};
I am using JEST and Enzyme. In my eslint file I have added jest as true under env. But I get a lint error for shallow as I have included it globally. Error is- error 'shallow' is not defined no-undef
setupTests.js
//as we are accessing our application with a http://localhost prefix, we need to update our jest configuration
import { shallow, render, mount, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';
// React 16 Enzyme adapter
configure({ adapter: new Adapter() });
// Make Enzyme functions available in all test files without importing
global.shallow = shallow;
global.render = render;
global.mount = mount;
.eslintrc
{
parser: "babel-eslint",
"extends": ["airbnb"],
"env": {
"browser": true,
"jest": true
},
"rules": {
"max-len": [1, 200, 2, {ignoreComments: true}],
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-underscore-dangle": [0, { "allow": [] }],
"jsx-a11y/label-has-associated-control": [
"error", {
"required": {
"every": [ "id" ]
}
}
],
"jsx-a11y/label-has-for": [
"error", {
"required": {
"every": [ "id" ]
}
}
]
}
}
app.test.js
import React from 'react';
import { LoginFormComponent } from '../../components';
describe('LoginForm', () => {
const loginform = shallow(<LoginFormComponent />);
it('renders correctly', () => {
expect(loginform).toMatchSnapshot();
});
});
package.json
"scripts": {
"dev": "webpack-dev-server --historyApiFallback true --port 8888 --content-base build/",
"test": "jest",
"lint": "eslint ./src",
"lintfix": "eslint ./src --fix"
},
"jest": {
"verbose": true,
"testURL": "http://localhost/",
"transform": {
"^.+\\.js$": "babel-jest"
},
"setupFiles": [
"./setupTests.js"
],
"snapshotSerializers": [
"enzyme-to-json/serializer"
]
},
The error comes in my app.test.js where I am trying to use shallow. Do I have to add something in my eslint config for enzyme the way I have made jest as true?
How about add global statement? eslint no-undef docs
/*global someFunction b:true*/
/*eslint no-undef: "error"*/
var a = someFunction();
b = 10;
or set global on .eslintrc (eslint global)
{
"globals": {
"shallow": true,
"render": true,
"mount": true
}
}
Updated .eslintrc
{
parser: "babel-eslint",
"extends": ["airbnb"],
"env": {
"browser": true,
"jest": true
},
"globals": {
"shallow": true
},
"rules": {
"max-len": [1, 200, 2, {ignoreComments: true}],
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-underscore-dangle": [0, { "allow": [] }],
"jsx-a11y/label-has-associated-control": [
"error", {
"required": {
"every": [ "id" ]
}
}
],
"jsx-a11y/label-has-for": [
"error", {
"required": {
"every": [ "id" ]
}
}
]
}
}
Since globals are only used in test files the best practise is not to set them globally but only for the test files. That can be done by using overrides property with proper files glob:
overrides: [
{
files: "*.test.js",
globals: {
shallow: true,
render: true,
mount: true,
},
},
],
Full .eslintrc after addition in the snippet.
{
"parser": "babel-eslint",
"extends": ["airbnb"],
"env": {
"browser": true,
"jest": true
},
"rules": {
"max-len": [1, 200, 2, { "ignoreComments": true }],
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"no-underscore-dangle": [0, { "allow": [] }],
"jsx-a11y/label-has-associated-control": [
"error",
{
"required": {
"every": ["id"]
}
}
],
"jsx-a11y/label-has-for": [
"error",
{
"required": {
"every": ["id"]
}
}
]
},
"overrides": [
{
"files": "*.test.js",
"globals": {
"shallow": true,
"render": true,
"mount": true
}
}
]
}