eslint vscode plugin is not producing warnings for hooks - reactjs

I created a react app with npx create-react-app my-app and did a yarn install. Added the following to App.js:
const a = () => 1,
b = () => 2,
c = () => 3;
function App() {
const wut = useMemo(() => {
return { a: a(), b: b(), c: c() };
}, [a]);
useEffect(() => {
console.log(a(), b(), c());
}, [a]);
Yarn start will give me warnings but vscode does not.
I added .eslintrc.js with the following content:
module.exports = {
env: {
browser: true,
es6: true
},
extends: ["eslint:recommended", "plugin:react/recommended"],
globals: {
Atomics: "readonly",
SharedArrayBuffer: "readonly"
},
parserOptions: {
ecmaFeatures: {
jsx: true
},
ecmaVersion: 2018,
sourceType: "module"
},
plugins: ["react"],
rules: {
"react/prop-types": [0],
"no-console": [0],
"react-hooks/exhaustive-deps": "warn"
}
};

The list of rules for react/recommended doesn't include react-hooks/exhaustive-deps.
You likely didn't install eslint-plugin-react-hooks.
It includes a note:
Note: If you're using Create React App, please wait for a corresponding release of react-scripts that includes this rule instead of adding it directly.
What version of c-r-a are you using? In theory it was added via this PR.

I'm using TypeScript, so the answer for me was to add the following to my VSCode settings:
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],

If I have the following code in a clean create-react-app:
function App(props) {
const {a,b,c}=props;
const wut = useMemo(() => {
console.log("this should not happen multiple times");
return { a: a(), b: b(), c: c() };
}, [a]);
useEffect(() => {
console.log(a(), b(), c());
}, [a]);
Then removing the .eslintrc.js would give me the React Hook useMemo has missing dependencies: warning and the option to auto fix it.
When I have the .eslintrc.js in project root directory I get the error Definition for rule 'react-hooks/exhaustive-deps' was not found. this is because the .eslintrc.js was missing a plugin and plugins: ["react", "react-hooks"], solved it.
However; now the rule is off by default so it won't warn, needed to explicitly add the rule and set it to warn (or error) in the .eslintrc.js:
rules: {
"react-hooks/exhaustive-deps": "error"
}

Related

Field 'browser' doesn't contain a valid alias configuration for storybook in react

The project is nextjs. align written in jsconfig.json file and it is working when i run the project. the problam is when i run yarn storybook
.storybook/main.js file
module.exports = {
addons: ["#storybook/addon-links", "#storybook/addon-essentials"],
core: {
builder: {
name: "webpack5",
options: {
fsCache: true,
},
},
},
stories: ["../src/**/*.stories.#(js|mdx)"],
};
I use a module resolver, like the following line of code, to fix the problem.
webpackFinal: async (config, { configType }) => {
config.resolve.alias = {
...config.resolve.alias,
"#hooks": path.resolve(__dirname, "../src/hooks"),
.
.
.
}
}

Next js jest coverage

I am using in my next js application Cypress and Jest. Running jest --coverage i get an error:
STACK: Error: Duplicate plugin / preset detected.
If you 'd like to use two separate instances of a plugin,
they need separate names, e.g.
plugins: [
['some-plugin', {}],
['some-plugin', {}, 'some unique name'],
]
This is my .babelrc file:
{
"presets": ["next/babel"],
"plugins": ["istanbul"]
}
Who faced with the same issue and how to solve it to get the coverage?
I found the solution that helped to solve the problem.
I had to add the env variable to the .babelrc
{
"env": {
"component": {
"plugins": [
"istanbul"
]
}
}
}
Then add it to cypress.config.js
const { defineConfig } = require('cypress');
const { devServer } = require('#cypress/webpack-dev-server');
const webpackConfig = require('./config/cypress.webpack.config.js');
const codeCoverageTask = require('#cypress/code-coverage/task');
module.exports = defineConfig({
viewportWidth: 1000,
viewportHeight: 660,
video: false,
env: {
BABEL_ENV: 'component',
},
component: {
devServer(devServerConfig) {
return devServer({
...devServerConfig,
framework: 'react',
webpackConfig,
});
},
specPattern: 'src/**/*.cy.{js,ts,jsx,tsx}',
setupNodeEvents(on, config) {
codeCoverageTask(on, config);
return config;
},
},
});

Web Worker - Jest - Cannot use 'import.meta' outside a module

I'm working on a nextjs 10.1.3 built-in web application. We implemented a web worker to boost up the performance in one of the pages and the plan is to continue adding more workers; also, all the code is properly unit tested, and using the worker-loader in previous webpack versions (4th and below) we were able to test it.
With the new webpack 5 version, the worker-loader plugin is not needed anymore; instead, the way to load a web worker using the new version is new Worker(new URL("#/workers/task.worker.js", import.meta.url));.
Doing it this way, my code is working as expected with npm build && npm start; however, when I try to add the respective unit tests I got the following error: Cannot use 'import.meta' outside a module and everything happens because of the import.meta.url used to add the location of the worker in the browser.
I read many posts on the web regarding babel but I want to get away from that option. Is there any other option to mock the import.meta.url with jest?
Any help will be very welcome. This is the current configuration.
package.json
{
...
"#babel/core": "^7.8.6",
"next": "^10.1.3",
"react": "^16.13.0",
"webpack": "^5.37.1"
"devDependencies": {
...
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"jest": "^24.9.0",
"jest-cli": "^25.1.0",
...
}
...
}
next.config.js
const {
...
} = process.env;
const basePath = "";
const COMMIT_SHA = [];
const { parsed: localEnv } = require("dotenv").config();
const webpack = require("webpack");
const withBundleAnalyzer = require("#next/bundle-analyzer")({
enabled: process.env.ANALYZE === "true",
});
const nextConfig = {
env: {
NEXT_PUBLIC_COMMIT_SHA: COMMIT_SHA,
},
images: {
domains: [
"...",
],
},
future: {
webpack5: true,
},
productionBrowserSourceMaps: true,
trailingSlash: true,
reactStrictMode: true,
webpack: (config, options) => {
if (localEnv) {
config.plugins.push(new webpack.EnvironmentPlugin(localEnv));
} else {
config.plugins.push(new webpack.EnvironmentPlugin(process.env));
}
config.module.rules.push({
test: /\.(eot|woff|woff2|ttf|svg|png|jpg|gif)$/,
use: {
loader: "url-loader",
options: {
limit: 100000,
name: "[name].[ext]",
},
},
});
config.output = {
...config.output,
chunkFilename: options.isServer
? `${options.dev ? "[name]" : "[name].[fullhash]"}.js`
: `static/chunks/${options.dev ? "[name]" : "[name].[fullhash]"}.js`,
publicPath: `/_next/`,
globalObject: `(typeof self !== 'undefined' ? self : this)`,
};
config.plugins.push(new webpack.IgnorePlugin(/pages.*\/__tests__.*/));
config.plugins.push(
new options.webpack.DefinePlugin({
"process.env.NEXT_IS_SERVER": JSON.stringify(
options.isServer.toString()
),
})
);
return config;
},
};
module.exports = withBundleAnalyzer(nextConfig);
The useEffect worker
useEffect(() => {
if (pageData.data?.length) {
workerRef.current = new Worker(new URL("#/workers/task.worker.js", import.meta.url));
workerRef.current.addEventListener("message", result => {
if (result.error) {
setWorkerError();
} else {
updateData(result.data);
}
});
const ids = pageData.data.map(store => store.id);
workerRef.current.postMessage(ids);
} else {
setNoDataFound();
}
return () => {
workerRef.current && workerRef.current.terminate();
};
}, []);
jest.config.js
module.exports = {
moduleDirectories: ["node_modules", "src", "static", "store"],
modulePathIgnorePatterns: [
"<rootDir>/node_modules/prismjs/plugins/line-numbers",
],
testPathIgnorePatterns: [
"<rootDir>/src/components/component-library",
"<rootDir>/.next",
"jest.config.js",
"next.config.js",
],
collectCoverageFrom: [
"**/src/**",
"**/store/**",
"**/pages/**",
"!**/__tests__/**",
"!**/node_modules/**",
"!**/component-library/**",
],
testEnvironment: "node",
collectCoverage: true,
verbose: false,
automock: false,
setupFiles: ["./setupTests.js"],
moduleNameMapper: {
"#/components/(.*)$": "<rootDir>/src/components/$1",
"#/functions/(.*)$": "<rootDir>/src/components/functions/$1",
"#/services/(.*)$": "<rootDir>/src/components/services/$1",
"#/workers/(.*)$": "<rootDir>/src/components/workers/$1",
"#/scripts(.*)$": "<rootDir>/src/scripts/$1",
"#/src(.*)$": "<rootDir>/src/$1",
"#/__mocks__(.*)$": "<rootDir>/__mocks__/$1",
"#/pages(.*)$": "<rootDir>/pages/$1",
"#/store(.*)$": "<rootDir>/store/$1",
"\\.(css|less)$": "<rootDir>/__mocks__/styleMock.js",
},
coveragePathIgnorePatterns: ["/node_modules/"],
coverageThreshold: {
global: {
branches: 67,
functions: 66,
lines: 73,
statements: 72,
},
},
runner: "groups",
extraGlobals: [],
testTimeout: 10000,
};
In my setup (typescript + ts-jest) I prepended the following node option to make it work:
NODE_OPTIONS=--experimental-vm-modules
Reference can be found here: https://jestjs.io/docs/ecmascript-modules

Disable in EsLint "react / jsx-props-no-spreading" error in Reactjs

After installing EsLint one of the errors that appears to me is the following:
Prop spreading is forbiddeneslint(react/jsx-props-no-spreading)
I want to create a rule in the EsLint configuration to ignore this error but the examples I found do not work.
This is the format to create a global exception:
...
"react/jsx-props-no-spreading": [{
"html": "ignore" / "enforce",
"custom": "ignore" / "enforce",
"exceptions": [<string>]
}]
...
And this is the format to create an exception in a specific file:
{
"rules": {...},
"overrides": [
{
"files": ["*-test.js","*.spec.js"],
"rules": {
"no-unused-expressions": "off"
}
}
]
}
And here, the code that I currently have:
module.exports = {
extends: "../../.eslintrc.js",
rules: {
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}]
},
env: {
"jest": true
}
};
At the moment, I just keep giving the same error continuously.
Thank you.
Try turning off the "react/jsx-props-no-spreading" rule:
module.exports = {
extends: "../../.eslintrc.js",
rules: {
"import/no-extraneous-dependencies": ["error", {"devDependencies": true}],
"react/jsx-props-no-spreading": "off",
},
env: {
"jest": true
}
};
As an example if there is not so much errors you can ignore them by
// eslint-disable-next-line
Or you can write for concrete error like
// eslint-disable jsx-props-no-spreading

Usage of Promise in webpack / react application

I am trying to use Promise in an react app using webpack but I have this error :
'Promise' is not defined no-undef
So far, everything was working well (used babel to translate js and jsx) but unfortunately Promise does not work.
Furthermore, I have this error in Chrome (latest) and I though Promise was buildin feature.... Am I right ?
Here is a piece of config that I use (I used survivejs kanban app as a starter, I am trying to add some functionalities). I did not change much the initial config :
From web pack.config.js
module: {
loaders: [
{
test: /\.(js|jsx)$/,
// Enable caching for extra performance
loaders: ['babel?cacheDirectory'],
include: include
}
]
}
From .babelrc
{
"presets": [
"es2015",
"react"
],
"env": {
"start": {
"presets": [
"react-hmre"
]
}
}
}
Failing code :
const locales = {
en: () => require('react-intl?locale=en!./en.json'),
fr: () => require('react-intl?locale=fr!./fr.json')
}
function loadLocaleData (locale) {
return new Promise((resolve) => {
locales[locale]()(resolve)
})
}
THE VALID ANSWER IS IN COMMENTS
So far as I know you need te include a Promise polyfill in your webpack config. I use:
plugins: [
new webpack.ProvidePlugin({
'Promise': 'exports?global.Promise!es6-promise'
})
],
Where es6-promise is a npm package which will be include when no promise is available or added by any other npm package

Resources