What is ESLint

ESLint is a checking tool for ECMAScript/JavaScript with the goal of making code more consistent and avoiding errors, with the following features:

  • Use Espress as the parser;
  • Perform operations in code based on the AST
  • Fully pluggable (each rule is a plug-in)

To sum up: ESLint is an AST based checker that implements ECMAScript/JavaScript, mainly for code quality, and has a large number of configurable items.

Prettier, ESLint’s golden partner Prettier

Prettier is the solution to code quality, but the style of code needs to be uniform in team development.

Prettier said code style is important, but don’t customize it, use me, and forget about the rest.

What are the code styles:

  • max-len
  • no-mixed-spaces-and-tabs
  • .

Prettier and ESLint because Prettier and ESLint overlap, there must be conflicts. To make ESLint and ESLint work harmonically, the plugin esLint-config-Prettier solves little conflicts between Prettier and ESLint.

npm install --save-dev eslint-config-prettier
Copy the code
{"extends": ["some-other-config-you-use", "prettier" // Prettier must be the last prettier in order to effectively cover conflicting configuration items]}Copy the code

Prettier if you want ESLint to handle all errors, use the plugin eslint-plugin-prettier, where Prettier is used as an ESLint plug-in.

How do I configure ESLint

Two configuration modes are available:

  1. Configure through comments in the file
  2. Through a specific configuration file
  • . Eslintrc. * (js | json | YAML) format of the configuration file
  • package.jsonIn theeslintConfig

Typical configuration items in a configuration file:

  • Environments Specifies the environment in which js runs to automatically inject global variables, such as NodeJS ES5 ES6
  • Globals specifies custom global variables
  • Rules Indicates all rule configuration items
  • Plugins plug-in configuration project

The.eslintrc.js file used in wechat applet DEMO:

module.exports = {
  env: {
    browser: true,
    es6: true,
    node: true,
  },
  extends: ['eslint:recommended'],
  parserOptions: {
    sourceType: 'module',
    ecmaVersion: 12
  },
  rules: {
    indent: ['error', 'tab', { SwitchCase: 1 }],
    'linebreak-style': ['error', 'unix'],
    quotes: ['error', 'single'],
    semi: ['error', 'always'],
    'object-shorthand': ['error', 'always'],
    'one-var': [
      2,
      {
        var: 'never',
        let: 'never',
        const: 'never',
      },
    ],
    'no-invalid-regexp': 'error'
  },
  globals: {
    getApp: false,
    wx: false,
    Page: false,
    getCurrentPages: false,
    Component: false,
    App: false,
    Behavior: false,
    requirePlugin: false,
  },
};
Copy the code

Because ESLint has so many configurable items, it is a best practice to inherit common validation rules such as “extends”: [” ESLint :recommended”] and then make team customization.

Things to know about this place:

.eslintrc.* searches for configuration files step by step from the checked file path until the root directory or configuration contains root: true. During the search, all.eslintrc.* file configurations are merged and conflicting configurations are overwritten based on the nearby preference principle.

If the eslintConfig item is specified in the package.json file of the project, this configuration is applied to all subdirectories of the project, overwriting the conflicting configurations based on the nearest preference principle.

How to write in ESLint

To simplify development, the scaffolding Generator-esLint has been customized based on Yo, so you can easily set up your development environment with just a few lines of command.

# Global Install Yo
npm install -g yo

# Install esLint official scaffolding
npm install -g generator-eslint
Copy the code

Create the plug-in

Create a project folder for example
mkdir eslint-wd

# enter directory
cd eslint-wd

Create the base file via scaffolding, including rules as guided

yo eslint:plugin

A directory with the following structure will be generated
#.
# ├ ─ ─ the README, md
# ├ ─ ─ lib
# │ ├ ─ ─ index. Js
# │   ├── processors
# │   └── rules
# ├ ─ ─ package - lock. Json
# ├ ─ ─ package. Json
# └ ─ ─ tests
# └ ─ ─ lib
# ├ ─ ─ processors
# └ ─ ─ rules
Copy the code

Create a rule

We'll still use scaffolding and execute in the eslint-wd directory
# let's create an example of a file where require is not allowed to introduce module variables

yo eslint:rule

Complete the configuration according to boot
#? What is your name? amin
#? Where will this rule be published? ESLint Plugin
#? What is the rule ID? no-require
#? Type a short description of this rule: Disallow the use of require in projects
#? Type a short example of the code that will fail: const fs = require('fs');
# create docs/rules/no-require.md
# create lib/rules/no-require.js
# create tests/lib/rules/no-require.js
Copy the code

After following the scaffolding bootstrap, three files are generated:

  • Docs /rules/no-require.md Document description
  • Lib /rules/no-require.js core logic
  • Tests /lib/rules/no-require.js unit tests

In the lib/rules/no-require.js file, there are two core parts:

  • metametadata
    • Type Specifies the type of the rule

      • "problem"Errors or abnormal behavior may result
      • "suggestion"Some optimization suggestions do not cause errors if they are not modified
      • "layout"Code style.
    • Doc has some literal descriptions of rules and document addresses

      • description(string)
      • category(string)
      • recommended(boolean) "extends": "eslint:recommended"Whether to enable the rule
      • url(string)
    • fixable

      • "code"
      • "whitespace"
    • Schema Configuration Description

  • create(context) {}The function returns an object in which various definitions are defined inASTDeep traversal in the callback function, simple traversal can be directly in the syntax tree node type as a function name, more usage can be viewedThe document.

Here’s how to create a plugin that disables require() :

First, check out the AST at the Syntax Tree online preview site

const fs = require('fs');
const { exec } = require('child_process');
Copy the code

After pasting in the code, you can see the structure of the AST on the right:

As can be seen, to identify require, we only need to focus on the node of the CallExpression type, whose callee attribute is an Identifier and whose name=”require”, then the code is easy to implement:

/ * * *@fileoverview Disallow the use of require * in projects@author amin`
 */
"use strict";

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

/ * * *@type {import('eslint').Rule.RuleModule}* /
module.exports = {
  meta: {
    type: "suggestion".// `problem`, `suggestion`, or `layout`
    docs: {
      description: "Prohibit the use of require in projects.".category: "Fill me in".recommended: false.url: null.// URL to the documentation page for this rule
    },
    fixable: null.// Or `code` or `whitespace`
    schema: [].// Add a schema if the rule has options
    messages: {
      avoidRequire: 'avoid use {{name}}',}},create(context) {
    // variables should be defined here

    //----------------------------------------------------------------------
    // Helpers
    //----------------------------------------------------------------------

    // any helper functions should go here or else delete this section

    //----------------------------------------------------------------------
    // Public
    //----------------------------------------------------------------------

    return {
      // visitor functions for different types of nodes
      CallExpression(node) {
        const callee = node.callee;
        if (callee && callee.type === 'Identifier' && callee.name === 'require') {
          context.report({
            node,
            messageId: 'avoidRequire'.// Corresponds to the Messages section defined in meta
            data: {
              name: callee.name, }, }); }}}; }};Copy the code

Perfecting Jest tests:

/ * * *@fileoverview Disallow the use of require * in projects@author fumin* /
"use strict";

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

const rule = require(".. /.. /.. /lib/rules/no-require"),
  RuleTester = require("eslint").RuleTester;


//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2015.sourceType: 'module'}}); ruleTester.run("no-require", rule, {
  valid: [
    'import fs from "fs"'.'import { exec } from "child_process"'].invalid: [{code: "const fs = require('fs');".// output: 'avoid use require',
      errors: [{ messageId: 'avoidRequire'}],},]});Copy the code

After writing the test case, we can execute the NPM run test to verify whether the function we wrote is correct. After passing the check, we can verify in the actual project.

In the plug-in root directory, run the NPM link command to link the plug-in soft to the global directory

In the project where you want to use it, run NPM link eslint-plugin-wd and the plugin soft chain will be created in the node_modules of the project

Introduce plugins in.eslintrc.* files to configure rules in rules:

{
  plugins: ['eslint-plugin-wd'].rules: {
    'eslint-plugin-wd/no-require': 'error',}}Copy the code

So you have the rule that you just created enabled in your project.