vue項(xiàng)目中如何配置eslint和prettier
一、現(xiàn)象
新建vue項(xiàng)目后,寫完代碼后,希望能保存ctrl+s之后,自動格式化代碼
目前只是使用vue-cli腳手架創(chuàng)建的項(xiàng)目,雖然引入了eslint,但要想在vscode中保存代碼時,實(shí)現(xiàn)自動格式化,還需要做以下的配置。
二、安裝vscode插件
首先要確保已經(jīng)安裝了 ESLlint、Vetur、Prettier 這三個插件。
1.eslint
在團(tuán)隊(duì)協(xié)作中,為避免低級 Bug、產(chǎn)出風(fēng)格統(tǒng)一的代碼,會預(yù)先制定編碼規(guī)范。
使用 Lint 工具和代碼風(fēng)格檢測工具,則可以輔助編碼規(guī)范執(zhí)行,有效控制代碼質(zhì)量。
ESLint 由 JavaScript 紅寶書 作者 Nicholas C. Zakas 編寫, 2013 年發(fā)布第一個版本。
NCZ 的初衷不是重復(fù)造一個輪子,而是在實(shí)際需求得不到 JSHint 團(tuán)隊(duì)響應(yīng)的情況下做出的選擇:以可擴(kuò)展、每條規(guī)則獨(dú)立、不內(nèi)置編碼風(fēng)格為理念編寫一個 lint 工具。
安裝之后:

2.Vetur
這個插件主要作用就是讓vscode識別.vue文件,實(shí)現(xiàn)語法高亮。

3.Prettier
它的作用是將我們散漫的風(fēng)格迥異的代碼格式化為符合規(guī)范的代碼。
安裝之后:

三、具體使用
團(tuán)隊(duì)開發(fā)寫代碼,通常會有以下這么兩個問題存在:
代碼質(zhì)量問題:使用方式有可能有問題
代碼風(fēng)格問題:風(fēng)格不符合一定規(guī)則
1.先談代碼質(zhì)量問題
當(dāng)你安裝了插件之后,你的代碼不符合它設(shè)定的默認(rèn)規(guī)范的時候,就會出現(xiàn)波浪線提示
npx eslint --init

這時候打開項(xiàng)目代碼,就會報錯了:

這是因?yàn)槲覀冞x擇了:“eslint-config-airbnb-base”作為eslint的默認(rèn)配置,而它設(shè)定了字符串使用單引號的。
具體的默認(rèn)配置可以查看:GitHub - airbnb/javascript: JavaScript Style Guide
打開.eslintrc.js文件,我們可以在rules處增加一個規(guī)則,這些規(guī)則會覆蓋剛剛我們采用的airbnb默認(rèn)配置,也就是說,我們可以在這里自定義:
rules: {
quotes: [2, 'double'], //錯誤,必須雙引號
semi: [ //錯誤,必須有分號結(jié)尾
2,
'always',
{
omitLastInOneLineBlock: true,
},
],
},
于是代碼又恢復(fù)了正常:

像這樣,統(tǒng)一代碼書寫的配置,是eslint的主要用途,可以統(tǒng)一代碼,減少bug的出現(xiàn)。
但是又出現(xiàn)了新的問題,如果出現(xiàn)這個eslint配置,使用者就必須寫成這種形式,那剛開始可能會很抵觸,畢竟習(xí)慣起來需要一個過程。所以應(yīng)該在使用eslint時,按ctrl+s保存代碼,能夠自動轉(zhuǎn)化為符合要求的代碼!
保存代碼時自動規(guī)范格式?
這個需要在vscode中進(jìn)行配置,按住ctrl+shift+p,輸入setting,打開setting.json,完成以下配置:
{
// 保存時 prettier 自動格式化
"editor.formatOnSave": true,
// 保存時自動啟用 eslint --fix 自動修復(fù)
"editor.codeActionsOnSave": {
"source.fixAll": true,
"eslint.autoFixOnSave" : true,
},
// 配置eslint適用于vue代碼
"eslint.validate": [
"vue",
"javascript",
// "typescript",
// "typescriptreact",
// "html",
// {
// "language":"vue",
// "autoFix":true
// }
],
}
這時候,回到代碼中ctrl+s,就會發(fā)現(xiàn)逗號的問題被自動修復(fù)了。

另外,有些文件,我們并不需要用eslint作為校驗(yàn),就可以在根目錄下新建一個.eslintignore文件來管理:
.eslintrc.js .prettierrc.js babel.config.js vetur.config.js /node_modules/
2.再來談代碼風(fēng)格問題
像縮進(jìn)是用空格還是用tab啦,使用單引號還是雙引號啦,句末需不需要分號啦,都屬于代碼風(fēng)格問題,他們影響的更多的是代碼的統(tǒng)一風(fēng)格。而這些,prettier也可以進(jìn)行規(guī)范。
在項(xiàng)目根目錄下新建.prettierrc文件,然后配置:
{
"semi": false,
"singleQuote": true
}
意思是不需要句尾分號,字符串需要單引號??梢宰⒁獾?,我這里特地寫地和上文eslint地配置沖突了。
解決配置的沖突問題
沖突的本質(zhì)在于 eslint既負(fù)責(zé)了代碼質(zhì)量檢測,又負(fù)責(zé)了一部分的格式美化工作,格式化的部分規(guī)則和 prettier不兼容。
extends: [
'plugin:vue/essential',
'airbnb-base',
"plugin:prettier/recommended"http://這樣寫,讓pettier的規(guī)則,放在eslint規(guī)則擴(kuò)展中,于是會經(jīng)由eslint報錯
],
網(wǎng)上的一些文章配置的這兩個地方的代碼,實(shí)現(xiàn)的效果和這一個extend是一樣的。

這樣設(shè)置之后,prettier的規(guī)則會放置到eslint的擴(kuò)展中,報錯會經(jīng)由eslint報錯。在VSCode中配置了保存自動格式化后,eslint中將代碼進(jìn)行格式化后,會重新被prettier再次格式化。因此最終的格式化效果是
Prettier提供的,然而我們代碼校驗(yàn)使用的是ESLint,因此往往會出現(xiàn)沖突,最常見的沖突就是:eslint fix后變成單引號,保存(prettier)自動格式化后變成雙引號,導(dǎo)致代碼校驗(yàn)異常。
接下來舉例兩者的沖突:
.eslint文件:必須分號結(jié)尾且雙引號
"rules": {
"quotes": [2, "double"], //警告,必須雙引號
semi: [
2,
"always",
{
omitLastInOneLineBlock: true
}
],
}
.prettierr文件:必須無分號結(jié)尾,且單引號
{
"semi": false,
"singleQuote": true
}于是會出現(xiàn)按ctrl+S,第一次報eslint配置的錯,第二次報prettier的錯,循環(huán)往復(fù),不斷沖突。

網(wǎng)上說的讓prettier的規(guī)則覆蓋eslint的,我并沒有生效,而是像上文這樣不斷沖突。
最后的解決是把eslint和prettier中的配置弄成一致:
.eslint.js配置:
module.exports = {
env: {
browser: true,
es6: true,
node: true,
},
extends: [
'plugin:vue/essential',
'airbnb-base',
"plugin:prettier/recommended"http://這樣寫,讓pettier的規(guī)則,放在eslint規(guī)則擴(kuò)展中,于是會經(jīng)由eslint報錯
],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: [
'vue',
],
"rules": {
"quotes": [2, "double"], //警告,必須雙引號
"no-compare-neg-zero": 2, //禁止與 -0 進(jìn)行比較
"no-cond-assign": [
2,
"except-parens"
], //禁止條件語句中出現(xiàn)賦值操作符
"no-console": 0, //允許出現(xiàn)console
"no-constant-condition": 2, //禁止在條件中使用常量表達(dá)式
"no-control-regex": 2, //禁止在正則表達(dá)式中使用控制字符
"no-debugger": 0, //可以使用debugger
"no-dupe-args": 2, //禁止 function 定義中出現(xiàn)重名參數(shù)
"no-dupe-keys": 2, //禁止對象字面量中出現(xiàn)重復(fù)的 key
"no-duplicate-case": 2, //禁止出現(xiàn)重復(fù)的 case 標(biāo)簽
"no-empty": 2, //禁止出現(xiàn)空語句塊
"no-empty-character-class": 2, //禁止在正則表達(dá)式中使用空字符集
"no-ex-assign": 2, //禁止對 catch 子句的參數(shù)重新賦值
"no-extra-boolean-cast": 2, //禁止不必要的布爾轉(zhuǎn)換
"no-extra-parens": [
"error",
"functions"
], //禁止不必要的括號
"no-extra-semi": 2, //禁止不必要的分號
"no-func-assign": 2, //禁止對 function 聲明重新賦值
"no-inner-declarations": 0, //禁止在嵌套的塊中出現(xiàn)變量聲明或 function 聲明
"no-invalid-regexp": 2, //禁止 RegExp 構(gòu)造函數(shù)中存在無效的正則表達(dá)式字符串
"no-irregular-whitespace": 2, //禁止不規(guī)則的空白
"no-obj-calls": 2, //禁止把全局對象作為函數(shù)調(diào)用
"no-prototype-builtins": 2, //禁止直接調(diào)用 Object.prototypes 的內(nèi)置屬性
"no-regex-spaces": 2, //禁止正則表達(dá)式字面量中出現(xiàn)多個空格
"no-sparse-arrays": 2, //禁用稀疏數(shù)組
"no-template-curly-in-string": 0, //禁止在常規(guī)字符串中出現(xiàn)模板字面量占位符語法
"no-unexpected-multiline": 2, //禁止出現(xiàn)令人困惑的多行表達(dá)式
"no-unreachable": 2, //禁止在 return、throw、continue 和 break 語句之后出現(xiàn)不可達(dá)代碼
"no-unsafe-finally": 2, //禁止在 finally 語句塊中出現(xiàn)控制流語句
"no-unsafe-negation": 2, //禁止對關(guān)系運(yùn)算符的左操作數(shù)使用否定操作符
"use-isnan": 2, //要求使用 isNaN() 檢查 NaN
"valid-jsdoc": "off", //
"valid-typeof": 2, //強(qiáng)制 typeof 表達(dá)式與有效的字符串進(jìn)行比較
"curly": 2, //強(qiáng)制所有控制語句使用一致的括號風(fēng)格
"consistent-return": [
2,
{
treatUndefinedAsUnspecified: true
}
],
"default-case": 2,
eqeqeq: "off",
"guard-for-in": 0,
"no-case-declarations": 0,
"no-empty-pattern": 2,
"no-fallthrough": 2,
"no-global-assign": [
2,
{
exceptions: []
}
],
"no-octal": 2,
"no-redeclare": 2,
"no-self-assign": 2,
"no-unused-labels": 2,
"no-useless-escape": 2,
strict: 2,
"no-delete-var": 2,
"no-undefined": 0,
"no-undef": 2,
"no-use-before-define": 2,
"array-bracket-spacing": [
2,
"never"
],
"block-spacing": [
2,
"always"
],
"brace-style": [
2,
"1tbs"
],
"comma-dangle": [
"error",
"never"
],
"comma-spacing": [
2,
{
before: false,
after: true
}
],
"comma-style": [
2,
"last"
],
"computed-property-spacing": [
"error",
"never"
],
"eol-last": [
2,
"always"
],
"func-call-spacing": [
"error",
"never"
],
indent: [
"error",
2,
{
SwitchCase: 1
}
],
"jsx-quotes": [
"error",
"prefer-double"
],
"key-spacing": [
"error",
{
beforeColon: false,
afterColon: true
}
],
"new-cap": [
"error",
{
newIsCap: true,
capIsNewExceptionPattern: "(Type[a-zA-Z0-9]+|Deco[a-zA-Z0-9]+)+"
}
],
"new-parens": "error",
"no-mixed-spaces-and-tabs": 2,
"no-multi-assign": "error",
"no-multiple-empty-lines": "error",
semi: [
2,
"always",
{
omitLastInOneLineBlock: true
}
],
"constructor-super": 2,
"no-class-assign": 0,
"no-const-assign": 2,
"no-this-before-super": 2,
"no-var": 2,
"no-dupe-class-members": 2,
"no-new-symbol": 2,
"require-yield": 2,
"prefer-const": 0,
}
};
.prettierrc.js的配置
module.exports = {
"arrowParens": "avoid",
"bracketSpacing": true,
"cursorOffset": -1,
"insertPragma": false,
"jsxBracketSameLine": false,
"plugins": [],
"printWidth": 80,
"proseWrap": "preserve",
"rangeStart": 0,
"requirePragma": false,
"semi": true,
"singleQuote": false,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": false
};
vscode中的setting.json配置
當(dāng)項(xiàng)目中沒有.prettierrc文件時,就會讓這里面的配置生效了:
{
"editor.minimap.enabled": false,
"diffEditor.ignoreTrimWhitespace": false,
"javascript.updateImportsOnFileMove.enabled": "always",
"http.proxyAuthorization": "false",
"workbench.editor.enablePreview": false,
"workbench.startupEditor": "newUntitledFile",
"emmet.includeLanguages": {
"vue-html": "html",
"vue": "html"
},
"emmet.preferences": {
},
"emmet.showSuggestionsAsSnippets": true,
"eslint.codeAction.showDocumentation": {
"enable": true
},
//配置保存時按照eslint文件的規(guī)則來處理一下代碼
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"eslint.autoFixOnSave" : true,
},
//配置eslint適用于vue代碼
"eslint.validate": [
"vue",
"javascript",
// "typescript",
// "typescriptreact",
// "html",
// {
// "language":"vue",
// "autoFix":true
// }
],
"window.zoomLevel": -1,
"leek-fund.immersiveBackground": true,
"leek-fund.statusBarStock": [
"sh000001"
],
"interview.workspaceFolder": "C:\\Users\\10594\\.FEInterview",
"eslint.codeActionsOnSave.mode": "problems",
"eslint.format.enable": true,
"interview.updateNotification": true,
"leek-fund.fundSort": -1,
"leek-fund.funds": [
"008888",
"008087",
"161725",
"006600",
"163115",
"001576",
"160225",
"519674",
"005311"
],
"leek-fund.showEarnings": 0,
// 使能每一種語言默認(rèn)格式化規(guī)則
"[html]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[css]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[less]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"javascript.validate.enable": true,
"emmet.excludeLanguages": [
"markdown"
],
/* prettier的配置 */
"prettier.printWidth": 80, // 超過最大值換行
"prettier.tabWidth": 2, // 縮進(jìn)字節(jié)數(shù)
"prettier.useTabs": false, // 句尾添加分號
"prettier.singleQuote": false, // 使用單引號代替雙引號
"prettier.proseWrap": "preserve", // (x) => {} 箭頭函數(shù)參數(shù)只有一個時是否要有小括號。avoid:省略括號
"prettier.bracketSpacing": true, // 在對象,數(shù)組括號與文字之間加空格 "{ foo: bar }"
"prettier.endOfLine": "auto", // 結(jié)尾是 \n \r \n\r auto
"prettier.eslintIntegration": false, //不讓prettier使用eslint的代碼格式進(jìn)行校驗(yàn)
"prettier.htmlWhitespaceSensitivity": "ignore",
"prettier.ignorePath": ".prettierignore", // 不使用prettier格式化的文件填寫在項(xiàng)目的.prettierignore文件中
"prettier.jsxBracketSameLine": false, // 在jsx中把'>' 是否單獨(dú)放一行
"prettier.jsxSingleQuote": false, // 在jsx中使用單引號代替雙引號
"prettier.parser": "babylon", // 格式化的解析器,默認(rèn)是babylon
"prettier.requireConfig": false, // Require a 'prettierconfig' to format prettier
"prettier.stylelintIntegration": false, //不讓prettier使用stylelint的代碼格式進(jìn)行校驗(yàn)
"prettier.trailingComma": "none", // 在對象或數(shù)組最后一個元素后面是否加逗號(在ES5中加尾逗號)
"prettier.tslintIntegration": false,
"[jsonc]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[javascriptreact]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}, // 不讓prettier使用tslint的代碼格式進(jìn)行校驗(yàn)
"vetur.experimental.templateInterpolationService": false,
"vetur.ignoreProjectWarning": true,
"prettier.arrowParens": "avoid"
}
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
在vue-cli腳手架中配置一個vue-router前端路由
Vue項(xiàng)目中使用jsonp抓取跨域數(shù)據(jù)的方法
Vue3-KeepAlive,多個頁面使用keepalive方式

