This solution will enforce standardization and good code quality for your entire project without any scope for compromise for anyone. It will also serve as the prefect Dev IDE setup where a developer doesn’t have to learn anything new to follow the rule set, the IDE automatically fixes everything for him.
Scope
We will be focussing on the following topics for enforcing standards
- IDE Tooling and Settings
- Code Aesthetics
- Code Quality
- Code Coverage
- PR Template
Setup
IDE
This article will assume you are using VS Code, but similar alternatives can be found for extensions in the IDE of your choice.
Configure VS Code using the following steps:
- Create a folder at the root of your project called
.vscode
-
Create the following two files within it
-
extensions.json
These extensions provide a lot of options and standardized intelligent tools for the developers. The Developer will be prompted to install these on opening the project, if not already done and should be a single click install. These will also be visible under the extensions section of the IDE.
{ "recommendations": [ "aaron-bond.better-comments", "CoenraadS.bracket-pair-colorizer-2", "Orta.vscode-jest", "PKief.material-icon-theme", "dbaeumer.vscode-eslint", "eamodio.gitlens", "eg2.vscode-npm-script", "esbenp.prettier-vscode", "jpoissonnier.vscode-styled-components", "msjsdiag.debugger-for-chrome", "streetsidesoftware.code-spell-checker", "stylelint.vscode-stylelint" ] }
-
settings.json
These are IDE settings which will set specific tools and formatting options in the IDE
{ "[html]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[javascript]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[json]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.tabSize": 2 }, "[typescriptreact]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "[yaml]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, "better-comments.multilineComments": true, "editor.formatOnSave": true, "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"], "javascript.updateImportsOnFileMove.enabled": "always", "jest.autoEnable": false, "jest.runAllTestsFirst": false, "jest.showCoverageOnLoad": true, "typescript.referencesCodeLens.enabled": true, "typescript.tsdk": "node_modules/typescript/lib", "typescript.updateImportsOnFileMove.enabled": "always", "vsicons.projectDetection.autoReload": true, "workbench.iconTheme": "material-icon-theme" }
-
Spell Checker
This extension make sure you use correct spelling in your code for variables and comments.
- Install Code Spell Checker extension in the IDE
- Then create
cSpell.json
in.vscode
folder. This file serves as the configuration for the extension -
Addd the following code in the file
{ "version": "0.1", "words": ["TheNikhilK"] }
Prettier
Prettier is a well known, industry wide used code formatter. We will use this tool two fold in our IDE, as an extension and as a CLI Tool
- Install the VS Code extension from this link
-
Install the tool package as a dev dependency
npm install --save-dev --save-exact prettier ## OR yarn add --dev --exact prettier
-
Create a file at the root of your project
.prettierrc
, add the following configuration settings to it:{ "printWidth": 100, "tabWidth": 2, "semi": true, "singleQuote": true, "trailingComma": "all", "arrowParens": "avoid", "endOfLine": "auto", "jsxBracketSameLine": true, "bracketSpacing": true }
-
Create
.prettierignore
for all the files and path to ignore for formattingdist/ out/ public/ strings/ tests/ node_modules/ package-lock.json
ESLint
- ESLint is an advanced linter which can scan for issues as well as fix them.
- Along with enforcing scripting rules we will also integrate
Prettier
rules here to make sure there are no code formatting issues and they are also flagged as violations - Install this extension
-
Install the following packages for CLI tools
npm install --save-dev eslint eslint-config-prettier eslint-loader eslint-plugin-import eslint-plugin-jest eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint # OR yarn add --dev eslint eslint-config-prettier eslint-loader eslint-plugin-import eslint-plugin-jest eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint
-
Create
.eslintrc.js
at the root of the project and add the following codeconst fs = require('fs'); const path = require('path'); const prettierOptions = JSON.parse(fs.readFileSync(path.resolve(__dirname, '.prettierrc'), 'utf8')); module.exports = { parser: '@typescript-eslint/parser', extends: [ 'eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier', 'plugin:prettier/recommended', 'prettier/@typescript-eslint', 'prettier/react', 'plugin:react/recommended', 'plugin:react-hooks/recommended', 'plugin:jsx-a11y/recommended', 'plugin:jest/recommended', 'plugin:import/errors', 'plugin:import/warnings', 'plugin:import/typescript', ], env: { browser: true, es6: true, jest: true, amd: true, node: true, }, plugins: [ 'prettier', 'jest', 'jsx-a11y', 'import', 'react'], rules: { 'prettier/prettier': ['error', prettierOptions], 'react/no-multi-comp': [2, { ignoreStateless: false }], 'react/display-name': 0, 'react/jsx-pascal-case': 2, 'react/prefer-read-only-props': 2, 'react/sort-prop-types': 2, 'react/jsx-sort-props': 2, 'react/jsx-max-depth': [1, { max: 4 }], 'react/jsx-no-literals': 2, 'react/no-typos': 2, 'react/no-multi-comp': 2, 'react/no-direct-mutation-state': 2, 'react/jsx-no-duplicate-props': 2, 'react/prefer-es6-class': 2, 'react/boolean-prop-naming': 2, 'react/function-component-definition': 2, 'react/sort-comp': [ 2, { order: ['instance-variables', 'static-methods', 'lifecycle', '/^on.+$/', 'everything-else', 'render'], }, ], '@typescript-eslint/interface-name-prefix': 0, '@typescript-eslint/no-parameter-properties': 0, '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], '@typescript-eslint/explicit-function-return-type': 2, '@typescript-eslint/switch-exhaustiveness-check': 2, '@typescript-eslint/prefer-optional-chain': 1, '@typescript-eslint/prefer-nullish-coalescing': 1, '@typescript-eslint/no-unnecessary-qualifier': 1, '@typescript-eslint/no-unsafe-return': 2, '@typescript-eslint/no-unsafe-call': 2, '@typescript-eslint/consistent-type-assertions': 2, '@typescript-eslint/consistent-type-definitions': 2, '@typescript-eslint/no-base-to-string': 2, '@typescript-eslint/prefer-ts-expect-error': 2, '@typescript-eslint/prefer-readonly': 2, '@typescript-eslint/prefer-readonly-parameter-types': 2, '@typescript-eslint/explicit-module-boundary-types': 2, '@typescript-eslint/prefer-nullish-coalescing': 2, '@typescript-eslint/naming-convention': [2, { selector: 'variable', format: ['camelCase', 'PascalCase'] }], '@typescript-eslint/interface-name-prefix': [2, { prefixWithI: 'always' }], 'no-use-before-define': 2, 'no-var': 2, eqeqeq: 2, 'prefer-const': 2, 'prefer-template': 2, 'prefer-spread': 2, 'spaced-comment': 1, 'max-lines': [2, { max: 400, skipComments: true }], 'max-lines-per-function': [2, { max: 75, skipComments: true }], 'max-statements-per-line': 2, 'multiline-comment-style': 2, 'no-shadow': 2, 'no-restricted-globals': [ 2, { name: 'fdescribe', message: 'Do not commit fdescribe. Use describe instead.', }, ], 'import/newline-after-import': [2, { count: 1 }], 'import/no-duplicates': 2, 'import/no-unresolved': 0, 'import/named': 0, 'import/no-named-as-default': 0, 'padding-line-between-statements': [ 2, { blankLine: 'always', prev: '*', next: ['return', 'class', 'try', 'for', 'if', 'switch', 'while'], }, ], 'lines-between-class-members': [2, 'always'], }, parserOptions: { sourceType: 'module', project: './tsconfig.json', ecmaFeatures: { jsx: true, }, }, settings: { react: { pragma: 'React', version: 'detect', }, }, };
-
Create
.eslintignore
at the root level and add files or paths which you don’t want to scan for ESLint.vscode configs dist node_modules out public
More details on how to configure other settings can be found in Part 2 of this guide.