vuejs / vetur

Vue tooling for VS Code.
https://vuejs.github.io/vetur/
MIT License
5.74k stars 591 forks source link

0.11.0 format JS still doen't obey eslint-prettier #521

Closed islishude closed 6 years ago

islishude commented 6 years ago

Info

Problem

The new vertion 0.11.0 I updated just now

my setting snippet

{
  "prettier.eslintIntegration": true,
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "html",
      "autoFix": true
    },
    {
      "language": "vue",
      "autoFix": true
    }
  ],
  "eslint.autoFixOnSave": true,
  "eslint.alwaysShowStatus": true,
  "eslint.options": {
    "plugins": ["html"]
  },
  "vetur.format.defaultFormatter.html": "js-beautify-html"
}

Reproducible Case

<template>
    <div>
        test vue.
    </div>
</template>
<script>
export default {
  name: "test", // here not obey eslint-standard 
  methods: {
    test() { // here not obey eslint-standard 
      console.log("test"); // here not obey eslint-standard 
    }
  }
}; // here not obey eslint-standard 
</script>
octref commented 6 years ago

What's your .eslintrc and package.json's dependencies? Does it not work on https://github.com/octref/veturpack too?

FFxSquall commented 6 years ago

At me too does not work. I use https://github.com/vuejs-templates/webpack .eslintrc

// https://eslint.org/docs/user-guide/configuring

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module',
  },
  env: {
    browser: true,
  },
  extends: 'airbnb-base',
  // required to lint *.vue files
  plugins: ['html'],
  // check if imports actually resolve
  settings: {
    'import/resolver': {
      webpack: {
        config: 'build/webpack.base.conf.js',
      },
    },
  },
  // add your custom rules here
  rules: {
    // don't require .vue extension when importing
    'import/extensions': [
      'error',
      'always',
      {
        js: 'never',
        vue: 'never',
      },
    ],
    // allow optionalDependencies
    'import/no-extraneous-dependencies': [
      'error',
      {
        optionalDependencies: ['test/unit/index.js'],
      },
    ],
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
  },
};

package.json

"dependencies": {
    "axios": "^0.16.2",
    "lodash": "^4.17.4",
    "vue": "^2.5.3",
    "vue-moment": "^2.1.0",
    "vue-router": "^3.0.1",
    "vuetify": "^0.16.9",
    "vuex": "^2.5.0"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.6",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^7.1.1",
    "babel-plugin-istanbul": "^4.1.1",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chai": "^4.1.2",
    "chalk": "^2.0.1",
    "chromedriver": "^2.27.2",
    "compression-webpack-plugin": "^1.0.1",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^5.1.1",
    "cross-spawn": "^5.0.1",
    "css-loader": "^0.28.0",
    "eslint": "^3.19.0",
    "eslint-config-airbnb-base": "^11.3.0",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-import-resolver-webpack": "^0.8.3",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^3.0.0",
    "eslint-plugin-import": "^2.7.0",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^3.0.2",
    "file-loader": "^1.1.4",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "http-proxy-middleware": "^0.17.3",
    "inject-loader": "^3.0.0",
    "karma": "^1.4.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-phantomjs-shim": "^1.4.0",
    "karma-sinon-chai": "^1.3.3",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "^2.0.2",
    "mocha": "^3.2.0",
    "nightwatch": "^0.9.12",
    "opn": "^5.1.0",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.2.0",
    "phantomjs-prebuilt": "^2.1.16",
    "portfinder": "^1.0.13",
    "rimraf": "^2.6.0",
    "selenium-server": "^3.7.0",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "sinon": "^4.1.1",
    "sinon-chai": "^2.8.0",
    "stylus": "^0.54.5",
    "stylus-loader": "^3.0.1",
    "url-loader": "^0.5.8",
    "vue-loader": "^13.4.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.3",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-middleware": "^1.12.0",
    "webpack-hot-middleware": "^2.18.2",
    "webpack-merge": "^4.1.1"
  }
islishude commented 6 years ago

package.json

{
  "name": "vue-app",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "isLishude <lishude@aliyun.com>",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "start": "npm run dev",
    "build": "node build/build.js",
    "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
    "e2e": "node test/e2e/runner.js",
    "test": "npm run unit && npm run e2e",
    "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
  },
  "dependencies": {
    "amazeui": "^2.7.2",
    "axios": "^0.17.0",
    "jparticles": "^2.0.1",
    "js-cookie": "^2.2.0",
    "lodash": "^4.17.4",
    "vue": "^2.5.2",
    "vue-qriously": "^1.1.1",
    "vue-router": "^3.0.1",
    "vue-toasted": "^1.1.21",
    "vuex": "^3.0.0"
  },
  "devDependencies": {
    "autoprefixer": "^7.1.2",
    "babel-core": "^6.22.1",
    "babel-eslint": "^7.1.1",
    "babel-loader": "^7.1.1",
    "babel-plugin-istanbul": "^4.1.1",
    "babel-plugin-transform-runtime": "^6.22.0",
    "babel-preset-env": "^1.3.2",
    "babel-preset-stage-2": "^6.22.0",
    "babel-register": "^6.22.0",
    "chai": "^4.1.2",
    "chalk": "^2.0.1",
    "chromedriver": "^2.27.2",
    "connect-history-api-fallback": "^1.3.0",
    "copy-webpack-plugin": "^4.0.1",
    "cross-env": "^5.0.1",
    "cross-spawn": "^5.0.1",
    "css-loader": "^0.28.0",
    "eslint": "^3.19.0",
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-html": "^3.0.0",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.2.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^3.0.1",
    "eslint-plugin-vue": "^2.1.0",
    "eventsource-polyfill": "^0.9.6",
    "express": "^4.14.1",
    "extract-text-webpack-plugin": "^3.0.0",
    "file-loader": "^1.1.4",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "http-proxy-middleware": "^0.17.3",
    "inject-loader": "^3.0.0",
    "karma": "^1.4.1",
    "karma-coverage": "^1.1.1",
    "karma-mocha": "^1.3.0",
    "karma-phantomjs-launcher": "^1.0.2",
    "karma-phantomjs-shim": "^1.4.0",
    "karma-sinon-chai": "^1.3.1",
    "karma-sourcemap-loader": "^0.3.7",
    "karma-spec-reporter": "0.0.31",
    "karma-webpack": "^2.0.2",
    "mocha": "^3.2.0",
    "nightwatch": "^0.9.12",
    "node-sass": "^4.5.3",
    "opn": "^5.1.0",
    "optimize-css-assets-webpack-plugin": "^3.2.0",
    "ora": "^1.2.0",
    "phantomjs-prebuilt": "^2.1.14",
    "portfinder": "^1.0.13",
    "rimraf": "^2.6.0",
    "sass-loader": "^6.0.6",
    "selenium-server": "^3.0.1",
    "semver": "^5.3.0",
    "shelljs": "^0.7.6",
    "sinon": "^4.0.0",
    "sinon-chai": "^2.8.0",
    "url-loader": "^0.5.8",
    "vue-loader": "^13.3.0",
    "vue-style-loader": "^3.0.1",
    "vue-template-compiler": "^2.5.2",
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",
    "webpack-dev-middleware": "^1.12.0",
    "webpack-hot-middleware": "^2.18.2",
    "webpack-merge": "^4.1.0"
  },
  "engines": {
    "node": ">= 4.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

.eslint.js

// https://eslint.org/docs/user-guide/configuring

module.exports = {
  root: true,
  parser: 'babel-eslint',
  parserOptions: {
    sourceType: 'module'
  },
  env: {
    browser: true,
  },
  // https://github.com/standard/standard/blob/master/docs/RULES-en.md
  extends: 'standard',
  // required to lint *.vue files
  plugins: [
    'html'
  ],
  // add your custom rules here
  'rules': {
    // allow paren-less arrow functions
    'arrow-parens': 0,
    // allow async-await
    'generator-star-spacing': 0,
    // allow debugger during development
    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
  }
}
octref commented 6 years ago

I see the problem. Will take a look tonight. Thanks.

octref commented 6 years ago

The problem comes from ESLint wants to do the <script> extraction by itself, whereas Vetur just passes in the extracted <script> section

octref commented 6 years ago

I'll follow up with a PR: https://github.com/vuejs-templates/webpack/issues/901

Meanwhile, you can try this setup:

{
  "extends": [
    "eslint:recommended",
    "plugin:vue/recommended",
    "standard"
  ],
  "rules": {
    "import/no-unresolved": 0,
    "import/no-unassigned-import": 0,
    "vue/html-no-self-closing": "error",
    "semi": ["error", "never"],
    "no-console": "off",
    "space-before-function-paren": [
      "error",
      {
        "anonymous": "always",
        "named": "always",
        "asyncArrow": "always"
      }
    ]
  }
}
MeirionHughes commented 6 years ago

seems to default to none for html: I had to set "vetur.format.defaultFormatter.html": "js-beautify-html" in vscode settings.

pillarlee16 commented 6 years ago

@octref, I've also faced a similar issue.

When "prettier.eslintIntegration" is true, I expected that if I run vscode 'Format Document' option, it will fix the differences of eslint in script tag.

<!-- App.vue (before) -->
<template>
</template>

<script>
import HelloWorld from './components/HelloWorld';

export default {
  name: 'app',
  components: {
    HelloWorld,
  },
  methods: {
    foo: function () {
      return 'bar';
    },
  },
};
</script>

<style>
</style>
<!-- App.vue (expected) -->
<!-- object-shorthand (https://eslint.org/docs/rules/object-shorthand) should be fixed -->
<template>
</template>

<script>
import HelloWorld from './components/HelloWorld';

export default {
  name: 'app',
  components: {
    HelloWorld,
  },
  methods: {
    foo () {
      return 'bar';
    },
  },
};
</script>

<style>
</style>

However, prettier part of prettier-eslint works, but eslint part doesn't work.

As you mentioned, ESLint parsers (both eslint-plugin-html and vue-eslint-parser) check whether file extension is '.vue' and then requires code string includes script tag.

In addition, https://github.com/vuejs/vetur/blob/25a4151a6cd424655ba7cec3042c3abb6811391a/server/src/utils/prettier/index.ts#L42-L45 when this code run 'prettier-eslint', it doesn't pass filePath. when I tested vetur in vscode debugger (I followed https://vuejs.github.io/vetur/CONTRIBUTING.html), it failed to retrieve proper eslint configs because that filePath was missing.

My poor solution was that it just replaces '.vue' of filePath with '.js' when it passes values to 'prettier-eslint' and it worked. However, I don't think that this is a proper approach.

octref commented 6 years ago

I'd suggest moving away from eslint-plugin-html to eslint-plugin-vue which is the official dedicated eslint plugin from @vuejs.

eslint-plugin-html won't contain many of the autofix in eslint-plugin-vue, so even if prettier-eslint runs through prettier -> eslint --autofix, the output with eslint-plugin-html won't be good enough.

@pillarlee16

when I tested vetur in vscode debugger (I followed https://vuejs.github.io/vetur/CONTRIBUTING.html), it failed to retrieve proper eslint configs because that filePath was missing. My poor solution was that it just replaces '.vue' of filePath with '.js' when it passes values to 'prettier-eslint' and it worked.

It was working for me in https://github.com/octref/veturpack -- what's your project structure where it didn't find the correct .eslintrc?

I also tried passing in filePath with .vue but it didn't work so I left it out. Changing to .js sounds really hacky to me too...

karlhorky commented 6 years ago

Is this actually working with veturpack without the .prettierrc file? If I delete this file it does not seem to read the ESLint config correctly. It then autoformats to incorrect syntax:

screen shot 2017-12-12 at 16 01 27

I tried the instructions in https://github.com/vuejs/vetur/issues/521#issuecomment-342560578 (this also needed eslint-plugin-node - see error message below) but that didn't seem to help.

Installation error message with -standard packages:

Failed to load plugin node: Cannot find module 'eslint-plugin-node' Referenced from: /Users/k/p/veturpack2/.eslintrc

Detailed list of what I did:

  1. Cloned veturpack
  2. npm install
  3. npm install eslint-config-standard eslint-plugin-standard
  4. npm install eslint-plugin-node
  5. rm .prettierrc
  6. code .
  7. Opened Counter.vue and add a line before the <script> tag. It will autoformat to incorrect syntax.

.prettierrc (deleted)

settings.json

{
  "workbench.startupEditor": "newUntitledFile",
  "workbench.activityBar.visible": false,
  "editor.wordWrap": "on",
  "editor.minimap.enabled": false,
  "editor.cursorBlinking": "solid",
  "editor.renderIndentGuides": false,
  "prettier.eslintIntegration": true,
  "editor.formatOnType": true,
  "javascript.format.enable": false,
  "editor.formatOnSave": true,
  "files.autoSave": "onWindowChange",
  "editor.folding": false,
  "explorer.openEditors.visible": 0,
  "workbench.colorCustomizations": {
    "statusBar.background": "#303030",
    "statusBar.noFolderBackground": "#222225",
    "statusBar.debuggingBackground": "#511f1f"
  },
  "vim.useSystemClipboard": true,
  "files.trimTrailingWhitespace": true,
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    {
      "language": "vue",
      "autofix": true
    }
  ],
  "editor.tabSize": 2,
  "workbench.editor.tabCloseButton": "off",
  "eslint.autoFixOnSave": true,
  "eslint.alwaysShowStatus": true
}

.eslintrc

{
  "extends": [
    "eslint:recommended",
    "plugin:vue/recommended",
    "standard"
  ],
  "rules": {
    "import/no-unresolved": 0,
    "import/no-unassigned-import": 0,
    "vue/html-no-self-closing": "error",
    "semi": ["error", "never"],
    "no-console": "off",
    "space-before-function-paren": [
      "error",
      {
        "anonymous": "always",
        "named": "always",
        "asyncArrow": "always"
      }
    ]
  }
}

package.json

{
  "name": "veturpack",
  "version": "0.1.0",
  "description": "Vuepack adapted for Vetur.",
  "main": "client/index.js",
  "scripts": {
    "build": "webpack --config build/webpack.prod.js",
    "dev": "node build/server.js",
    "lint": "xo **/client/**/*.{vue,js} !node_modules/**"
  },
  "author": "Pine Wu <octref@gmail.com>",
  "license": "MIT",
  "xo": {
    "extends": "./.eslintrc",
    "esnext": true,
    "envs": [
      "browser"
    ]
  },
  "babel": {
    "presets": [
      [
        "vue-app",
        {
          "useBuiltIns": true
        }
      ]
    ]
  },
  "postcss": {
    "plugins": {
      "autoprefixer": {},
      "postcss-nested": {}
    }
  },
  "browserslist": [
    "last 2 versions",
    "ie > 8"
  ],
  "dependencies": {
    "babel-runtime": "^6.26.0",
    "eslint-config-standard": "^11.0.0-beta.0",
    "eslint-plugin-node": "^5.2.1",
    "eslint-plugin-standard": "^3.0.1",
    "lodash": "^4.17.4",
    "prettier": "^1.7.4",
    "prettier-eslint-cli": "^4.4.0",
    "promise-polyfill": "^6.0.2",
    "vue": "^2.5.3",
    "vue-router": "^3.0.1",
    "vuex": "^3.0.1",
    "vuex-router-sync": "^5.0.0"
  },
  "devDependencies": {
    "@types/lodash": "^4.14.77",
    "autoprefixer": "^7.1.5",
    "babel-core": "^6.26.0",
    "babel-loader": "^7.1.2",
    "babel-preset-vue-app": "^1.3.1",
    "chalk": "^2.1.0",
    "copy-webpack-plugin": "^4.1.1",
    "cross-env": "^5.0.5",
    "css-loader": "^0.28.7",
    "eslint": "^4.8.0",
    "eslint-config-vue": "latest",
    "eslint-plugin-vue": "beta",
    "express": "^4.16.2",
    "extract-text-webpack-plugin": "^3.0.1",
    "file-loader": "^1.1.5",
    "friendly-errors-webpack-plugin": "^1.6.1",
    "html-webpack-plugin": "^2.30.1",
    "node-sass": "^4.5.3",
    "offline-plugin": "^4.8.4",
    "postcss-loader": "^2.0.7",
    "postcss-nested": "^2.1.2",
    "raw-loader": "^0.5.1",
    "rimraf": "^2.6.2",
    "sass-loader": "^6.0.6",
    "style-loader": "^0.19.0",
    "vue-loader": "^13.3.0",
    "vue-template-compiler": "^2.5.3",
    "webpack": "3.7.1",
    "webpack-dev-middleware": "^1.12.0",
    "webpack-hot-middleware": "^2.19.1",
    "xo": "^0.18.2"
  }
}
dmzkrsk commented 6 years ago

I can confirm the behaviour described by @karlhorky prettier-eslint does NOT find eslint config when filePath is empty

There's another fix:

Don't rename '.vue' to '.js', just pass directory name to eslint!

            filePath: require("path").dirname(filePath),
            text: code,
            fallbackPrettierOptions: prettierOptions
        });