十分钟初始化 Vite + Vue + TypeScript 项目(Eslint Flat/prettier)

573 阅读5分钟

十分钟创建 Vite + Vue + TypeScript 项目(Eslint Flat/prettier)

主要使用最新版本ESLint Flat Config + prettier 来检测格式化代码

项目相关依赖版本

  • vue: ^3.4.21
  • vite: ^5.2.0
  • typescript: ^5.2.2
  • eslint: ^9.0.0

1. 初始化项目

1.1 node版本要求

node: v18.17.1

1.2. 创建项目

使用 PNPM:

# 创建项目
pnpm create vite vue3-element-template --template vue-ts
# 安装依赖
pnpm install
# 启动项目
cd my-vue-app
pnpm run dev
# 构建项目
pnpm run build

2. 配置 tsconfig.json

修改 tsconfig.json, 删除tsconfig.node.json

{
	"compilerOptions": {
		"target": "ES2020", // 将代码编译为ES2020版本的 JS
		"useDefineForClassFields": true, // 将 class 声明中的字段语义从 [[Set]] 变更到 [[Define]]
		"module": "ES2020", // 使用 ES Module 格式打包编译后的文件
		"lib": ["ES2020", "DOM", "DOM.Iterable"], // 使用 Node 的模块解析策略
		"skipLibCheck": true, // 跳过对 .d.ts 文件的类型检查

		/* Bundler mode */
		"moduleResolution": "bundler", // 使用 Node 的模块解析策略 , 一般配合上面的module
		"allowImportingTsExtensions": true, // 允许 TypeScript 文件使用特定于 TypeScript 的扩展名(如 .ts、.mts 或 .tsx)相互导入。
		"resolveJsonModule": true, // 允许引入 JSON 文件
		"isolatedModules": true, // 要求所有文件都是 ES Module 模块。
		"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
		"jsx": "preserve", // 保留原始的 JSX 代码,不进行编译

		/* Linting */
		"strict": true, // 开启所有严格的类型检查
		"noUnusedLocals": true, //报告未使用的局部变量的错误
		"noUnusedParameters": true, //报告函数中未使用参数的错误
		"noFallthroughCasesInSwitch": true, //确保switch语句中的任何非空情况都包含
		"allowJs": true, //允许使用js
		"noImplicitAny": false /* 不允许隐式的any类型 */,
		"forceConsistentCasingInFileNames": true /* 是否强制代码中使用的模块文件名必须和文件系统中的文件名保持大小写一致 */,
		"baseUrl": ".", //查询的基础路径
		"paths": { "@/*": ["src/*"], "#/*": ["types/*"] }, //路径映射,配合别名使用
		"types": [
			// 编译过程中被包含进来的类型声明文件
			"node",
			"vite/client"
		]
	}
}

tsconfig.json 会有Error提示:找不到“node”的类型定义文件。

3. 配置路径别名

3.1 安装Node.js API的ts类型

pnpm add @types/node -D

对应tsconfig.json文件:

  "types": [
    "node",
    "vite/client"
  ]

其中 node 表示 “node”的类型声明文件 @types/node 会被加载进来。

3.2 修改vite.config.ts

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path' // 引入path模块

export default defineConfig({
	plugins: [vue()],
	resolve: {
		// 配置别名
		alias: {
			'@': path.resolve('./src'),
			'#': path.resolve('./types'),
		},
	},
})

对应tsconfig.json文件:

"paths": {
  "@/*": ["src/*"],
  "#/*": ["types/*"]
}

如果此时 vite.config.ts 文件的 plugins: [vue()] 有报错,重启VScode可解决。

4. 配置 ESLint 和 prettier

4.1 开发工具配置

本文使用代码编辑器为 VSCode,需安装好了相应的插件 Vue - Official(v2.0.10),ESLint 以及 Prettier。

4.2 ESLint 的初始化

pnpm create @eslint/config
√ How would you like to use ESLint? · problems
√ What type of modules does your project use? · esm
√ Which framework does your project use? · vue
√ Does your project use TypeScript? · typescript
√ Where does your code run? · browser
The config that you've selected requires the following dependencies:

eslint, globals, @eslint/js, typescript-eslint, eslint-plugin-vue
√ Would you like to install them now? · No / Yes
√ Which package manager do you want to use? · pnpm

这时候项目根路径下就会生成一份 ESLint 的配置文件 eslint.config.js

import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginVue from 'eslint-plugin-vue'

export default [
	{ languageOptions: { globals: globals.browser } },
	pluginJs.configs.recommended,
	...tseslint.configs.recommended,
	...pluginVue.configs['flat/essential'],
]

此时,如果更改VSCode 的配置文件 settings.json

  • 添加如下内容可使用 ESLint 在保存时格式化代码:
	"eslint.experimental.useFlatConfig": true //, 启用 eslint 配置扁平化
	"editor.formatOnSave": true, // 保存时进行格式化
	"editor.defaultFormatter": "dbaeumer.vscode-eslint", // 设置 ESLint 为默认格式化工具
	"eslint.format.enable": true, // 启用 ESLint 格式化下面添加入 validated 的文件
	"eslint.validate": [
		"javascript",
		"javascriptreact",
		"typescript",
		"typescriptreact",
		"vue",
		"html",
		"markdown",
		"json",
		"jsonc",
		"yaml"
	],

4.3 安装 prettier

pnpm install -D eslint-plugin-prettier	eslint-config-prettier

修改 eslint.config.js 添加 prettier 配置

import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginVue from 'eslint-plugin-vue'
import pluginPrettierRecommendedConfigs from 'eslint-plugin-prettier/recommended'

export default [
	// eslint 默认推荐规则
	pluginJs.configs.recommended,
	// ts 默认推荐规则
	...tseslint.configs.recommended,
	// vue3 基础推荐规则
	...pluginVue.configs['flat/recommended'],
	// prettier 默认推荐规则
	pluginPrettierRecommendedConfigs,
	{
		languageOptions: { globals: globals.browser },
	},
]

根目录下新建 prettier.config.js:

export default {
	tabWidth: 2,
	useTabs: true,
	semi: false,
	singleQuote: true,
	printWidth: 120,
	arrowParens: 'always',
	bracketSpacing: true,
	endOfLine: 'auto',
	vueIndentScriptAndStyle: true,
}

这个时候保存时,就会使 eslint 按照 prettier 配置的规则进行格式化,如果有其他错误,重启vscode可解决。

4.4 配置 vue 检测

如果此时打开 components/HelloWorld.vue 文件,会发现此行报错:

defineProps<{ msg: string }>() // Parsing error: Unexpected token )eslint

解决办法: 配置 vue-eslint-parser,修改eslint.config.js

import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import pluginVue from 'eslint-plugin-vue'
import pluginPrettierRecommendedConfigs from 'eslint-plugin-prettier/recommended'
import parserVue from 'vue-eslint-parser'

export default [
	// eslint 默认推荐规则
	pluginJs.configs.recommended,
	// ts 默认推荐规则
	...tseslint.configs.recommended,
	// vue3 基础推荐规则
	...pluginVue.configs['flat/recommended'],
	// prettier 默认推荐规则
	pluginPrettierRecommendedConfigs,
	{
		languageOptions: {
			globals: {
				...globals.browser,
				...globals.es2020,
				...globals.node,
			},
			ecmaVersion: 2020,
			parser: parserVue,
			parserOptions: {
				parser: tseslint.parser,
			},
		},
	},
	// 可添加一些自定义规则
	rules: {
		'no-unused-vars': ['off', { caughtErrors: 'none' }], // 未使用变量
		'@typescript-eslint/no-unused-vars': ['off', { caughtErrors: 'none' }], // 未使用变量
		'vue/no-unused-vars': ['off', { caughtErrors: 'none' }], // 未使用变量
		'vue/v-on-event-hyphenation': 'off', // html元素上事件函数名使用短横线连接
		'vue/multi-word-component-names': ['off'], // 组件名应该多个词组成
		'vue/require-default-prop': 'warn', // props 参数 应该有默认值
		'vue/no-v-html': 'off', // 不推荐使用 v-html
		'vue/no-mutating-props': 'warn', // props 参数应该不能直接修改
	},
]

至此,保存文件时会按照eslint 和 prettier 的规则进行格式化。

4.5 添加插件 vite-plugin-eslint

安装

pnpm install -D vite-plugin-eslint

修改 vite.config

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
import eslintPlugin from 'vite-plugin-eslint'

// https://vitejs.dev/config/
export default defineConfig({
	plugins: [vue(), eslintPlugin()],
	resolve: {
		// 配置别名
		alias: {
			'@': path.resolve('./src'),
			'#': path.resolve('./types'),
		},
	},
})

添加 vite-plugin-eslint 类型声明

/// <reference types="vite/client" />

/**
 * 由于 vite-plugin-eslint 库有点落后,导致 vite 高版本不能正确的识别 cjs 模块
 * 所以这里手动定义
 */
declare module 'vite-plugin-eslint' {
	import { Plugin } from 'vite'
	import { ESLint } from 'eslint'

	/** Plugin options, extending from ESlint options */
	interface Options extends ESLint.Options {
		/** Path to ESLint instance that will be used for linting */
		eslintPath?: string
		/** Check all matching files on project startup */
		lintOnStart?: boolean
		/** A single file, or array of files, to include when linting */
		include?: string | string[]
		/** A single file, or array of files, to exclude when linting */
		exclude?: string | string[]
		/** Custom error formatter or the name of a built-in formatter */
		formatter?: string | ESLint.Formatter['format']
		/** The waring found will be printed */
		emitWarning?: boolean
		/** The errors found will be printed */
		emitError?: boolean
		/** Will cause the module build to fail if there are any warnings, based on emitWarning */
		failOnWarning?: boolean
		/** Will cause the module build to fail if there are any errors, based on emitError */
		failOnError?: boolean
	}

	const content: (rawOptions?: Options) => Plugin
	export default content
}