Can't get correct autoformat on save in Visual Studio Code with ESLint and Prettier

28,661

Solution 1

Short answer: I needed: "editor.formatOnSave": false, "javascript.format.enable": false.

I finally found the magical combination of settings, thanks to this thread from Wes Bos on Twitter. I was right in my suspicion that there seem to be multiple conflicting formatters. Though I'm not sure what they actually are, I was able to turn off all but eslint as follows:

In the VS Code settings, I need:

"editor.formatOnSave": false,
"javascript.format.enable": false,
"eslint.autoFixOnSave": true,
"eslint.alwaysShowStatus": true,
"eslint.options": {
  "extensions": [ ".html", ".js", ".vue", ".jsx" ]
},
"eslint.validate": [
  { "language": "html", "autoFix": true },
  { "language": "vue", "autoFix": true },
  { "language": "javascript", "autoFix": true },
  { "language": "javascriptreact", "autoFix": true }
]

In .eslintrc.js, then I can use the settings in my original post and then also change 'vue/max-attributes-per-line' as desired. Then VS Code's ESLint plugin will format code one step at a time on every save, much as kenjiru wrote. One last snag: HMR won't pick up these changes, so rebuild from scratch.

Solution 2

With 'vue/max-attributes-per-line': 'off' the rule is disabled so VSCode does not try to fix the long line on autosave. Other eslint fixes are applied, as expected.

With 'vue/max-attributes-per-line': 1 VSCode fixes only one error per save. This is a known limitation of vscode-eslint

vscode-eslint only does a single pass in order to keep to a minimum the amount of edits generated by the plugin. The goal is to keep as many markers (like break points) in the file as possible.

VSCode has a time limit of 1 second for all the plugins to compute the change set on save. If one of the plugins causes the other plugins to not run for 3 times in a row, it will be disabled.

eslint --fix runs all the rules in a loop until there are no more linting errors. I think it has a limit of 10 iterations maximum.

See these links for more details:

I've created a minimal setup to demonstrate this issue:

Solution 3

I know this is old but in case anyone should find this and not have success with the posted solutions, the fix for me was to add:

"editor.codeActionsOnSave": {
   "source.fixAll": true
}

I did not need "editor.formatOnSave": true for some reason. I do not have Prettier installed - only ESLint - but this now performs any fixes automatically when I save.

Solution 4

This is the setup I ended up going with in VSC settings.json file.

Works perfectly for locally set up eslint disabling the default vetur settings (if the plugin is installed).

"files.autoSave": "onFocusChange",
"editor.codeActionsOnSave": {
  "source.fixAll.eslint": true
},
"editor.formatOnSave": false,
"javascript.format.enable": false,
"eslint.alwaysShowStatus": true,
"eslint.options": {
  "extensions": [ ".html", ".js", ".vue", ".jsx" ]
},
"eslint.validate": [
  "html",
  "javascript",
  "vue"
],
Share:
28,661
Patrick Szalapski
Author by

Patrick Szalapski

I make software using .NET, lead software teams, and coach on Scrum and Agile. I've spent my whole life twiddling with software, and I have grown to be passionate about good software design and practices. Since 2009, I have been leading Scrum teams and gathering all the best practices and attitudes necessary to make a software team effective and efficient. I am most experienced in digital/relationship marketing, eCommerce, CRM, ETL, and data warehousing domains, but I don't limit myself to these areas.

Updated on July 09, 2022

Comments

  • Patrick Szalapski
    Patrick Szalapski almost 2 years

    in Visual Studio Code with ESLint and Prettier when working on .vue files, it seems I can't get vue/max-attributes-per-line to auto-fix correctly.

    For example, with vue/max-attributes-per-line set to 'off', and I try to add line breaks manually it corrects it to always have every element on no more than one line, no matter if it is 81, 120, 200, or more characters wide. How can I figure out what is forcing my markup elements onto exactly one line?

    I am using ESLint version 5.1.0 and Visual Studio Code (without the Prettier Extension), with Prettier 1.14.2.

    Here's the example in a .vue file-- I cannot make this go on multiple lines no matter what I do, when 'vue/max-attributes-per-line': 'off'. Every time I save, it forces the long line of markup to be all on one line.

    <template>
      <font-awesome-icon v-if="statusOptions.icon" :icon="statusOptions.icon" :spin="statusOptions.isIconSpin" :class="['saving-indicator', 'pl-1', 'pt-1', statusOptions.iconClasses]" />
    </template>
    

    If I set 'vue/max-attributes-per-line': 2, it formats like so, with one line break(which is quite wrong as well).

    <font-awesome-icon
      v-if="statusOptions.icon" 
      :icon="statusOptions.icon"
      :spin="statusOptions.isIconSpin"
      :class="['saving-indicator', 'pl-1', 'pt-1', statusOptions.iconClasses]"
    />
    

    If I try to reformat it manually, it just reverts to the above when I save.

    Additionally, it seems to reformat twice when I hit Ctrl+S: first it reformats to put it all on one line, then a half-second later the formatting above results. Any ideas? What is causing this weirdness--are there multiple reformatters running? How do I figure out what the first one is to disable it?

    VS Code workspace settings:

    {
      "editor.formatOnType": false,
      "editor.formatOnPaste": false,
      "editor.formatOnSave": true,
      "[javascript]": {
        "editor.tabSize": 2
      },
      "[vue]": {
        "editor.tabSize": 2
      },
      "[csharp]": {
        "editor.tabSize": 4
      },
      "javascript.format.insertSpaceAfterFunctionKeywordForAnonymousFunctions": true,
      "javascript.referencesCodeLens.enabled": true,
      "vetur.validation.script": false,
      "vetur.validation.template": false,
      "eslint.autoFixOnSave": true,
      "eslint.alwaysShowStatus": true,
      "eslint.options": {
        "extensions": [
          ".html",
          ".js",
          ".vue",
          ".jsx"
        ]
      },
      "eslint.validate": [
        {
          "language": "html",
          "autoFix": true
        },
        {
          "language": "vue",
          "autoFix": true
        },
        "vue-html",
        {
          "language": "javascript",
          "autoFix": true
        },
        {
          "language": "javascriptreact",
          "autoFix": true
        }
      ],
      "editor.rulers": [
        80,
        100
      ]
    }
    

    .eslintrc.js:

    module.exports = {
      parserOptions: {
        parser: 'babel-eslint'
      },
      env: {
        browser: true,
        node: true,
        jest: true
      },
      globals: {
        expect: true
      },
      extends: [
        'prettier',
        'plugin:vue/recommended',        // /base, /essential, /strongly-recommended, /recommended
        'plugin:prettier/recommended',   // turns off all ESLINT rules that are unnecessary due to Prettier or might conflict with Prettier. 
        'eslint:recommended'
      ],
      plugins: ['vue', 'prettier'],
      rules: {
        'vue/max-attributes-per-line': 'off',
        'prettier/prettier': [            // customizing prettier rules (not many of them are customizable)
          'error',
          {
            singleQuote: true,
            semi: false,
            tabWidth: 2
          },
        ],
        'no-console': 'off'
      }
    }
    

    Without changing any settings, ESLint --fix does indeed format properly--breaking all my .vue template elements into many lines properly. So any ideas how I whip VS Code into shape? The above settings didn't help, but I am at a loss how as to even know what is interfering. Any ideas?

    To emphasize, when I save in VS Code, a long HTML element will collapse to one line then break to two lines a half-second later, all from one save operation. I'm expecting it instead to break it up into many lines. It would be okay if it took several saves, but instead the first save shows this behavior as well as every subsequent save.

  • Patrick Szalapski
    Patrick Szalapski over 5 years
    This is not at all the behavior I am seeing. With 'vue/max-attributes-per-line': 'off', the long line is forced onto one line no matter how many line breaks I add. With 'vue/max-attributes-per-line': 1, the long line is broken only once no matter how many times I press Ctrl+S. Any other ideas?
  • kenjiru
    kenjiru over 5 years
    You got this behavior with my repository?
  • Richard Matsen
    Richard Matsen over 5 years
    This sample repository works on my machine, so seems quite likely to be another extension running first that we are not yet aware of.
  • Patrick Szalapski
    Patrick Szalapski over 5 years
    Thanks for the thoughts; they weren't exactly my problem but helped nudge me to the answer.
  • HalfWebDev
    HalfWebDev over 5 years
    Our fates were intertwined. Ditto situations and explanations. Following you from github.com/vuejs/eslint-plugin-vue/issues/557. Worked for me as well
  • Darko Tasevski
    Darko Tasevski over 5 years
    Spent more time setting prettier and eslint to work correctly than actually coding -.- Your answer helped a lot, thanks! Edit: It seems to be working well with javascript.format.enable: true If you want to keep VSCode formatter to work for other files (json, gql, etc.) instead of "editor.formatOnSave": false add this line to settings.json: "[javascript]": { "editor.formatOnSave": false },
  • Micros
    Micros over 5 years
    In some cases, it might be enough to go into the User Settings, search for eslint, then activate the checkbox for Eslint: Auto Fix On Save
  • Paul-Hebert
    Paul-Hebert almost 5 years
    This has been a real pain for me lately. This answer finally fixed it! Though I was able to remove the jsx/react stuff. Thanks!
  • parker_codes
    parker_codes over 4 years
    If you're working in WSL, remember that there are different settings for User / WSL / and Workspace! Set "javascript.format.enable": false in User and WSL.
  • Mieszczańczyk S.
    Mieszczańczyk S. over 4 years
    Not working for me - since some of the dependencies are deprecated. Here my issue: github.com/vuejs/eslint-plugin-vue/issues/557
  • Mieszczańczyk S.
    Mieszczańczyk S. over 4 years
    Not working and for now autoFix is set as true in default.
  • Jon Wood
    Jon Wood over 4 years
    "eslint.formatOnSave is now: "editor.codeActionsOnSave": { "source.fixAll.eslint": true}
  • Akintunde
    Akintunde almost 4 years
    Thanks. You saved me some hours
  • NSjonas
    NSjonas over 3 years
    for the love of god ty.... Been driving me crazy for weeks but never could figure it out despite multiple debugging attempts.
  • Admin
    Admin over 3 years
    This works great thank you! I felt the need to say it because each time I saved a file, immediately I had to hit cmd + z to undo the autosave changes. My life is normal again.