vue项目集成eslint(无需prettier),配合vscode自动检测及手动修复、package.json脚本检测及自动修复

vue项目集成eslint🏆

前言:相信同学们肯定纠结过eslint和prettier要不要配合使用,eslint侧重于代码语法和内部错误的校验,而prettier侧重于代码风格格式化,纠结的原因是一方面不想如此复杂地配置,另一方面还得兼容两个插件,避免起冲突,那么本文阐述了摒弃prettier的方案,使用eslint-plugin-vuevue3项目进行eslint相关配置(vue2项目也可以使用,只不过有些规则上的区别,后面会阐述)。
介绍一下两个工具:

  • eslint:eslint是一个可配置的 JavaScript 检查器。 它可以帮助你发现并修复 JavaScript 代码中的问题。 问题可以是任何东西,从潜在的运行时错误,到不遵循最佳实践,再到风格问题。
  • eslint-plugin-vue:在eslint基础上开发的代码检测插件,这个插件允许我们用eslint检查vue文件中的 < template >和< script >,以及js文件中的vue代码(mixins等)。

本文解决了两个大家最关心的问题:

  • 使项目在coding阶段能够通过vscode编辑器实时检测代码语法、内部错误和风格问题并高亮提示,可随时通过快速修复按钮修复可自动修复的问题(部分语法问题无法自动修复)
  • 使项目能通过package.json文件的scripts模块配置的脚本自动检测、自动修复代码语法、内部错误和风格问题,并能够输出检测报告

如何集成eslint❓

创建项目时集成eslint

如果通过vue cli创建vue项目,可在创建时选择eslint选项:
在这里插入图片描述
项目创建好后可在package.json文件中看到这两个依赖:
在这里插入图片描述
是不是似曾相识?可以看看本文第一段介绍。

已有项目集成eslint

如果使用vite创建项目或者vue cli创建项目时没有选择eslint选项,就可以看这里了。
其实仔细看过vue3官网的同学会有印象
在这里插入图片描述
我们可以在项目中安装eslint和eslint-plugin-vue依赖:

npm install -D eslint eslint-plugin-vue

这里科普一下 -D 和 -S 的区别:

  • -D:将依赖安装到package.json文件下的devDependencies模块,表示开发环境下的依赖,不用于生产环境,不会参与打包,由于eslint只在开发环境下规范代码使用,所以需要加 -D
  • -S:将依赖安装到package.json文件下的dependencies模块,表示生产环境下的依赖,会参与打包,从npm5开始,加不加 -S 都是一样的效果

安装好依赖之后可以在package.json中看到:
在这里插入图片描述

配置eslint🍟

如果创建项目时选择了eslint,那么项目根目录下会有一个.eslintrc.js文件,如果后面集成的eslint,那么就没有这个文件,需要自己在项目根目录添加:
在这里插入图片描述
经历了两天的eslint(378个规则)、eslint-plugin-vue(504个规则)官网的学习,将每个规则了解一遍,得到下面的葵花宝典🌻,史上最全最规范的代码规则,包含了语法、风格、内部错误等方面的检验,无需和prettier死缠烂打,拒绝复杂配置和插件冲突。哈哈哈~~像不像打广告,雀食有些激动,话不多说,打开.eslintrc.js文件,添加以下代码:

// eslint-plugin-vue官网:https://eslint.vuejs.org/rules/
// eslint中文官网:https://eslint.nodejs.cn/docs/latest/rules/
module.exports = {
  root:          true,
  parserOptions: {
    ecmaVersion: 2020, // 支持的最新的ECMAScript语法版本
    sourceType:  'module', // 如果你的代码在 ECMAScript 模块中,则设置为 "script"(默认)或 "module"
  },
  parser:  'vue-eslint-parser',
  // eslint:recommended:eslint推荐的默认规则,eslint中文官网可查看所有推荐的默认规则
  // plugin:vue/vue3-essential、plugin:vue/vue3-recommended、plugin:vue/vue3-strongly-recommended:eslint-plugin-vue推荐的基于vue3的默认规则,eslint-plugin-vue官网可查看所有推荐的默认规则
  extends: [
    'eslint:recommended',
    'plugin:vue/vue3-essential',
    'plugin:vue/vue3-recommended',
    'plugin:vue/vue3-strongly-recommended',
  ],
  // no-undef规则会检测没有声明的变量,但有些情况不是我们理想的,例如elementUI-plus、uniapp的全局变量等,在此声明即可
  globals: {
    ElMessage:      'readonly',
    ElNotification: 'readonly',
  },
  env: {
    browser: true, // 支持浏览器全局变量,如window、document
    node:    true, // 支持nodejs全局变量,如global
    es6:     true, // 支持es6的全局变量,如Set
  },
  // 跳过检测的文件
  ignorePatterns: [
    'auto-imports.d.ts',
    'components.d.ts',
  ],
  // "off" 或 0 - 关闭规则
  // "warn" 或 1 - 打开规则作为警告(不影响退出代码)
  // "error" 或 2 - 打开规则作为错误(触发时退出代码为 1)
  rules: {
    // eslint规则,主要对代码语法进行规范
    'no-console':                  process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-debugger':                 process.env.NODE_ENV === 'production' ? 'warn' : 'off',
    'no-var':                      'error',
    'no-await-in-loop':            'error',
    'no-constructor-return':       'error',
    'no-duplicate-imports':        'error',
    'no-promise-executor-return':  'error',
    'no-self-compare':             'error',
    'no-template-curly-in-string': 'error',
    'no-unreachable-loop':         'error',
    'no-use-before-define':        'error',
    'require-atomic-updates':      'error',
    'accessor-pairs':              'error',
    'arrow-body-style':            [
      'error',
      'as-needed',
      {
        requireReturnForObjectLiteral: false,
      },
    ],
    camelcase: [
      'error',
      {
        properties:          'always',
        ignoreDestructuring: true,
        ignoreImports:       true,
        ignoreGlobals:       true,
        allow:               ['^\\$_'],
      },
    ],
    curly:                'error',
    'default-case':       'error',
    'default-case-last':  'error',
    'default-param-last': 'error',
    eqeqeq:               [
      'error',
      'always',
    ],
    'grouped-accessor-pairs': 'error',
    'max-nested-callbacks':   [
      'error',
      {
        max: 3,
      },
    ],
    'max-params':           'off',
    'no-array-constructor': 'error',
    'no-bitwise':           'error',
    'no-caller':            'error',
    'no-continue':          'error',
    'no-div-regex':         'error',
    'no-empty-function':    'error',
    'no-eq-null':           'error',
    'no-eval':              'error',
    'no-extend-native':     'error',
    'no-extra-bind':        'error',
    'no-extra-label':       'error',
    'no-implicit-coercion': [
      'warn',
      {
        boolean:                   true,
        number:                    true,
        string:                    true,
        disallowTemplateShorthand: false,
        allow:                     ['!!'],
      },
    ],
    'no-implicit-globals':   'error',
    'no-implied-eval':       'error',
    'no-invalid-this':       'error',
    'no-iterator':           'error',
    'no-label-var':          'error',
    'no-labels':             'error',
    'no-lone-blocks':        'error',
    'no-loop-func':          'error',
    'no-multi-assign':       'error',
    'no-multi-str':          'error',
    'no-new':                'error',
    'no-new-func':           'error',
    'no-new-object':         'error',
    'no-new-wrappers':       'error',
    'no-octal-escape':       'error',
    'no-param-reassign':     'error',
    'no-proto':              'error',
    'no-return-assign':      'error',
    'no-return-await':       'error',
    'no-script-url':         'error',
    'no-sequences':          'error',
    'no-shadow':             'error',
    'no-throw-literal':      'error',
    'no-unneeded-ternary':   'error',
    'no-unused-expressions': [
      'error',
      {
        allowShortCircuit:    true,
        allowTernary:         true,
        allowTaggedTemplates: false,
        enforceForJSX:        false,
      },
    ],
    'no-useless-call':         'error',
    'no-useless-computed-key': 'error',
    'no-useless-concat':       'error',
    'no-useless-constructor':  'error',
    'no-useless-rename':       'error',
    'object-shorthand':        [
      'error',
      'always',
    ],
    'one-var': [
      'error',
      'never',
    ],
    'one-var-declaration-per-line': 'error',
    'operator-assignment':          'error',
    'prefer-arrow-callback':        'error',
    'prefer-const':                 'error',
    'require-await':                'error',
    'symbol-description':           'error',
    'vars-on-top':                  'error',
    // eslint stylistic规则,主要对代码风格进行规范
    'no-multiple-empty-lines':      [
      'error',
      {
        max:    1,
        maxBOF: 0,
        maxEOF: 1,
      },
    ],
    'keyword-spacing': [
      'error',
      {
        before: true,
        after:  true,
      },
    ],
    'space-before-blocks': [
      'error',
      {
        functions: 'always',
        keywords:  'always',
        classes:   'always',
      },
    ],
    'space-before-function-paren': [
      'error',
      {
        anonymous:  'never',
        named:      'never',
        asyncArrow: 'always',
      },
    ],
    'space-in-parens': [
      'error',
      'never',
    ],
    'space-infix-ops': [
      'error',
      {
        int32Hint: false,
      },
    ],
    'switch-colon-spacing': [
      'error',
      {
        after:  true,
        before: false,
      },
    ],
    'space-unary-ops':        'error',
    'template-curly-spacing': [
      'error',
      'never',
    ],
    'key-spacing': [
      'error',
      {
        beforeColon: false,
        afterColon:  true,
        mode:        'strict',
        align:       'value',
      },
    ],
    'comma-dangle': [
      'error',
      'always-multiline',
    ],
    semi: [
      'error',
      'always',
    ],
    'semi-spacing': [
      'error',
      {
        before: false,
        after:  true,
      },
    ],
    'semi-style': [
      'error',
      'last',
    ],
    'no-extra-semi': 'error',
    quotes:          [
      'error',
      'single',
      {
        allowTemplateLiterals: true,
      },
    ],
    'array-bracket-newline': [
      'error',
      {
        multiline: true,
        minItems:  2,
      },
    ],
    'array-bracket-spacing': [
      'error',
      'never',
    ],
    'array-element-newline': [
      'error',
      {
        multiline: true,
        minItems:  2,
      },
    ],
    'arrow-parens': [
      'error',
      'always',
    ],
    'arrow-spacing': [
      'error',
      {
        before: true,
        after:  true,
      },
    ],
    'block-spacing': [
      'error',
      'always',
    ],
    'brace-style': [
      'error',
      '1tbs',
      {
        allowSingleLine: false,
      },
    ],
    'comma-spacing': [
      'error',
      {
        before: false,
        after:  true,
      },
    ],
    'comma-style': [
      'error',
      'last',
    ],
    'computed-property-spacing': [
      'error',
      'never',
    ],
    'dot-location': [
      'error',
      'property',
    ],
    'eol-last': [
      'error',
      'always',
    ],
    'func-call-spacing': [
      'error',
      'never',
    ],
    'function-call-argument-newline': [
      'error',
      'consistent',
    ],
    'function-paren-newline': [
      'error',
      'multiline',
    ],
    'generator-star-spacing': [
      'error',
      {
        before:    false,
        after:     true,
        anonymous: 'neither',
        method:    {
          before: true,
          after:  true,
        },
      },
    ],
    'implicit-arrow-linebreak': [
      'error',
      'beside',
    ],
    indent: [
      'error',
      2,
    ],
    'linebreak-style': [
      'error',
      'unix',
    ],
    'lines-around-comment': [
      'error',
      {
        beforeBlockComment: true,
        afterBlockComment:  false,
        beforeLineComment:  false,
        afterLineComment:   false,
        allowBlockStart:    true,
        allowBlockEnd:      false,
        allowObjectStart:   true,
        allowObjectEnd:     false,
        allowArrayStart:    true,
        allowArrayEnd:      false,
        allowClassStart:    true,
        allowClassEnd:      false,
      },
    ],
    'multiline-ternary': [
      'error',
      'never',
    ],
    'new-parens': [
      'error',
      'always',
    ],
    'newline-per-chained-call': [
      'error',
      { ignoreChainWithDepth: 2 },
    ],
    'no-extra-parens': [
      'warn',
      'all',
      {
        conditionalAssign:                  false,
        returnAssign:                       false,
        nestedBinaryExpressions:            false,
        ignoreJSX:                          'multi-line',
        enforceForArrowConditionals:        false,
        enforceForSequenceExpressions:      false,
        enforceForNewInMemberExpressions:   false,
        enforceForFunctionPrototypeMethods: false,
      },
    ],
    'no-mixed-spaces-and-tabs': 'error',
    'no-multi-spaces':          'error',
    'no-trailing-spaces':       [
      'error',
      {
        skipBlankLines: false,
        ignoreComments: false,
      },
    ],
    'no-whitespace-before-property': 'error',
    'object-curly-newline':          [
      'error',
      {
        multiline:     true,
        minProperties: 2,
        consistent:    true,
      },
    ],
    'object-curly-spacing': [
      'error',
      'always',
      {
        arraysInObjects:  false,
        objectsInObjects: true,
      },
    ],
    'object-property-newline': [
      'error',
      {
        allowAllPropertiesOnSameLine: false,
      },
    ],
    'operator-linebreak': [
      'error',
      'before',
      {
        overrides: {
          '?': 'none',
          ':': 'none',
        },
      },
    ],
    'padded-blocks': [
      'error',
      'never',
    ],
    'rest-spread-spacing': [
      'error',
      'never',
    ],
    'template-tag-spacing': [
      'error',
      'never',
    ],
    'unicode-bom': [
      'error',
      'never',
    ],
    'wrap-iife': [
      'error',
      'outside',
    ],
    'yield-star-spacing': [
      'error',
      'after',
    ],
    'no-confusing-arrow':  'error',
    'no-floating-decimal': 'error',
    'quote-props':         [
      'error',
      'as-needed',
    ],
    // eslint-plugin-vue规则,对代码语法和风格都进行了规范
    'vue/attribute-hyphenation':                  'error',
    'vue/attributes-order':                       'error',
    'vue/multiline-html-element-content-newline': 'error',
    'vue/component-definition-name-casing':       'off',
    'vue/component-name-in-template-casing':      [
      'error',
      'PascalCase',
      {
        registeredComponentsOnly: true,
        ignores:                  [],
      },
    ],
    'vue/component-options-name-casing': [
      'error',
      'PascalCase',
    ],
    'vue/custom-event-name-casing': [
      'error',
      'kebab-case',
    ],
    'vue/html-comment-content-newline': [
      'error',
      {
        singleline: 'never',
        multiline:  'always',
      },
    ],
    'vue/html-comment-content-spacing': [
      'error',
      'always',
    ],
    'vue/match-component-file-name': [
      'error',
      {
        extensions: [
          'jsx',
          'tsx',
          'vue',
        ],
        shouldMatchCase: false,
      },
    ],
    'vue/no-child-content':                   'error',
    'vue/no-multiple-objects-in-class':       'error',
    'vue/no-potential-component-option-typo': [
      'error',
      {
        presets: ['vue'],
      },
    ],
    'vue/no-reserved-component-names': [
      'error',
      {
        disallowVueBuiltInComponents:  true,
        disallowVue3BuiltInComponents: true,
      },
    ],
    'vue/no-template-target-blank': [
      'error',
      {
        allowReferrer:       false,
        enforceDynamicLinks: 'always',
      },
    ],
    'vue/no-this-in-before-route-enter': 'error',
    'vue/no-unused-properties':          [
      'error',
      {
        groups:              ['props'],
        deepData:            false,
        ignorePublicMembers: false,
      },
    ],
    'vue/no-unused-refs':                       'error',
    'vue/no-use-computed-property-like-method': 'error',
    'vue/no-useless-mustaches':                 [
      'error',
      {
        ignoreIncludesComment: false,
        ignoreStringEscape:    false,
      },
    ],
    'vue/no-useless-v-bind': [
      'error',
      {
        ignoreIncludesComment: false,
        ignoreStringEscape:    false,
      },
    ],
    'vue/no-v-text-v-html-on-component': 'error',
    'vue/no-v-text':                     'error',
    'vue/padding-line-between-blocks':   [
      'error',
      'always',
    ],
    'vue/prefer-import-from-vue':          'error',
    'vue/prefer-prop-type-boolean-first':  'error',
    'vue/prefer-separate-static-class':    'error',
    'vue/prefer-true-attribute-shorthand': 'error',
    'vue/require-direct-export':           [
      'error',
      {
        disallowFunctionalComponentFunction: true,
      },
    ],
    'vue/require-emit-validator': 'error',
    'vue/v-for-delimiter-style':  [
      'error',
      'in',
    ],
    'vue/v-on-function-call': [
      'error',
      'never',
      {
        ignoreIncludesComment: false,
      },
    ],
    'vue/array-bracket-newline': [
      'error',
      {
        multiline: true,
        minItems:  2,
      },
    ],
    'vue/array-bracket-spacing': [
      'error',
      'never',
    ],
    'vue/eqeqeq': [
      'error',
      'always',
    ],
    'vue/no-constant-condition':   'error',
    'vue/no-empty-pattern':        'error',
    'vue/no-irregular-whitespace': 'error',
    'vue/no-loss-of-precision':    'error',
    'vue/no-restricted-syntax':    [
      'error',
      {
        selector: 'WithStatement',
        message:  'With statement are not allowed.',
      },
    ],
    'vue/no-sparse-arrays':  'error',
    'vue/no-useless-concat': 'error',
    'vue/object-shorthand':  [
      'error',
      'always',
    ],
    'vue/prefer-template': 'error',
    'vue/quote-props':     [
      'error',
      'as-needed',
    ],
    'vue/multi-word-component-names': 'off', // 组件和页面的name必须是多单词组成的,可用-或者大驼峰连接
    'vue/no-undef-properties':        [ // 禁止使用未定义的属性,这个规则无法检测到外部文件、外部组件、mixins中的变量,可在ignores中加入需要忽略的关键字
      'error',
      {
        ignores: [],
      },
    ],
    'vue/no-undef-components': [ // 禁止使用未定义的组件,这个规则无法检测到外部文件、外部组件、mixins中的变量,可在ignores中加入需要忽略的关键字
      'error',
      {
        ignorePatterns: [
          '^el-',
          '^g-gantt-',
          'router-view',
        ],
      },
    ],
    'vue/script-indent': [
      'error',
      2,
      {
        baseIndent: 0,
        switchCase: 0,
        ignores:    [],
      },
    ],
    'vue/block-tag-newline': [
      'error',
      {
        singleline:    'always',
        multiline:     'always',
        maxEmptyLines: 0,
      },
    ],
  },
  // 当eslint默认的indent规则使用tab时,vue/script-indent规则会和eslint默认的indent规则冲突,为了兼容两者,所以这里要关闭eslint的默认规则
  overrides: [
    {
      files: ['*.vue'],
      rules: {
        indent: 'off',
      },
    },
  ],
};

通过阅读代码中的注释相信大家能明白各种配置的含义,大部分规则的含义请移步:eslint官网eslint-plugin-vue官网

eslint、eslint-plugin-vue官网阅读技巧🧀

为了让大家能更有效率地理解规则及相关配置,下面做一些技巧性提示。如果不需要请直接跳过。

eslint官网阅读技巧🍻

默认开启的规则🍝

在这里插入图片描述

眼熟吧?打开.eslintrc.js文件:
在这里插入图片描述
此处加入eslint:recommended规则集,英译过来就是eslint推荐规则,eslint:recommended默认是开启的,就不需要在rules选项里面配置该规则了,但是如果不需要某个规则的时候需要去禁用它(使用off或0),如下:
在这里插入图片描述

需要使用非默认规则🍔

相反的,如果我们想使用的规则不在推荐规则集内,就需要自行添加(error或2表示检测到时提示报错,warn或1表示提示警告),例如:
在这里插入图片描述

规则弃用了怎么办❓

细心的小伙伴发现eslint官网有很多废弃的规则:
在这里插入图片描述
而且担心还能不能使用,如果不能使用,那现在正在使用的规则以后废弃了怎么办?请阅读eslint规则废弃政策,翻译一下:
在这里插入图片描述
所以不用担心,是可以一直使用的,废弃代表着不维护而已。
但是有的同学又有疑问:我想看看废弃的规则的含义,在哪里找?
问得好!其实大部分废弃的规则都是与代码风格相关的,可以在eslint stylistic官网找到,eslint从v8.53.0版本开始废弃了代码风格规则集,由eslint stylistic代替维护。从官网中可以看到,eslint中废弃的规则迁移到了@stylistic/eslint-plugin-js规则集中:
在这里插入图片描述
下面两个规则集分别是针对typescript、jsx语法的规则集,其余的请自行查阅。
因此eslint废弃的规则会映射到@stylistic/eslint-plugin-js规则集,所以我们可以直接使用这些废弃的规则,也可以使用@stylistic/eslint-plugin-js规则集,像这样:
在这里插入图片描述

eslint-plugin-vue官网阅读技巧🍻

规则的分类🍝

在这里插入图片描述
这是eslint-plugin-vue规则的菜单,可以看出分成了很多种类,Available rules为可用的规则(全部规则),下面的英译过来分别是:基本规则、优先级A:基本规则、优先级A:基于vue3的基本规则、优先级A:基于vue2的基本规则、优先级B:强烈推荐、优先级B:基于vue3的强烈推荐、优先级C:推荐、未分类的规则、扩展规则、已废弃的规则。根据分类名称可知有的规则集适用于vue2,有的适用于vue3,所以前面我说此文章是对vue3进行eslint配置,意为我使用的都是基于vue3的规则,大家如果是vue2项目,自行在.eslintrc.js文件的extends选项中添加vue2相关的规则集,记得删除vue3的规则集哦。
我们随便打开一条规则:
在这里插入图片描述
证明这个规则默认在这些规则集中,这些规则集是不是又很眼熟?我们打开.eslintrc.js文件:
在这里插入图片描述
所以我们已经继承了这些规则集,默认是开启了上面举例的规则,就不需要在rules选项里面配置该规则了,但是若不想用此规则则需要将其置为off或0

未分类的规则🍝

在这里插入图片描述
可以看到此规则并不属于任何规则集,所以如果我们需要使用它,必须在.eslintrc.js文件中的rules选项中进行配置
在这里插入图片描述

扩展规则🍝

在这里插入图片描述
随便点开一个扩展规则,是不是很眼熟哇?就是前面eslint讲废弃规则讲到的eslint stylistic,这段话翻译过来:
在这里插入图片描述
所以至此形成了一个闭环,eslint-plugin-vue基于eslint,eslint代码风格相关规则迁移至eslint stylistic,它主要是基于js的,也就是< script >,而eslint-plugin-vue的扩展规则也是代码风格相关规则,他主要是基于< template >的,根据需求可以两者结合或者只取其一。

配置package.json脚本自动检测代码🥗

scripts选项中加入以下代码:

"scripts": {
    "lint": "npx eslint --ext .js,.vue ./src vite.config.js .eslintrc.js",
    "lint:fix": "npx eslint --ext .js,.vue --fix ./src vite.config.js .eslintrc.js",
    "lint:out": "npx eslint --ext .js,.vue -o eslint-output.html -f html ./src vite.config.js .eslintrc.js",
    "lint:fixout": "npx eslint --ext .js,.vue --fix -o eslint-output.html -f html ./src vite.config.js .eslintrc.js"
  },

各脚本含义:

  • lint:检测 js、vue文件,包括src目录、vite.config.js文件、.eslintrc.js文件
  • lint:fix:检测 js、vue文件,包括src目录、vite.config.js文件、.eslintrc.js文件,并自动修复
  • lint:out:检测 js、vue文件,包括src目录、vite.config.js文件、.eslintrc.js文件,并输出检测报告
  • lint:fixout:检测 js、vue文件,包括src目录、vite.config.js文件、.eslintrc.js文件,并自动修复且输出检测报告

此时可以运行 npm run lint,在终端可以看到输出的检测结果:
在这里插入图片描述
具体到哪个文件多少行都会显示,按住ctrl并单击能直接定位到有问题的地方。
运行 npm run lint:out,可以生成检测报告(报告名称在npm run lint:out命令中有配置):
在这里插入图片描述
打开此文件可在浏览器中查看详情:
在这里插入图片描述
lint:fix、lint:fixout请自行实验。至此,大家有没有发现好像编辑器里面的代码并没有给出任何报错或警告,好,接下来我们就对vscode做手脚了。

vscode自动检测代码及手动修复🥙

vscode扩展搜索eslint并安装:
在这里插入图片描述
此时我们代码中如果有问题,会出现报错或警告:
在这里插入图片描述
鼠标移入报错或警告会提示相应内容:
在这里插入图片描述
点击快速修复,出现以下选项:
在这里插入图片描述
第一个选项是只修复这一条问题,最后一个选项是修复此文件中所有可修复的问题,其余选项为使用禁用语句来禁用此报错或警告。
如果有时候该插件不工作了,可以运行脚本的命令,可以唤醒插件,感觉很玄学,但很有用,如果还是不行,可以禁用eslint插件再开启或者重新打开vscode。
谢谢捧场~~🍗

  • 11
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值