很多小伙伴苦于无法搭建一个规范的前端项目,导致后续开发不规范,今天给大家带来一个基于Vite6+TypeScript+Vue3+ESlint9+Prettier的搭建教程。
环境依赖版本
- node:v18.20.0
- vite:^6.0.5
- typescript:~5.6.2
- vue:^3.5.13
- eslint: ^9.14.0,
- vite-plugin-checker: ^0.8.0
- husky: ^9.1.7
- lint-staged: ^15.3.0
一、基础配置
最新版vue官方已放弃webpack作为构建工具,vue官方之前一直是以webpack,但是近期我发现vue官网已经更新了相关内容,目前开始主推vite作为脚手架构建的工具,使用官方推荐的脚手架会更加方便,脚手架可自行选择ts、pinia 、router等相关配置,不用再像之前一样从头到尾进行安装,简单又方便!!! 官方地址: cn.vuejs.org/guide/quick...
1、初始化项目
注意:此处使用node版本需要>18.3
sql
pnpm create vue@latest
运行指令后接下来就是根据需要安装所需的功能 初始化完成的结构如图所示
2、代码质量风格的统一
eslint可以保证项目的质量,prettier可以保证项目的统一格式、风格。 每个公司的开发规则各有不同,此处根据各自的需求自行配置,下方是我常用的风格配置(仅供参考)
2.1、配置prettier
- 安装
eslint-plugin-prettier: 将 Prettier 的问题以 ESLint 错误的形式呈现。 eslint-config-prettier: 关闭 ESLint 中与 Prettier 冲突的规则。
arduino
pnpm add eslint-plugin-prettier eslint-config-prettier prettier -D
- 新增.prettierrc.json文件
bash
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": true,
"tabWidth": 2,
"singleQuote": true,
"printWidth": 150,
"bracketSpacing": true,
"arrowParens": "always",
"endOfLine": "lf",
"trailingComma": "all",
"bracketSameLine": false,
"embeddedLanguageFormatting": "auto",
"useTabs": false,
"htmlWhitespaceSensitivity": "ignore"
}
2.2、配置eslint
- 规则
- "off" 或 0 - 关闭规则
- "warn" 或 1 - 打开规则作为警告(不影响退出代码)
- "error" 或 2 - 打开规则作为错误(触发时退出代码为 1)
- 安装
csharp
// eslint vue插件安装
pnpm add eslint eslint-plugin-vue -D
//eslint 识别ts语法
pnpm add @typescript-eslint/parser
//eslint ts默认规则补充
pnpm add @typescript-eslint/eslint-plugin -D
自 ESLint v9.0.0 以后,平面配置文件格式一直是默认的配置文件格式。配置文件格式已从
eslintrc
更改为flat config
。默认情况下,ESLint CLI 将搜索 eslint.config.(js | cjs | mjs) 而不是 .eslintrc.* 文件。如果未找到 eslint.config.js 文件,CLI 会将其视为错误,并且不会运行。 以下是官方给出的具体介绍。eslint.org/docs/latest... 可参考以下文章: 探索 Antfu ESLint 配置:一款极为便捷的 ESLint 设置方案 ESLint 扁平化配置使用指南
- 修改eslint.config.js配置信息
css
import pluginVue from 'eslint-plugin-vue';
import typescriptEslint from '@typescript-eslint/eslint-plugin';
import prettier from 'eslint-plugin-prettier';
import vueTsEslintConfig from '@vue/eslint-config-typescript';
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting';
import vueEslintParser from 'vue-eslint-parser';
import tsEslintParser from '@typescript-eslint/parser';
export default [ { name: 'app/files-to-lint', files: ['**/*.{ts,mts,tsx,vue,js,jsx}'],
},
{
name: 'app/files-to-ignore',
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**', 'node_modules'],
// plugins: ['vue', '@typescript-eslint', 'prettier'],
},
...pluginVue.configs['flat/essential'],
...vueTsEslintConfig(),
skipFormatting,
{
name: 'app/plugins',
plugins: {
vue: pluginVue,
'@typescript-eslint': typescriptEslint,
prettier,
},
},
{
name: 'app/parser-config-vue',
languageOptions: {
parser: vueEslintParser,
},
},
{
name: 'app/parser-config-ts',
files: ['**/*.{ts,mts,tsx}'],
languageOptions: {
parser: tsEslintParser,
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
},
},
{
name: 'app/custom-rules',
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'off' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'key-spacing': [
'error',
{
beforeColon: false,
afterColon: true,
},
],
'space-in-parens': ['error', 'never'],
'object-curly-spacing': ['error', 'always'],
'object-curly-newline': [
'error',
{
minProperties: 4,
multiline: true,
consistent: true,
},
],
'vue/object-curly-spacing': ['error', 'always'],
'max-len': 'off',
'no-multi-spaces': 'error',
'no-return-assign': 'off',
semi: ['error', 'always'],
eqeqeq: 'error',
'jsx-quotes': ['off', 'prefer-single'],
'jsx-a11y/click-events-have-key-events': 'off',
'jsx-a11y/no-noninteractive-element-interactions': 'off',
'import/prefer-default-export': 'off',
'import/extensions': 'off',
'import/no-unresolved': 'off',
'no-multiple-empty-lines': [
'error',
{
max: 2,
maxEOF: 1,
},
],
'no-param-reassign': 'off',
'vue/eqeqeq': ['error', 'always'],
'vue/html-end-tags': 'error',
'vue/no-spaces-around-equal-signs-in-attribute': 'error',
'vue/multi-word-component-names': 'off',
'vue/no-template-shadow': 'error',
'vue/require-prop-types': 'error',
'vue/require-explicit-emits': 'error',
'vue/mustache-interpolation-spacing': ['error', 'always'],
'vue/no-multi-spaces': [
'error',
{
ignoreProperties: false,
},
],
'vue/html-closing-bracket-newline': [
'error',
{
singleline: 'never',
multiline: 'always',
},
],
'vue/html-self-closing': 'off',
'vue/block-lang': 'off',
'vue/html-indent': [
'error',
2,
{
attribute: 1,
baseIndent: 1,
closeBracket: 0,
alignAttributesVertically: true,
ignores: ['VExpressionContainer'],
},
],
'vue/html-closing-bracket-spacing': [
'error',
{
startTag: 'never',
endTag: 'never',
selfClosingTag: 'always',
},
],
'vue/max-attributes-per-line': [
'error',
{
singleline: 3,
multiline: 1,
},
],
'vue/attribute-hyphenation': 'off',
'@typescript-eslint/no-shadow': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/indent': 'off',
},
},
];
2.3、配置typescript
- 修改配置tsconfig.json文件
json
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"exclude": ["src/**/__tests__/*", "node_modules/**"],
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"module": "ESNext",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "node",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"allowJs": true,
/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
/* Paths */
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
},
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}
3、配置代码检查器
vite-plugin-checker 是一个 Vite 插件,它能够在工作线程中运行 TypeScript、ESLint、vue-tsc、Stylelint 等多种静态代码检查工具
,以提高开发效率并确保代码质量。
- 安装
csharp
pnpm add vite-plugin-checker -D
- 修改vite.config.ts配置
php
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import checker from 'vite-plugin-checker';
import vueDevTools from 'vite-plugin-vue-devtools';
// https://vite.dev/config/
export default defineConfig({
base: './', // 配置服务器的检索方式
plugins: [
vue(),
vueJsx(),
vueDevTools(),
checker({
eslint: {
useFlatConfig: true,
lintCommand: 'eslint "./src/**/*.{ts,tsx,vue}"',
},
overlay: {
initialIsOpen: false,
},
typescript: true,
vueTsc: true,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
// 配置外部 ip 访问与端口
server: {
host: '0.0.0.0',
port: 9999,
},
});
4、修改路由配置信息
如果公司对应服务没有做相关的路由映射,需要将src/router/index.ts 中的createWebHistory 替换成createWebHashHistory ,如果有请忽略这一步骤~
如下所示
二、重置浏览器默认样式
normalize.css 是一个用于重置浏览器默认样式的库,使得不同浏览器之间的渲染更加一致
- 安装
csharp
pnpm add normalize.css
- src/mian.ts引入
javascript
import './assets/main.css';
import { createApp } from 'vue';
import { createPinia } from 'pinia';
import App from './App.vue';
import router from './router';
import 'normalize.css';
const app = createApp(App);
app.use(createPinia());
app.use(router);
app.mount('#app');
三、安装样式预处理器
大家可以自行安装自己熟悉的预处理器(less、sass、stylus......),此处我选择自己常用的sass
csharp
pnpm add sass -D
tip:vite内置了常用的预处理器支持无需,安装配置sass-loader 即可使用
四、ui组件库安装
市面上的ui组件库有很多,此处我只提供我最常用的两种组件库进行配置
如果是搭建后台管理系统 ,此处可看element-plus配置。 如果是搭建移动端h5,此处建议可看vant组件库
1、element-plus组件库配置(后台管理系统推荐)
官方文档配置: element-plus.org/zh-CN/guide...
- 安装
arduino
pnpm add element-plus
pnpm add -D unplugin-vue-components unplugin-auto-import
- 修改vite.config.ts配置
php
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import checker from 'vite-plugin-checker';
import vueDevTools from 'vite-plugin-vue-devtools';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
// https://vite.dev/config/
export default defineConfig({
base: './', // 设置打包路径
plugins: [
vue(),
vueJsx(),
vueDevTools(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
checker({
eslint: {
useFlatConfig: true,
lintCommand: 'eslint "./src/**/*.{ts,tsx,vue}"',
},
overlay: {
initialIsOpen: false,
},
typescript: true,
vueTsc: true,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
server: {
host: '0.0.0.0',
port: 9999,
},
});
2、vant组件库配置(移动端推荐)
官方文档配置: vant-ui.github.io/vant/#/zh-C...
- 安装
arduino
pnpm add vant
pnpm add @vant/auto-import-resolver unplugin-vue-components unplugin-auto-import -D
- 修改vite.config.ts配置
php
import { fileURLToPath, URL } from 'node:url';
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueJsx from '@vitejs/plugin-vue-jsx';
import checker from 'vite-plugin-checker';
import vueDevTools from 'vite-plugin-vue-devtools';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { VantResolver } from '@vant/auto-import-resolver';
// https://vite.dev/config/
export default defineConfig({
base: './', // 设置打包路径
plugins: [
vue(),
vueJsx(),
vueDevTools(),
AutoImport({
resolvers: [VantResolver()],
}),
Components({
resolvers: [VantResolver()],
}),
checker({
eslint: {
useFlatConfig: true,
lintCommand: 'eslint "./src/**/*.{ts,tsx,vue}"',
},
overlay: {
initialIsOpen: false,
},
typescript: true,
vueTsc: true,
}),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url)),
},
},
server: {
host: '0.0.0.0',
port: 9999,
},
});
五、二次封装axios
- 安装
csharp
pnpm add axios
新增src/service/index.ts文件
typescript
import Axios from 'axios';
import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse } from 'axios';
const axios: AxiosInstance = Axios.create({
baseURL: 'XXX',
timeout: 20000,
withCredentials: true,
});
axios.interceptors.request.use(
(config: InternalAxiosRequestConfig) => {
return config;
},
(error) => {
// pendingRequest.clear();
console.log(error);
return Promise.reject(error);
},
);
// 请求结束关闭loading
axios.interceptors.response.use(
(response: AxiosResponse) => {
// console.log(response);
return response.data || {};
},
(err) => {
console.log('err', err);
return Promise.reject(err);
},
);
export function get<T>(url: string, params?: any): Promise<T> {
return axios.get(url, { params });
}
export function post<T>(url: string, data?: any): Promise<T> {
return axios.post(url, data);
}
export default axios;
六、配置环境变量
1、创建配置文件
根目录创建三个配置文件,更多环境一样如此操作。
注: 定义的变量必须以VITE_开头
- .env.development (开发环境)
ini
VITE_APP_ENV = 'development';
VITE_APP_API_URL = /api / xxx务后地服本端 / xxx测试 / xxx生产都行;
- .env.test (测试环境)
ini
VITE_APP_ENV = 'test';
VITE_APP_API_URL = xxx测试域名;
- .env.production (生产环境)
ini
VITE_APP_ENV = 'production';
VITE_APP_API_URL = xxx生产域名;
2、使用变量
- 在代码中使用
ini
const baseUrl = import.meta.env.VITE_BASE_URL;
- 在vite.config.ts中使用环境变量
arduino
// 使用loadEnv方法加载环境变量
import { defineConfig, loadEnv } from 'vite';
//...
export default ({ mode }) => {
console.log('加载的环境变量', loadEnv(mode, process.cwd()).VITE_BASE_URL);
return defineConfig({
//...
});
};
3、修改package.json启动命令
json
"scripts": {
"dev": "vite --mode development",
"build": "vite build --mode production",
},
七、配置Husky和Lint-staged
不知道大家有没有过这种经历,在同一套项目代码里,遇到这种两模两样的代码风格。 ---------------------------------- 分割线 ---------------------------------------
当你
pnpm i
和pnpm run dev
运行项目的时候,控制台呼啦呼啦的冒出n多条的warning和error,你找同事了解情况,得知人家不仅把编辑器的报错行为关闭了,还把保存自动修复也给关闭了,还直接忽略warning提示,然后就直接提交了。此时内心一万匹草泥马飘过😒......
于是乎开始思考解决方案,有没有什么东西能让同事的报错代码提交不了,提交的时候有格式问题的代码自动修复呢?
借助
eslint --fix
的代码修复功能,可以尽最大可能的保持代码一致。当我执行eslint --fix
的修复功能时,代码中所有的格式相关问题都被自动修复了,并且提示相关代码中格式的错误。那么有没有什么方法可以让代码在提交到git之前执行自动修复的指令呢?这个时候,优秀的第三方工具库Husky
和Lint-staged
就出现了。
1、什么是Husky和Lint-staged
Husky
和 Lint-staged
是现代前端开发中常用的工具组合,用于在提交代码前进行检查和修复,确保代码质量并规范团队协作流程。
Husky: husky 是一个用于简化Git钩子(hooks)的设置的工具,允许开发者轻松地在各种Git事件触发时运行脚本。例如,在提交之前(pre-commit)、推送之前(pre-push)、或者在提交信息被写入后(commit-msg)等,它通常与lint-staged一起使用,以在提交前自动执行代码的静态检查。
- 替代 Git 原生钩子,方便管理和配置。
- 集成团队协作流程,减少低质量代码进入仓库。
Lint-staged: lint-staged 是一个在提交代码之前运行linter或其他工具的工具。使用lint-staged可以确保只有符合项目规定代码质量标准的代码被提交,减少了不必要的错误和风格问题被引入代码库的可能性。
- 仅处理需要提交的文件,节约时间。
- 可结合 ESLint、Prettier 等工具自动修复代码。
2、配置Husky
- 安装
csharp
pnpm add -D husky
- 初始化husky
csharp
npx husky init
自动生成的 .husky 目录和指令:

prepare 是 NPM 的一个特殊生命周期脚本,它会在以下场景自动执行:
- 安装依赖时(运行
npm install
)。- 发布包时(运行
npm publish
)。
- 修改 .husky/pre-commit
根目录 .husky
目录下 pre-commit
文件中的 npm test 修改为 npx lint-staged

3、配置Lint-staged
- 安装
csharp
pnpm add -D lint-staged
- 修改package.json 在 package.json 中添加以下字段
json
"scripts": {
"lint": "eslint . --fix",
"format": "prettier --write src/",
"prepare": "husky"
},
"lint-staged": {
"*.{js,ts,jsx,tsx,vue}": [
"pnpm lint",
"pnpm format"
]
}
4、提交代码后执行结果 现在,当我们提交代码时,husky会帮我们执行git
的git commit
钩子,从而触发lint-staged
,针对js,ts,jsx,tsx,vue
文件执行pnpm lint
,pnpm format
。
八、拓展实用插件(按需安装配置)
此处推荐一些我常用的工具库,大家可以参考按需安装。相关使用方法网上一搜一大堆,这边就不多余再演示了
1、dayjs 时间处理
Day.js是一个极简的JavaScript库,
可以为现代浏览器解析、验证、操作和显示日期和时间,文件大小只有2KB左右。Day.js对国际化有很大的支持。
csharp
pnpm add dayjs
2、qs
qs是一个流行的查询参数序列化和解析库。
csharp
pnpm add qs
// 如果项目配置了typescript需安装
pnpm add @types/qs -D
3、lodash实用工具库
Lodash 是一个一致性、模块化、高性能的 JavaScript 实用工具库
。它提供了一套从数组、数字、对象、字符串、日期等常见数据类型中提取值的函数,以及很多其他实用功能。Lodash 旨在通过提高抽象程度来减少代码量,提高代码的可维护性。
csharp
pnpm add lodash
// 如果项目配置了typescript需安装
pnpm add @types/lodash -D
4、big.js(涉及计算相关)
big.js 是一个用于任意精度十进制算术的小型快速 JavaScript 库。
它允许你创建、操作和比较大数字,这些数字的精度超过了 JavaScript 原生 Number 类型所能提供的范围。主要可以用于处理需要高精度计算的场景,例如金额计算、科学计算、密码学等等。
csharp
pnpm add big.js
// 如果项目配置了typescript需安装
pnpm add @types/big.js -D
5、js-cookie
是一个简单、轻量级的 JavaScript API 库,用于处理浏览器 cookies。它允许你创建、读取、删除和操作 cookie,而不需要担心浏览器的兼容性问题。
csharp
pnpm add js-cookie
// 如果项目配置了typescript需安装
pnpm add @types/js-cookie -D
6、postcss-plugin-px2rem
postcss-plugin-px2rem
是一个 PostCSS 插件,它可以自动 将 CSS 文件中的像素单位(px)转换为相对单位(rem)
,以实现响应式布局和移动端适配。这个插件特别适用于需要根据不同分辨率的移动设备进行适配的场景。
- 安装
csharp
pnpm add -D postcss-plugin-px2rem autoprefixer
- 配置vite.config.js
javascript
import autoprefixer from 'autoprefixer'
import postcssPluginPx2rem from 'postcss-plugin-px2rem';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
...
],
resolve: {
...
},
css: {
postcss: {
plugins: [
autoprefixer,
postcssPluginPx2rem({
remUnit: 108,
rootValue: 108, // 换算基数,1rem 相当于多少 px
unitPrecision: 5, // 允许 REM 单位增长到的十进制数字
propWhiteList: [], // 白名单,指定哪些属性不转换为 rem
propBlackList: [], // 黑名单,指定哪些属性需要转换为 rem
exclude: /(node_module)/, // 排除的文件夹或文件
selectorBlackList: [], // 要忽略并保留为 px 的选择器
mediaQuery: false, // 允许在媒体查询中转换 px
minPixelValue: 3 // 设置要替换的最小像素值
}),
],
},
},
});
7、@vitejs/plugin-legacy(兼容旧浏览器,移动端项目重点推荐!!!)
公司合作的一些客户自带的客户端浏览器版本超级无敌老旧(此处内涵某些银行😒),项目发布后由于浏览器过于老旧无法处理新版本的语法产生白屏问题,使用这个插件可以生成兼容旧版浏览器的构建文件解决这个问题(救我狗命!!!)。
@vitejs/plugin-legacy 是一个 Vite 插件,用于为 Vite 项目提供对旧版浏览器的支持。
这个插件可以根据你在项目配置中指定的目标浏览器列表(通过 browserslist 字段),自动生成兼容旧版浏览器的构建文件。这些构建文件将包含经过转换和降级处理的代码,以 确保在不支持最新 JavaScript 特性的浏览器中正常运行。
使用 @vitejs/plugin-legacy 插件后,当用户访问你的网站时,Vite 将根据用户的浏览器版本动态加载适合其浏览器的构建文件。
- 安装
sql
pnpm add -D @vitejs/plugin-legacy
- 配置vite.config.js
php
import legacy from '@vitejs/plugin-legacy';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [
vue(),
legacy({
targets: ['ie >= 11', 'chrome <= 60'], // 需要兼容的目标列表,可以设置多个
additionalLegacyPolyfills: ['regenerator-runtime/runtime'],
renderLegacyChunks: true,
polyfills: [
'es.symbol',
'es.array.filter',
'es.promise',
'es.promise.finally',
'es/map',
'es/set',
'es.array.for-each',
'es.object.define-properties',
'es.object.define-property',
'es.object.get-own-property-descriptor',
'es.object.get-own-property-descriptors',
'es.object.keys',
'es.object.to-string',
'web.dom-collections.for-each',
'esnext.global-this',
'esnext.string.match-all',
],
}),
],
resolve: {
...
},
});
- 配置package.json 在 package.json 文件中的 "browserslist" 字段中指定需要支持的目标浏览器。例如,如果你想要支持最近两个版本的 Chrome 和 Firefox 浏览器,可以将该字段修改为:
json
"browserslist": [
"last 2 Chrome versions",
"last 2 Firefox versions"
]
8、vconsole(移动端调试)
vConsole模拟了浏览器的 Console、Network、Storage 等核心功能,使得开发者可以在 移动端网页中直接进行调试
。vConsole 提供了丰富的功能,包括查看 console 日志、监控网络请求、检查页面 DOM 结构以及管理 Cookies 和 localStorage 等,极大地便利了开发者的调试工作。
- 安装
csharp
pnpm add vconsole
- 使用
ini
import VConsole from 'vconsole';
const isPc = () => {
const userAgentInfo = navigator.userAgent;
const Agents = ['Android', 'iPhone', 'SymbianOS', 'Windows Phone', 'iPad', 'iPod'];
let flag = true;
for (let v = 0; v < Agents.length; v++) {
if (userAgentInfo.indexOf(Agents[v]) > 0) {
flag = false;
break;
}
}
return flag;
};
if (import.meta.env.VITE_APP_ENV !== 'production' && !isPc) {
new VConsole();
}
下面是我已搭建好的项目初始化框架,各位有需要的自取: 移动端: gitee.com/nanwu-aga/v... 后台管理系统: gitee.com/nanwu-aga/v...