读懂ESLint,告别讨厌的方便面xian

前言

eslint能够帮助咱们约束代码规范,保证团队代码风格的一致性,前端项目不可或缺的代码检查工具,重要性不言而喻。那么你真正的看懂配置了吗?plugins是什么插件,extends又是继承了什么东西,有些时候怎么写的和plugin差很少呢,parser又是作什么的,rules要写这么多吗,去哪里找到对应的规则?javascript

当你出现这些疑问的时候,那么就应该看看本文,也许可以帮助你找到答案。html

本文目的

帮助你们快速了解eslint,若是你的时间和精力很充裕,最直接有效的方式仍是看官方文档,强烈推荐。(做者废话多,文章很长,感谢阅读)前端

契机

首先聊聊为何会有这篇文章,要从一个夜黑风高伸手掏出手机的瞬间提及,收到某大佬公众号的文章,红宝书4发了电子版,其author居然再也不是Nicholas C. Zakas,缘由是当年约稿,尼古拉斯认为不是时候,前端变化太快,还要等等,终于等到适合开始写的时候,却病了。同时,恰好团队在推动vue3 + ts的最佳实践,梳理eslint的发现author居然是Nicholas,真的是缘起缘聚呀,当下就有了写文章的冲动,难在一时不可脱身,搁浅。过了两周,我又翻出项目代码,发现撸了一遍源码的配置,居然忘了!一点没剩,这能忍?因此,此文诞生。vue

Lint历史

为何命名为eslint?理解为java

(ECMAScript, Lint) => eslint
复制代码

Lint

Lint是C语言著名的静态程序分析工具,使用在UNIX系统中,历史推移,陆续演变出Linux系统的splint及Windows系统中的PC-Lint.node

JSLint

前端最先出现的Lint工具是Douglas Crockford于2002年建立的JSLint,若是你认同jslint默认配置规则的话,那么开箱即用。同时这也是它的缺点,不可配置致使没办法自由扩展,不能定制规则,出错的时候也很难找到出错点。jquery

JSHint

JSHint是JSLint的fork版本,支持配置,使用者能够任意配置规则,也有相对完整的文档支持。初始自带少许配置,须要开发者本身添加不少规则,同时它很难找到哪条规则引发的错误,不支持自定义扩展。webpack

Closure Linter

出自Google,比较久远,已经废弃。缘由是Javascript语法更新太快,其不支持后续的ES2015等后续内容的更新,没人维护。git

JSCS

没有默认规则,支持定制化,支持预设,也可以很好的找到哪里出错,能够很好的被继承。只是它只检测code style问题,不能发现潜在的bug,好比未使用的变量,或者不当心定义的全局变量。github

                                               

ESlint

灵活,可扩展,容易理解,让开发者自定义规则,提供完整的插件机制,动态加载规则,超详细的文档支持。(终于等到你,啰哩啰嗦讲了这么久,还不到重点!同志,你要有耐心)

小结

读到这里,至少要意识到:

  • 文档的重要性,良好的文档是保证代码可以使用的前提。
  • 可维护性,code须要有人持续维护,才能发挥价值。
  • 跟随时代变化,落后只能被淘汰。

正文

全文仿照官方文档结构介绍,重点讲述其背后的逻辑关系,让你少走弯路,看懂配置。

eslint

简单理解,就是各类rule组成的集合。 利用不一样配置字段进行rule组装,而后经过rules配置进行微调处理。

configuration

先从简单的规则入手,了解rules是什么,看个例子:

{
    "rules": {
        "semi": ["error", "always"],
        "quotes": ["error", "double"]
    }
}
复制代码

这两条规则分别表示的:句子末尾分号必须存在,使用双引号。

value值数组中,第一个值表示错误级别,有三个可选值:

  • "off" or 0 - turn the rule off
  • "warn" or 1 - turn the rule on as a warning (doesn't affect exit code)
  • "error" or 2 - turn the rule on as an error (exit code will be 1)

咱们能够配置任意多个这样的规则,固然随着规则的增多,写起来就比较麻烦,因此eslint提供了一些预设,像这样:

{
    "extends": "eslint:recommended"
}
复制代码

extends

简单的解释,就是从基础配置中,继承可用的规则集合。

有两种使用方式:

1. 字符串

  • 配置文件path,如"./config/custom-vue-eslint.js"
  • 共享配置的名称,如"eslint:recommended"

2. 字符串数组

extends: [
    'eslint:recommended',
    'plugin:vue/vue3-strongly-recommended',
    '@vue/typescript/recommended'
]
复制代码

eslint递归的继承配置,因此base config能够有`extends`属性,`rules`的内容能够继承或者重写规则集的任意内容,有几种方式:

1. 新添加规则

2. 修改规则的提醒级别,好比从`error`->`warn` // 这么神奇的配置代码怎么写的?

例如:

base config: ["error", "always", {"null": "ignore"}]

a === b
foo === true
item.value !== 'DOWN'
foo == null
复制代码

derived config:  "eqeqeq": "warn"

result config: "eqeqeq": ["warn", "always", {"null": "ignore"}]

3. 重写options参数。

例如:

base config: "quotes": ["error", "single", {"avoidEscape": true}]

e.g.: const double = "a string containing 'single' quotes"

derived config: "quotes": ["error", "single"]

result config: "quotes": ["error", "single"]

extends默认配置

那么

"extends": "eslint:recommended"
复制代码

这句简单的配置,到底怎么找到的对应rules的呢?

------------------------------------------题外话-------------------------------------------

以经常使用的IDE工具vscode为例说明,有三种方式使用eslint:

  1. vscode extension 插件: ESLint
  2. npm node_modules包:eslint command
  3. vue-cli集成插件:cli-plugin-eslint

本质上,三种方式是同一种,经过不一样的方式,调用当前项目下node_modules下的eslint包。

1. vscode extension

  • Mac插件文件位置:~/.vscode/extensions/dbaeumer.vscode-eslint-x.x.x
  • vscode 启动,执行./client/out/extension.js
  • 检测项目目录是否存在'.eslintrc.js', '.eslintrc.yaml', '.eslintrc.yml', '.eslintrc', '.eslintrc.json'
  • 不存在的话,utils.findEslint() 而后Terminal执行eslint --init
  • 存在,activate() -> realActivate() -> migration.record(),经过激活eslint.xxxx命令,执行eslint包,检测并作出反馈提示,就是咱们常常见到的红色波浪线。

2. eslint命令行

  • eslint --no-fix 或者 eslint -c path/.eslintrc
  • 全局安装直接eslint命令,当前项目安装使用npx eslint
  • 入口在./node_modules/eslint/bin/eslint.js

3. cli-plugin-eslint

  • vue-cli启动,加载`cli-plugin-eslint`插件和`eslint-loader`,注册lint命令
  • 经过npm run lint执行eslint/lib/lint.js文件

最终都须要eslint/lib/cli-engine/cli-engine.js文件,启动eslint引擎,lint or init。

而eslint config的内容解析在cli-engine.js引用的@eslint/eslintrc包中。

--------------------------------------------------------------------------------------------

经过查阅node_modules/@eslint/eslintrc包,找到以下关键代码:

@eslint/eslintrc -> lib/index.js -> lib/cascading-config-array-factory.js -> lib/config-array-factory.js

看代码帮助理解,可跳过阅读。

`@eslint/eslintrc/lib/config-array-factory.js`

/**
 * Load configs of an element in `extends`.
 * @param {string} extendName The name of a base config.
 * @param {ConfigArrayFactoryLoadingContext} ctx The loading context.
 * @returns {IterableIterator<ConfigArrayElement>} The normalized config.
 * @private
 */
_loadExtends(extendName, ctx) {
    debug("Loading {extends:%j} relative to %s", extendName, ctx.filePath);
    try {
        if (extendName.startsWith("eslint:")) {
            return this._loadExtendedBuiltInConfig(extendName, ctx);
        }
        if (extendName.startsWith("plugin:")) {
            return this._loadExtendedPluginConfig(extendName, ctx);
        }
        return this._loadExtendedShareableConfig(extendName, ctx);
    } catch (error) {
        error.message += `\nReferenced from: ${ctx.filePath || ctx.name}`;
        throw error;
    }
}
复制代码

在`eslint/lib/cli-engine/cli-engine.js`,关注eslintRecommendedPath/eslintAllPath变量

const configArrayFactory = new CascadingConfigArrayFactory({
    additionalPluginPool,
    baseConfig: options.baseConfig || null,
    cliConfig: createConfigDataFromOptions(options),
    cwd: options.cwd,
    ignorePath: options.ignorePath,
    resolvePluginsRelativeTo: options.resolvePluginsRelativeTo,
    rulePaths: options.rulePaths,
    specificConfigPath: options.configFile,
    useEslintrc: options.useEslintrc,
    builtInRules,
    loadRules,
    eslintRecommendedPath: path.resolve(__dirname, "../../conf/eslint-recommended.js"),
    eslintAllPath: path.resolve(__dirname, "../../conf/eslint-all.js")
});
复制代码

`_loadConfigData`函数的做用是加载指定的配置文件。

因此,配置"extends": "eslint:recommended"指的使用就是eslint-recommended.js文件里面的内容。同理,还可使用"extends": "eslint:all"

从`_loadExtends`的代码逻辑里,能够追踪出三种配置方式:

  • 默认配置,如上述解释。
  • 插件配置
  • 共享配置

extends插件配置

插件是npm包导出的rules配置对象,有些插件能够导出一个或者多个配置对象,例如:

eslint-plugin-babel
eslint-plugin-vue
eslint-plugin-jest
eslint-plugin-eslint-plugin
复制代码

插件配置能够忽略前缀`eslint-plugin-`,以下写法:

{
    "extends": [
        "plugin:jest/all",
        "plugin:vue/recommended"
    ]
}
复制代码

格式这样写:`plugin:${packageName}/${configurationName}`

逻辑代码在config-array-factory.js -> _loadExtendedPluginConfig()

extends共享配置

共享配置就是npm包导出的一个配置对象,例如:

eslint-config-standard
eslint-config-airbnb
eslint-config-prettier
@vue/eslint-config-typescript
复制代码

extends配置能够忽略前缀`eslint-config-`,仅仅使用包名,因此在`.eslintrc.js`文件中,咱们使用以下两种写法都是正确的。

{
    "extends": "eslint-config-standard"
}

{
    "extends": [
        "standard",
        "prettier",
        "@vue/typescript"
    ]
}
复制代码

逻辑代码在config-array-factory.js -> _loadExtendedShareableConfig()

命名解析在@eslint/eslintrc/lib/shared/naming.js

plugins

在eslint的配置文件中,支持直接引入第三方插件,例如:

@typescript-eslint/eslint-plugin
eslint-plugin-vue
eslint-plugin-prettier
@jquery/eslint-plugin-jquery
复制代码

一样,`eslint-plugin-`前缀能够忽略。

{
    "plugins": [
        "@typescript-eslint",
        "vue",
        "prettier",
        "@jquery/jquery"
    ]
}
复制代码

名称转化规则

  • eslint-plugin-foo -> foo/a-rule
  • @foo/eslint-plugin -> @foo/a-config
  • @foo/eslint-plugin-bar -> @foo/bar/a-environment

看个官方例子

{
    // ...
    "plugins": [
        "jquery",   // eslint-plugin-jquery
        "@foo/foo", // @foo/eslint-plugin-foo
        "@bar"      // @bar/eslint-plugin
    ],
    "extends": [
        "plugin:@foo/foo/recommended",
        "plugin:@bar/recommended"
    ],
    "rules": {
        "jquery/a-rule": "error",
        "@foo/foo/some-rule": "error",
        "@bar/another-rule": "error"
    },
    "env": {
        "jquery/jquery": true,
        "@foo/foo/env-foo": true,
        "@bar/env-bar": true,
    }
    // ...
}
复制代码

有个疑问,这里的plugin和extends中提到的plugin有什么关联关系?

  • plugin配置,是把第三方规则引入到eslint的配置文件中,咱们能够在rules配置更改plugin插件提供的rules。
  • extends配置,是使用node_modules包提供的preset rules。一样,也能够在rules配置中修改rule内容。
  • 两个配置的根本做用不一样。extends可使用plugin配置提供的preset,详见上面的`extends插件配置`部分。`preset rules`能够帮助减小rules规则的书写,在项目中,咱们一般直接使用社区的最佳实践recommended,而后基于此rules,进行微调。

因此结论是:使用preset,就是extends的用法,不使用preset就引用插件就行,而后自行配置rules

parser

默认状况下,eslint使用`Espress`解析,咱们能够选择不一样的解析器。好比咱们使用`eslint-plugin-vue`插件,就须要配置自定义parser。

{
    "parser": "vue-eslint-parser"
}
复制代码

解析器`vue-eslint-parser`能够解析`.vue`文件。

parser options

该选项与parser配合使用,当使用自定义parser时,options的内容并非每一项都会被自定义parser须要。options容许eslint自定义ECMAScript支持的语法。

{
    "parserOptions": {
        "ecmaVersion": 12,
        "sourceType": "module", 
        "ecmaFeatures": {
            "jsx": true
        }
    }
}
复制代码
  • ecmaVersion: 3, 5(default), 6, 7, 8, 9, 10, 11, 12 or 2015, 2016, ..., 2021

  • sourceType:"script" or "module",表示在什么模式下解析代码。

    if (sourceType === "module" && ecmaVersion < 6) {
        throw new Error("sourceType 'module' is not supported when ecmaVersion < 2015. Consider adding `{ ecmaVersion: 2015 }` to the parser options.");
    }
    复制代码
  • ecmaFeatures:指定其余语言功能

processor

有的插件自带处理器,处理器能够从另外一种文件中提取js代码,而后让elint对js代码进行lint处理。或者在预处理中转换js代码。

overrides

overrides配置能够更精细的控制某些规则,能够只针对某个特殊场景生效,这样设定很灵活。

其余配置

未介绍environments/globals等概念,看官方文档,与parser相关的AST(Abstract Syntax Tree)会单独文章讲解。

项目实践

目前项目(vue3 + typescript)上是这样使用的,配置文件.eslintrc.js

module.exports = {
    root: true,
    env: {
        node: true,
        browser: true
    },
    plugins: [
        'vue',
        '@typescript-eslint' // 可省略,why?
    ],
    extends: [
        'eslint:recommended',
        'plugin:vue/vue3-strongly-recommended',
        '@vue/typescript/recommended'
    ],
    parser: 'vue-eslint-parser',
    parserOptions: {
        parser: '@typescript-eslint/parser',
        ecmaVersion: 2020,
        sourceType: 'module'
    },
    rules: {
        'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
        'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
        'semi': ['error', 'always'],
        'indent': ['error', 4, {
            'SwitchCase': 1
        }],
        'no-empty-function': 'off',
        'no-useless-escape': 'off',
        // allow paren-less arrow functions
        'arrow-parens': ['error', 'as-needed'],
        // enforce consistent linebreak style for operators
        'operator-linebreak': ['error', 'before'],
        'space-before-function-paren': ['error', {
            'anonymous': 'always',
            'named': 'never',
            'asyncArrow': 'always'
        }],
        'no-template-curly-in-string': 'error',
        // require space before blocks
        'space-before-blocks': ['error', 'always'],
        // enforce consistent spacing before and after keywords
        'keyword-spacing': 'error',
        // enforce consistent spacing between keys and values in object literal properties
        'key-spacing': 'error',
        // require or disallow spacing between function identifiers and their invocations
        'func-call-spacing': ['error', 'never'],
        // enforce consistent spacing before and after commas
        'comma-spacing': ['error', {
            'before': false,
            'after': true
        }],
        // disallow or enforce spaces inside of parentheses
        'space-in-parens': ['error', 'never'],
        // enforce consistent spacing inside braces
        'object-curly-spacing': ['error', 'never'],
        'vue/html-indent': ['error', 4],
        'vue/max-attributes-per-line': ['error', {
            'singleline': 10,
            'multiline': {
                'max': 1,
                'allowFirstLine': false
            }
        }],
        '@typescript-eslint/semi': ['error', 'always'],
        '@typescript-eslint/indent': ['error', 4],
        '@typescript-eslint/no-empty-function': 'off',
        '@typescript-eslint/no-namespace': 'off',
        '@typescript-eslint/no-this-alias': 'off',
        '@typescript-eslint/no-explicit-any': 'off',
        '@typescript-eslint/explicit-module-boundary-types': 'off'
    },
    overrides: [
        {
            files: ['*.ts', '*.tsx'],
            parserOptions: {
                parser: '@typescript-eslint/parser',
                project: './tsconfig.json'
            },
            rules: {
                '@typescript-eslint/restrict-plus-operands': 'error'
            }
        },
        {
            files: ['*.js', '*.ts'],
            rules: {
                '@typescript-eslint/explicit-module-boundary-types': 'warn'
            }
        }
    ]
};
复制代码

运用咱们前面的知识,该配置引入两个插件,eslint-plugin-vue@typescript-eslint/eslint-plugin,使用三种预设规则,配置两种语法解析器,以及自定义支持的一系列规则,并重写ts的两个特殊规则。

示例讲解

重点看下extends下配置的三个preset:

  1. eslint:recommended
  • 在`extends`已经重点讲过。
  • 全部eslint的rules经过官方文档可查阅。
  • check mark表示默认启用的规则。

2. plugin:vue/vue3-strongly-recommended

  • 来自插件eslint-plugin-vue提供的preset。
  • 全部vue的rules经过官方文档可查阅。
  • 插件提供多种preset。

3. @vue/typescript/recommended

  • 来自共享配置@vue/eslint-config-typescript提供的preset。
  • 全部typescript-eslint的rules经过官方文档可查阅。

经过源码能够看到,全部默认提供的preset。

再来说下, '@typescript-eslint' // 可省略,why? 这句话是什么意思。

@vue/eslint-config-typescript/recommended.js(from version: 7.0.0)

module.exports = {
  extends: [
    './index.js',
    'plugin:@typescript-eslint/recommended'
  ],
  // the ts-eslint recommended ruleset sets the parser so we need to set it back
  parser: require.resolve('vue-eslint-parser'),
  rules: {
    // this rule, if on, would require explicit return type on the `render` function
    '@typescript-eslint/explicit-function-return-type': 'off'
  },
  overrides: [
    {
      files: ['shims-tsx.d.ts'],
      rules: {
        '@typescript-eslint/no-empty-interface': 'off',
        '@typescript-eslint/no-explicit-any': 'off',
        '@typescript-eslint/no-unused-vars': 'off'
      }
    }
  ]
};
复制代码

extends使用文件path,引用当前路径下的index.js文件

@vue/eslint-config-typescript/index.js

module.exports = {
  plugins: ['@typescript-eslint'],  // Prerequisite `eslint-plugin-vue`, being extended, sets
  // root property `parser` to `'vue-eslint-parser'`, which, for code parsing,
  // in turn delegates to the parser, specified in `parserOptions.parser`:
  // https://github.com/vuejs/eslint-plugin-vue#what-is-the-use-the-latest-vue-eslint-parser-error
  parserOptions: {
    parser: require.resolve('@typescript-eslint/parser'),
    extraFileExtensions: ['.vue'],
    ecmaFeatures: {
      jsx: true
    }
  },
  extends: [
    'plugin:@typescript-eslint/eslint-recommended'
  ],
  overrides: [{
    files: ['*.ts', '*.tsx'],
    rules: {
      // The core 'no-unused-vars' rules (in the eslint:recommeded ruleset)
      // does not work with type definitions
      'no-unused-vars': 'off'
    }
  }]
};
复制代码

把两个文件合在一块儿,看看长什么样。(eslint的extends是使用的递归方式检测配置,但最终和文件整合在一块儿原理同样,须要排列好关系优先级)

module.exports = {
    extends: [
        'plugin:@typescript-eslint/eslint-recommended',
        'plugin:@typescript-eslint/recommended'
    ],
    plugins: ['@typescript-eslint'],
    parser: require.resolve('vue-eslint-parser'),
    parserOptions: {
        parser: require.resolve('@typescript-eslint/parser'),
        extraFileExtensions: ['.vue'],
        ecmaFeatures: {
            jsx: true
        }
    },
    rules: {
        '@typescript-eslint/explicit-function-return-type': 'off'
    },
    overrides: [
        {
            files: ['shims-tsx.d.ts'],
            rules: {
                '@typescript-eslint/no-empty-interface': 'off',
                '@typescript-eslint/no-explicit-any': 'off',
                '@typescript-eslint/no-unused-vars': 'off'
            }
        },
        {
            files: ['*.ts', '*.tsx'],
            rules: {
                'no-unused-vars': 'off'
            }
        }
    ]
};
复制代码

整合后有两个共享配置,咱们再去看看@typescript-eslint/eslint-plugin源码,发现@typescript-eslint/eslint-plugin/dist/configs/recommended.js也已经经继承eslint-recommended.js内容。

因此就解释了.eslintrc.js中的注释内容。

{
    plugins: ["@typescript-eslint"] // 可忽略
}
复制代码

能够忽略上面的配置,@vue/typescript/recommended已经包含。

--------------------------------------------------------------------------------------------

简化模型,粗略讲下extends的继承,主要是ConfigArray。

假如,简化后的.eslintrc.js文件以下:

module.exports = {
    root: true,
    env: {
        node: true,
        browser: true
    },
    extends: [
        '@vue/typescript/recommended'
    ],
    parser: 'vue-eslint-parser',
    parserOptions: {
        parser: '@typescript-eslint/parser',
        ecmaVersion: 2020,
        sourceType: 'module'
    }
};
复制代码

@vue/eslint-config-typescript/recommended.js简化后以下:

module.exports = {
  extends: [
    'plugin:@typescript-eslint/recommended'
  ],
  parser: require.resolve('vue-eslint-parser'),
  rules: {
    '@typescript-eslint/explicit-function-return-type': 'off'
  }
};
复制代码

@typescript-eslint/eslint-plugin/recommended简化后以下:

module.exports = {
    rules: {
        '@typescript-eslint/adjacent-overload-signatures': 'error',
        '@typescript-eslint/ban-ts-comment': 'error'
    }
};
复制代码

那么最终生成待处理的ConfigArray(5)

[
    {
        type: 'config',
        name: 'DefaultIgnorePattern',
        // ...
    },
    {
        type: 'config',
        name: '.eslintrc.js » @vue/eslint-config-typescript/recommended » plugin:@typescript-eslint/recommended',
        rules: {
            '@typescript-eslint/adjacent-overload-signatures': 'error',
            '@typescript-eslint/ban-ts-comment': 'error'
        },
        // ...
    },
    {
        type: 'config',
        name: '.eslintrc.js » @vue/eslint-config-typescript/recommended',
        importerName: '.eslintrc.js » @vue/eslint-config-typescript/recommended',
        rules: { '@typescript-eslint/explicit-function-return-type': 'off' },
        // ...
    },
    {
        type: 'config',
        name: '.eslintrc.js',
        filePath: 'xxxx/project/.eslintrc.js',
        env: { node: true, browser: true },
        globals: undefined,
        ignorePattern: undefined,
        noInlineConfig: undefined,
        parser: {
            error: null,
            filePath: '/xxxx/project/node_modules/vue-eslint-parser/index.js',
            id: 'vue-eslint-parser',
            importerName: '.eslintrc.js',
            importerPath: '/xxxx/project/.eslintrc.js'
        },
        parserOptions: {
            parser: '@typescript-eslint/parser',
            ecmaVersion: 2020,
            sourceType: 'module'
        },
        plugins: {},
        processor: undefined,
        reportUnusedDisableDirectives: undefined,
        root: true,
        rules: undefined,
        settings: undefined
    },
    {
        type: 'ignore',
        name: '.eslintignore',
        // ...
    }
]
复制代码

从ConfigArray的5个子项中,很清晰的看到递归的解析过程。

--------------------------------------------------------------------------------------------

总结

Eslint用了好几年,最近花不少时间进行梳理,尝试所有讲清楚彷佛也不太容易,源码看了不少。那么当咱们看源码的时候,咱们应该学什么?

  • 明确,它要解决的问题是什么。
  • 学习函数命名,组织代码结构,逻辑关系。
  • 或多或少可以发现精彩的code写法,拿出小本本抄下来。
  • 可以帮助咱们更好的理解官方文档。

写在最后

文章较长,可能也比较乱,各位菜鸟大佬们,不要手上嘴上留情,哪里没理解,读起来不通顺,明显逻辑不正确,欢迎斧正,积极交流,互相学习。

QA

团队内初次分享后,发现一些明显的问题,在这里以QA的形式,补充说明下。

1.写文章思路是帮助你们看懂配置,理解配置项表明的含义。而这些须要读者具有一些初级的eslint知识,至少了解什么是rule,本身接触过配置,修改过,有一点点的学习门槛。

2.上述被我忽略的前提说明,发现一个新的文章思路,教程类的文章《教别人配置eslint》,内容能够从基础eslint提及,介绍完默认配置等属性后。引入若是要使用vue,那么如何约束vue代码呢,进一步,若是使用typescript,又改如何引入ts的校验语法规则呢。这个三步走战略能够是一篇很好的教程文章。

3.为何使用项目vue-cli集成的命令,npm run lint 检查结果和项目启动检测结果不一样,两处应该是一致的才对,是哪里出现问题?

这个问题,能够肯定的结论:

  • npm run lint 和 npm run serve 使用的都是是project下面的.eslintrc.js文件
  •  可是npm run serve忽略了*.d.ts文件,因此没有error,至于进一步的问题,仍在跟进,from issue多是bug
  • npm run serve 只有首次运行后,有warning和error提示,是由于存在本地缓存,在node_modules/.cache目录,删除.cache目录后,就能够每次都看到错误提示信息,已经经过更改eslint-loader为eslint-webpack-plugin插件解决。

4.在eslint的配置文件中,extends属性,支持多种配置方法,那么plugin和share config 有什么区别?

必定是我太认真了,居然晕晕的。这么简单的区别,其实从名字上就能够明白,一个是共享,一个是插件。共享就是不会新加内容,只对原有内容的梳理,把最终配置好的文件,共享给其余人使用。插件,顾名思义,是会引入新东西的,会有新的rule引入,导出的配置文件,包含了新引入的rule规则。而share config没有新的rule。

参考资料

1. About Nicholas C.Zakas 

2. 主流lint工具比较,参考一参考二

3. Closure Linter 

4. Eslint官网

5. eslint-plugin-vue官网

6.typescript-eslint文档 

7. ESLint工做原理 

8.extends与plugins区别,进一步说明

相关文章
相关标签/搜索