记一次vue@cli创建项目prettier失效

最近在学vue3,使用vue@cli创建项目的时候突然发现prettier失效。各种上网查资料,修改vscode配置操作都不行。后来开两个项目,一个使用vue@cli一个手动创建,发现使用vue@cli创建的项目就是存在失效的问题,排查了很久才发现是官方配置问题,可以查看我提的issues

vue@cli创建项目

Vue3支持用vue@cli创建项目,但前提是vue@cli版本要在5.x以上,4.x的版本升级一下就可以。

创建项目

1
npm init vue@last

这一指令将会安装并执行 create-vue,它是 Vue 官方的项目脚手架工具。你将会看到一些诸如 TypeScript 和测试支持之类的可选功能提示:

1
2
3
4
5
6
7
8
9
✔ Project name: … <your-project-name> // 项目名称
✔ Add TypeScript? … No / Yes // 添加ts
✔ Add JSX Support? … No / Yes // 添加jsx支持
✔ Add Vue Router for Single Page Application development? … No / Yes // 添加 router
✔ Add Pinia for state management? … No / Yes // 添加 Pinia
✔ Add Vitest for Unit testing? … No / Yes // 添加 vitest
✔ Add an End-to-End Testing Solution? … No / Cypress / Playwright // 添加端到端测试
✔ Add ESLint for code quality? … No / Yes // 添加Eslit
✔ Add Prettier for code formatting? … No / Yes // 添加Prettier

按照自己的需求选择完之后

1
2
3
cd vue-project2
npm install
npm run dev

我当时是选择了eslintprettier配置,最后会生成对应的配置文件,这里就只关心一下.eslintrc.cjs文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
}
}

问题

由于是vue3项目,我直接把vetur插件禁用掉,使用volar插件

image.png

对应的eslintprettier插件都有安装,VsCode自动保存修复也打开。

1
2
3
4
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.fixAll.eslint": true
}

然后修改一下代码,测试一下prettier功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue';






</script>

<template>
<header>
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />

<div class="wrapper">
<HelloWorld msg="You did it!" />


<nav>
<RouterLink to="/">Home</RouterLink>
<RouterLink to="/about">About</RouterLink>
</nav>

</div>
</header>

<RouterView />
</template>


很容易发现代码会有几个错误在里面,相同的代码我放在一个prettier功能完好的项目里面就发现错误。

image.png

排查

为什么会这样,我修改了vue@cli创建项目的好多配置,主要排查对象放在eslintvscode编辑器上,甚至重新安装相关依赖,不使用脚手架提供的,还是没有发现问题。

吃完饭后无意中发现eslint的一个配置后面加了skip-formatting,为啥要跳过配置?然后把这个选项移除,惊奇的发现可以用了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
- '@vue/eslint-config-prettier/skip-formatting'
+ '@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: 'latest'
},
}


然后查看这个包文件,skip-formatting到底是什么意思?它在node_modules/@vue/eslint-config-prettier/skip-formatting.js

1
2
3
4
5
6
7
module.exports = {
extends: [require.resolve("./index.js")],
rules: {
"prettier/prettier": "off",
},
};

有一个很关键的代码"prettier/prettier": "off",它把prettier关闭了,为什么要关闭这个配置呢,百思不得其解,然后去查阅Vue仓库下的create-vue相关代码,发现官方用的是另外一个eslint配置仓库create-eslint-config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import * as fs from 'node:fs'
import * as path from 'node:path'

import type { Linter } from 'eslint'

import createESLintConfig from '@vue/create-eslint-config' // create-eslint-config项目
...

const { pkg, files } = createESLintConfig({
vueVersion: '3.x',
// we currently don't support other style guides
styleGuide: 'default',
hasTypeScript: needsTypeScript,
needsPrettier, // needsPrettier参数从脚手架配置命令行参数里面获取

additionalConfig,
additionalDependencies
})
...

查看一下create-eslint-config项目里面的相关代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

// This is also used in `create-vue`
export default function createConfig ({
vueVersion = '3.x', // '2.x' | '3.x' (TODO: 2.7 / vue-demi)

styleGuide = 'default', // default | airbnb | typescript
hasTypeScript = false, // js | ts
needsPrettier = false, // true | false

additionalConfig = {}, // e.g. Cypress, createAliasSetting for Airbnb, etc.
additionalDependencies = {} // e.g. eslint-plugin-cypress
}) {
// This is the pkg object to extend
const pkg = { devDependencies: {} }
const addDependency = (name) => {
pkg.devDependencies[name] = versionMap[name]
}


deepMerge(pkg.devDependencies, additionalDependencies)
deepMerge(eslintConfig, additionalConfig)

if (needsPrettier) {
addDependency('prettier')
addDependency('@vue/eslint-config-prettier')
eslintConfig.extends.push('@vue/eslint-config-prettier/skip-formatting') // 这里往eslint的extend属性里面添加了配置
}

const files = {
'.eslintrc.cjs': ''
}
...

就是这行eslintConfig.extends.push('@vue/eslint-config-prettier/skip-formatting')它添加的是配置里面对应的skip-formatting配置,也就是关掉prettier那个。

这个commit里面,作者重构了这个配置,目的是为了使用prettier时,不使用eslint格式化。

但我们日常开发中,通常都是prettiereslint都是一起使用的,如果要想单独使用某一个的话,skip-formatting参数应该是根据用户是否在prettiereslint二选一的时候决定,也不知道这样做是为了什么。

解决

最后的解决办法就很简单

  1. 不使用skip-formatting这个配置文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
root: true,
'extends': [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
- '@vue/eslint-config-prettier/skip-formatting'
+ '@vue/eslint-config-prettier'
],
parserOptions: {
ecmaVersion: 'latest'
},
}


  1. 这个文件不是吧prettier给关掉了吗,我们打开就行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')

module.exports = {
root: true,
extends: [
'plugin:vue/vue3-essential',
'eslint:recommended',
'@vue/eslint-config-typescript',
'@vue/eslint-config-prettier/skip-formatting'
],
parserOptions: {
ecmaVersion: 'latest'
},
+ rules: {
+ 'prettier/prettier': 'error'
+ }
}