Create a custom ESLint Plugin — In a Simple and easy way

hariom sinha
4 min readNov 20, 2023

--

ESLint is one of the tools to analyse problematic patterns found in the JS Code. Rules are configurable and new rules can be added in the ESLint configuration based on our requirements.

We have used many ESLint plugins to identify any code errors in JS. In this article, I will guide you to create your own custom ESLint plugin.

Credits: Google Images

My Project Structure —

Credits: Self

Step By Step Guide :

  1. Create a React app using CRA :
npx create-react-app react-js-custom-eslint-plugin

2. Install basic plugins to run ESLint :

npm install eslint eslint-plugin-react eslint-plugin-react-hooks --save-dev

3. Add a script to run ESLint :

./package.json

"lint": "eslint src/**/*.js"

3. Run the app and test the ESLint work

npm run lint

4. You will see below errors from ESLint :

Credits: Self

5. Now let's create your own custom ESLint Plugin.

Important Note:

For a custom ESlint plugin, we need to create a plugin folder with a package.json in it.

This plugin will have its own rules.

We need to add this plugin to the project’s global .eslintrc file.

Finally, we must add this plugin as a dependency in our package.json file.

6. Create a plugins folder. Plugins folder can have multiple numbers of custom plugins, so create a subfolder for your own plugin. Remember, folder names can be anything.

The custom plugin folder should have a package.json file and an index.js file that will contain the rule.

You can also initialise the plugin folder by running:

npm init
Credits: Self

7. Add your custom rule to the index.js file.

Important Note: This plugin will read imports in each file and will scan for imports with source “file/bad-import”. If there are any occurrences of this source in any of the imports, it will complain.

react-js-custom-eslint-plugin/plugins/no-bad-imports/index.js
-------------------------------------------------------------

module.exports = {
rules: {
"no-bad-imports": {
create: function (context) {
return {
ImportDeclaration(node) {
if (node.source.value === "file/bad-import") {
context.report({
node,
message: "Do not use bad imports",
});
}
},
};
},
},
},
};
react-js-custom-eslint-plugin/plugins/no-bad-imports/package.json
-----------------------------------------------------------------

{
"name": "eslint-plugin-no-bad-import",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}

Important Note: Plugin name should start with prefix — “eslint-plugin-

8. Now add this plugin to the project’s global .eslintrc file.

react-js-custom-eslint-plugin/.eslintrc.js
------------------------------------------

module.exports = {
env: {
browser: true,
es2021: true,
},
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
],
parserOptions: {
ecmaVersion: 12,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
plugins: ["react", "react-hooks", "no-bad-imports"],
rules: {
"no-bad-imports/no-bad-imports": 2, // 0 : OFF, 1 : WARN, 2 : ERROR
},
};

Important Note: We can have three states for a custom rule in eslint.

0 — OFF
1 — WARN
2 — ERROR

Also,
rules object structure —
pluginName/ruleName : STATE

9. Now, at last, add this plugin as a dependency to the project.

react-js-custom-eslint-plugin/package.json
------------------------------------------

{
"name": "react-js-custom-eslint-plugin",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.js"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"eslint": "^8.53.0",
"eslint-plugin-no-bad-imports": "file:plugins/no-bad-imports",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0"
}
}

10. Now run the plugin and test it.

npm run lint

11. Sample App.js

import logo from './logo.svg';
import './App.css';
import BadImport from "file/bad-import";

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

export default App;

Here, we have added a bad import —

import BadImport from "file/bad-import";

This bad import should be caught by our custom Lint.

Important Note: Remember, our plugin uses AST to traverse the nested file and read imports. You can read more on this here — AST Explorer.

Output :

Credits: Self

Here we go, we are able to find the usage of bad imports in our Project.

Links And References :

https://github.com/git-hariom/custom-eslint-plugin

Thanks,

Hariom Sinha | Developer | Learning And Growing
New Blog drops every Sunday

--

--

hariom sinha

UI Engineer | 5 + Years of Experience | Web and Mobile Developer | Content Writer