讀懂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區別,進一步說明

相關文章
相關標籤/搜索