前言
为何自己要搭建封装项目框架呢?
定制化的vue3框架能够提供更加个性化、高效的开发体验,帮助团队更好地掌控整个开发过程,避免了从零开始和重复编写相同的代码框架和基础配置,大大提高开发效率。
本项目是基于vue3 + vite + TypeScript
, 对vite 快速创建的框架做的二次封装
封装的切入点主要有:
-
- 规范开发代码风格
-
- 规范git提交代码
-
- Vite的基础配置
-
- 引入状态管理库pinia和路由router
-
- 封装请求
-
- 按需引入Element Plus组件库
-
- 配置预处理器scss
github源码地址:github.com/wyx6/vue3Vi... (走过路过给个star)
搭建前准备
前置包管理工具pnpm安装(已安装可跳过)
vue3项目推荐使用pnpm来作为包管理工具。若当前没安装过pnpm,执行下面的命令安装一下。
npm install pnpm -g
具体搭建过程
创建vue3+vite框架
方式一:使用 vite 快速创建脚手架
lua
pnpm create vite
选择vue
选择TS
接下来根据提示操作即可

方式二:直接创建vue框架
你也可以pnpm create vue@latest
安装,这种方式比较方便,可以直接选择创建状态管理库,路由,代码检测规范等,不用自己后期去创建相应的文件


本文选择方式一创建vue3项目,仓库,状态管理库,eslint等等在后面配置,目的是加深记忆
规范代码风格
前置工具介绍
- husky
对git执行的一些命令,通过对应的hooks钩子触发,它在执行 Git 命令时自动运行一些自定义的脚本
- lint-staged
用于在 Git 提交之前自动运行 ESLint 的工具。可以帮助你确保代码质量,避免不必要的提交
- eslint:一个可配置的 JavaScript 检查器
可以帮助你发现并修复 JavaScript 代码中的问题
- prettier:代码格式化工具
是一个代码格式化插件,对代码的格式进行优化
配置Eslint
ESLint 是一个可配置的 JavaScript 检查器。它可以帮助你发现并修复 JavaScript 代码中的问题。问题可以是任何东西,从潜在的运行时错误,到不遵循最佳实践,再到风格问题。
首先介绍一下需要使用到的插件
pnpm add eslint
:安装ESLint本身。pnpm add eslint-plugin-vue
:安装Vue的ESLint插件,用于检查Vue项目的代码规范。pnpm add @typescript-eslint/eslint-plugin
:安装TypeScript的ESLint插件,用于检查TypeScript项目的代码规范。pnpm add eslint-plugin-prettier
:安装Prettier的ESLint插件,用于自动格式化代码。pnpm add @typescript-eslint/parser
:安装TypeScript的解析器,用于解析TypeScript代码。
安装
sql
pnpm add eslint -D
pnpm add eslint-plugin-vue -D
pnpm add @typescript-eslint/eslint-plugin -D
pnpm add eslint-plugin-prettier -D
pnpm add @typescript-eslint/parser -D
//使得 ESLint 能够正确识别和解析 ES6+ 语法的模块
npm install --save-dev @rushstack/eslint-patch
项目下新建 .eslintrc.cjs

在文件中配置 eslint
校验规则(校验规则可以根据自己需求配置):
perl
//使得 ESLint 能够正确识别和解析 ES6+ 语法的模块
require("@rushstack/eslint-patch/modern-module-resolution");
module.exports = {
root: true,
env: {
browser: true,
node: true,
es2021: true,
},
parser: 'vue-eslint-parser',
extends: [
'eslint:recommended',
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
// eslint-config-prettier 的缩写
'prettier',
],
parserOptions: {
ecmaVersion: 12,
parser: '@typescript-eslint/parser',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
// eslint-plugin-vue @typescript-eslint/eslint-plugin eslint-plugin-prettier的缩写
plugins: ['vue', '@typescript-eslint', 'prettier'],
rules: {
'@typescript-eslint/ban-ts-ignore': 'off',
'@typescript-eslint/no-unused-vars': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-var-requires': 'off',
'@typescript-eslint/no-empty-function': 'off',
'@typescript-eslint/no-use-before-define': 'off',
'@typescript-eslint/ban-ts-comment': 'off',
'@typescript-eslint/ban-types': 'off',
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'no-var': 'error',
'prettier/prettier': 'error',
// 禁止出现console
'no-console': 'warn',
// 禁用debugger
'no-debugger': 'warn',
// 禁止出现重复的 case 标签
'no-duplicate-case': 'warn',
// 禁止出现空语句块
'no-empty': 'warn',
// 禁止不必要的括号
'no-extra-parens': 'off',
// 禁止对 function 声明重新赋值
'no-func-assign': 'warn',
// 禁止在 return、throw、continue 和 break 语句之后出现不可达代码
'no-unreachable': 'warn',
// 强制所有控制语句使用一致的括号风格
curly: 'warn',
// 要求 switch 语句中有 default 分支
'default-case': 'warn',
// 强制尽可能地使用点号
'dot-notation': 'warn',
// 要求使用 === 和 !==
eqeqeq: 'warn',
// 禁止 if 语句中 return 语句之后有 else 块
'no-else-return': 'warn',
// 禁止出现空函数
'no-empty-function': 'warn',
// 禁用不必要的嵌套块
'no-lone-blocks': 'warn',
// 禁止使用多个空格
'no-multi-spaces': 'warn',
// 禁止多次声明同一变量
'no-redeclare': 'warn',
// 禁止在 return 语句中使用赋值语句
'no-return-assign': 'warn',
// 禁用不必要的 return await
'no-return-await': 'warn',
// 禁止自我赋值
'no-self-assign': 'warn',
// 禁止自身比较
'no-self-compare': 'warn',
// 禁止不必要的 catch 子句
'no-useless-catch': 'warn',
// 禁止多余的 return 语句
'no-useless-return': 'warn',
// 禁止变量声明与外层作用域的变量同名
'no-shadow': 'off',
// 允许delete变量
'no-delete-var': 'off',
// 强制数组方括号中使用一致的空格
'array-bracket-spacing': 'warn',
// 强制在代码块中使用一致的大括号风格
'brace-style': 'warn',
// 强制使用骆驼拼写法命名约定
camelcase: 'warn',
// 强制使用一致的缩进
indent: 'off',
// 强制在 JSX 属性中一致地使用双引号或单引号
// 'jsx-quotes': 'warn',
// 强制可嵌套的块的最大深度4
'max-depth': 'warn',
// 强制最大行数 300
// "max-lines": ["warn", { "max": 1200 }],
// 强制函数最大代码行数 50
// 'max-lines-per-function': ['warn', { max: 70 }],
// 强制函数块最多允许的的语句数量20
'max-statements': ['warn', 100],
// 强制回调函数最大嵌套深度
'max-nested-callbacks': ['warn', 3],
// 强制函数定义中最多允许的参数数量
'max-params': ['warn', 3],
// 强制每一行中所允许的最大语句数量
'max-statements-per-line': ['warn', { max: 1 }],
// 要求方法链中每个调用都有一个换行符
'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 3 }],
// 禁止 if 作为唯一的语句出现在 else 语句中
'no-lonely-if': 'warn',
// 禁止空格和 tab 的混合缩进
'no-mixed-spaces-and-tabs': 'warn',
// 禁止出现多行空行
'no-multiple-empty-lines': 'warn',
// 禁止出现;
semi: ['warn', 'never'],
// 强制在块之前使用一致的空格
'space-before-blocks': 'warn',
// 强制在 function的左括号之前使用一致的空格
// 'space-before-function-paren': ['warn', 'never'],
// 强制在圆括号内使用一致的空格
'space-in-parens': 'warn',
// 要求操作符周围有空格
'space-infix-ops': 'warn',
// 强制在一元操作符前后使用一致的空格
'space-unary-ops': 'warn',
// 强制在注释中 // 或 /* 使用一致的空格
// "spaced-comment": "warn",
// 强制在 switch 的冒号左右有空格
'switch-colon-spacing': 'warn',
// 强制箭头函数的箭头前后使用一致的空格
'arrow-spacing': 'warn',
'no-var': 'warn',
'prefer-const': 'warn',
'prefer-rest-params': 'warn',
'no-useless-escape': 'warn',
'no-irregular-whitespace': 'warn',
'no-prototype-builtins': 'warn',
'no-fallthrough': 'warn',
'no-extra-boolean-cast': 'warn',
'no-case-declarations': 'warn',
'no-async-promise-executor': 'warn',
},
globals: {
defineProps: 'readonly',
defineEmits: 'readonly',
defineExpose: 'readonly',
withDefaults: 'readonly',
},
}
更多配置规则请戳Eslint中文网
项目下新建 .eslintignore
配置eslint 忽略检查文件 (根据需要添加)
node_modules
dist
package.json 配置
json
{
"script": {
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
}
}
遇到的问题

报错的原因:
在组件命名的时候未按照 ESLint 的官方代码规范进行命名,根据 ESLint 官方代码风格指南,除了根组件(App.vue)以外,其他自定义组件命名要使用大驼峰命名方式或者用"-"连接单词进行命名;
解决
关闭命名规则
找到 .eslintrc.cjs 文件在 rules 后面加上这段代码就可解决
arduino
// 关闭名称校验
'vue/multi-word-component-names': 'off'
配置prettier
Prettier是一个代码格式化插件,对代码的格式进行优化,例如,它可以自动调整代码中的缩进、空格和换行等细节,确保代码风格的一致性。
安装
csharp
pnpm add prettier -D
解决 eslint 和 prettier 冲突
解决
ESLint
中的样式规范和prettier
的冲突
,以prettier
的样式规范为准
,使 ESLint 中的样式规范自动失效
安装
arduino
pnpm add eslint-config-prettier -D
在项目下新建 .prettierrc.json文件
配置 prettier
规则(可以根据自己需求配置):
json
{
"singleQuote": true, // 使用单引号
"semi": false, // 不使用分号
"bracketSpacing": true, // 在对象,数组括号与文字之间加空格
"htmlWhitespaceSensitivity": "ignore", // 对html的空格不敏感
"endOfLine": "auto", // 行结尾统一样式,保持现有的行尾
"trailingComma": "none", // 对象,数组等末尾不加逗号
"tabWidth": 2 // 水平缩进的空格数为2
}
更多prettier配置请戳prettier中文网
项目下新建 .prettierignore
配置忽略文件 (根据需要添加)
node_modules
dist
package.json 配置
json
{
"script": {
"prettier": "prettier --write ."
}
}
配置完后,可以执行以下命令看看效果:
pnpm lint
pnpm prettier


配置husky + lint-staged
介绍
husky
是一个为 git 客户端增加 hook
的工具。安装后,它会自动在仓库中的 .git/
目录下增加相应的钩子;比如 pre-commit
钩子就会在你执行 git commit
的触发。
常用hooks介绍
- pre-commit:钩子在提交信息前运行命令。
- prepare-commit-msg:钩子在启动提交信息编辑器之前,默认信息被创建之后运行。
- commit-msg:这个钩子在
git commit
和git merge
命令触发,会传递一个参数,该参数为存放当前 commit 消息的临时文件路径。 如果该钩子脚本以非零值退出,Git 将放弃提交, 因此,可以用来在提交通过前验证项目状态或提交信息。- post-commit:钩子在整个提交过程完成后运行
钩子有两种编写形式,可以在.husky文件编写相应的钩子文件也可以在package.json写,接下来我以第一种的形式编写相应钩子


lint-staged:用于在 Git 提交之前自动运行 ESLint 的工具。可以帮助你确保代码质量,避免不必要的提交
配置husky
安装
csharp
pnpm add husky -D
初始化husky配置,在根目录会有.husky配置文件,里面有初始化配置pre-commit
csharp
pnpm husky-init
在.husky下的pre-commit配置文件中添加以下信息
bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint-staged
配置完后如果git commit到仓库时就会触发pre-commit钩子,然后执行npm run lint-staged
安装成功后在 package.json
中配置:
json
"scripts": {
"prepare": "husky install",
},
配置lint-staged
安装
csharp
pnpm add lint-staged -D
安装成功后在 package.json
中配置:
json
"scripts": {
"lint-staged": "lint-staged",
},
"lint-staged": {
"*.{js,jsx,vue,ts,tsx}": [
"pnpm lint",
"pnpm prettier",
"git add"
]
}
配置完后,当提交代码到仓库时,就会自动执行lint和prettier检查代码规范了

规范git提交代码
工具介绍
commitlint:代码提交检测,检测git commit 内容是否符合定义的规范
commitizen:用于自动化提交信息的工具,帮助开发者在每次提交代码时自动生成符合规范的提交信息,使用Commitizen可以使得团队的提交信息更加统一和规范。
配置commitlint
安装
sql
pnpm add @commitlint/config-conventional @commitlint/cli -D
在.husky配置文件中,添加commit-msg钩子
sql
npx husky add .husky/commit-msg

在commit-msg配置文件中添加以下信息
bash
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run commitlint
新建commitlint.config.cjs
配置文件
在配置文件添加下面的代码:
java
module.exports = {
extends: ['@commitlint/config-conventional'],
// 校验规则
rules: {
'type-enum': [
2,
'always',
[
'feat',
'fix',
'docs',
'style',
'refactor',
'perf',
'test',
'chore',
'revert',
'build',
],
],
'type-case': [0],
'type-empty': [0],
'scope-empty': [0],
'scope-case': [0],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 72],
},
}
在package.json
中配置
在scrips中添加下面的代码
json
"scripts": {
"commitlint": "commitlint --config commitlint.config.cjs -e -V"
}

按照上面配置完成后,现在当我们填写commit
信息的时候,前面就需要带着下面的subject
arduino
'feat',//新特性、新功能
'fix',//修改bug
'docs',//文档修改
'style',//代码格式修改, 注意不是 css 修改
'refactor',//代码重构
'perf',//优化相关,比如提升性能、体验
'test',//测试用例修改
'chore',//其他修改, 比如改变构建流程、或者增加依赖库、工具等
'revert',//回滚到上一个版本
'build',//编译相关的修改,例如发布版本、对项目构建或者依赖的改动
测试
sql
git commit -m "改bug"
提交失败

sql
git commit -m "#fix 修改bug"
提交成功

注意 :当我们 commit 提交信息时,必须是 git commit -m 'fix: xxx' 符合类型的才可以,需要注意的是类型的后面需要用英文的 :,并且冒号后面是需要空一格的,这个是不能省略的
commitizen
配置commitizen后,帮助开发者在每次提交代码 时自动生成符合规范的提交信息,提示每个subjet的含义

安装
csharp
pnpm add commitizen cz-customizable -D
pnpm add commitizen -g
配置package.json
json
"scripts": {
"commit": "git-cz",
}
// 这里自定义commitizen,使用git-cz执行git commit命令
"config": {
"commitizen": {
"path": "./node_modules/cz-customizable"
},
"cz-customizable": {
"config": "./.cz-config.cjs"
}
}
在根目录创建的.cz-config.cjs文件
看了别人的版本是创建.cz-config.cjs文件,但会报错,提示我改为cjs文件,这样就不会报错了

在文件中添加以下代码
css
// 自定义commit提示内容
module.exports = {
types: [
{ value: 'feat', name: 'feat: 新功能' },
{ value: 'fix', name: 'fix: 修复' },
{ value: 'docs', name: 'docs: 文档变更' },
{ value: 'style', name: 'style: 代码格式(不影响代码运行的变动)' },
{
value: 'refactor',
name: 'refactor: 重构(既不是增加feature,也不是修复bug)'
},
{ value: 'perf', name: 'perf: 性能优化' },
{ value: 'test', name: 'test: 增加测试' },
{ value: 'chore', name: 'chore: 构建过程或辅助工具的变动' },
{ value: 'revert', name: 'revert: 回退' },
{ value: 'build', name: 'build: 打包' }
],
// override the messages, defaults are as follows
messages: {
type: '请选择提交类型:',
// scope: '请输入文件修改范围(可选):',
// used if allowCustomScopes is true
customScope: '请输入修改范围(可选):',
subject: '请简要描述提交(必填):',
body: '请输入详细描述(可选,待优化去除,跳过即可):',
// breaking: 'List any BREAKING CHANGES (optional):\n',
footer: '请输入要关闭的issue(待优化去除,跳过即可):',
confirmCommit: '确认使用以上信息提交?(y/n/e/h)'
},
allowCustomScopes: true,
// allowBreakingChanges: ['feat', 'fix'],
skipQuestions: ['body', 'footer'],
// limit subject length, commitlint默认是72
subjectLimit: 72
}
配置完成后,后面的提交,使用pnpm commit
或者git cz
来代替git commit
测试

配置文件引用别名
修改 vite.config.ts
文件配置:
javascript
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
})
修改 tsconfig.json
json
{
"compilerOptions": {
......
"baseUrl": ".",
"paths": {
"@/*":["src/*"]
}
},
}

环境变量配置
vite
提供了两种模式:具有开发服务器的开发模式
(development)和生产模式
(production)
项目根目录新建:.env.development
,添加以下代码:
ini
NODE_ENV=development
VITE_APP_URL= 'YOUR WEB URL'
VITE_APP_BASE_API = '/api'
项目根目录新建:.env.production
,添加以下代码:
ini
NODE_ENV=production
VITE_APP_URL= 'YOUR WEB URL'
VITE_APP_BASE_API = 'YOUR BASE API'
组件中使用:
arduino
console.log(import.meta.env.VITE_APP_URL)
配置 package.json
:
打包区分开发环境和生产环境
json
"build:dev": "vite build --mode development",
"build:pro": "vite build --mode production",
axios的二次封装
安装
csharp
pnpm add axios
utils
下新增 http
文件夹,在http
文件夹下新增index.ts
文件

在index.ts
文件中添加以下代码
typescript
import axios, { AxiosRequestConfig } from 'axios'
// 创建axios的一个实例
const instance = axios.create({
baseURL: String(import.meta.env.VITE_APP_BASE_API),
timeout: 5000, // 设置超时
headers: {
'Content-Type': 'application/json;charset=UTF-8;'
}
})
//显示loading,可以用于封装加载动画
export const showLoading = () => {}
//隐藏loading,可以用于封装取消加载动画
export const hideLoading = () => {
}
// 请求拦截器
instance.interceptors.request.use(
(config: any) => {
showLoading()
const token = window.localStorage.getItem('token')
//判断token是否存在
if (token) {
config.headers.token = token
}
// 若请求方式为post,则将data参数转为JSON字符串
if (config.method === 'POST') {
config.data = JSON.stringify(config.data)
}
return config
},
(error: any) =>
// 错误处理逻辑
Promise.reject(error)
)
// 响应拦截器
instance.interceptors.response.use(
(response: any) => {
hideLoading()
return response
},
(error: { response: { status: any } }) => {
// 响应错误
if (error.response && error.response.status) {
const status = error.response.status
//对status进行判断,这里可以用策略模式进行改进
switch (status) {
case 401:
message = 'TOKEN过期'
break
case 403:
message = '无权访问'
break
case 404:
message = '请求地址错误'
break
case 500:
message = '服务器出现问题'
break
default:
message = '网络出现问题'
break
}
return Promise.reject(error)
}
return Promise.reject(error)
}
)
export default async <T = any>(config: AxiosRequestConfig) => {
const res = await instance(config)
return res.data as T
}
上面是自己封装的,比较基础,可能有很多没有考虑到的可以参考这篇文章
状态管理库 pinia
pinia让Vue Store拥有Composition API方式的状态管理库,能同时支持Option API 和setup Composition API开发模式,并兼容Typescript写法
Pinia与Vuex代码分割机制
Vuex的代码分割: 打包时,vuex会把所有store合并打包,当页面用到Vuex某个仓库模块时,所有仓库模块会一起打包,其实只需要其中1个store,但其他无关的store也被打包进来,影响前端性能,当然这也可以通过一些办法解决
Pinia的代码分割: 打包时,Pinia会检查引用依赖,当页面用到哪个 store,打包就只会引入相应的模块,其它仓库模块不会一起打包。这也是pinia的优势
图片引用=》juejin.cn/post/708903...
安装
csharp
pnpm add pinia
在main.ts文件注册仓库
javascript
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia)
app.mount('#app')
创建第一个仓库
在store文件夹下创建counter.ts文件
添加以下代码:
javascript
//src/store/counter.ts
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
const increment= () => {
count.value++
}
const decrement= () => {
count.value--
}
return { count, doubleCount, increment,decrement }
})
创建pinia总入口
在
src/store
目录下创建入口index.ts
文件,其中包含一个注册函数registerStore()
,其作用是把所有的store都提前注册在appStore上,在任何组件要使用pinia时,只要import appStore进来,取对应的store实例就行。
添加以下代码
typescript
// src/store/index.ts
import { useCounterStore } from './counter';
//还可以引入其它仓库模块
export interface IAppStore {
useCounter: ReturnType<typeof useCounterStore>;
}
const appStore: IAppStore = {} as IAppStore;
/**
* 注册app状态库
*/
export const registerStore = () => {
appStore.useCounter = useCounterStore();
};
export default appStore;
composition API 模式下不支持某些内置方法,如$reset(),解决方式是重写一下reset方法。
在src/utils创建storeTools.ts文件
typescript
// src/utils/storeTools
// Pinia store基础集成方法
import type { IAppStore } from '@/store'
/**
* 重构$reset()
* @desc 因为setup模式编程不支持reset方法,这里要手动重构
* @param appStore
*/
export const initResetFun = (appStore: IAppStore) => {
// 遍历 appStore 中的所有项。
Object.values(appStore).forEach((item) => {
// 创建一个空对象 initState 用于存储初始状态。
const initState = {} as Record<string, any>
// 遍历 item 的 $state 对象的所有条目。
Object.entries(item.$state).forEach((item) => {
// 将每个状态的初始值存储到 initState 对象中。
initState[item[0]] = item[1]
})
// 为每个 store 项定义一个 reset 方法。
item.reset = () => {
// 遍历 $state 对象的所有状态。
Object.keys(item.$state).forEach((state) => {
// 将每个状态重置为其初始值。
item.$state[state] = initState[state]
})
}
})
}
src/store/index.ts
修改index.ts的代码
typescript
//src/store/index.ts
//导入counter.ts
import { useCounterStore } from "./counter";
import { initResetFun } from '@/utils/storeTools'
export interface IAppStore {
useCounter: ReturnType<typeof useCounterStore>;
// 其他store...
}
const appStore:IAppStore = {} as IAppStore;
/**
* 注册app状态库
*/
export const registerStore = () => {
appStore.useCounter = useCounterStore();
// 其他store...
//重写reset方法
initResetFun(appStore);
}
export default appStore;
统一注册
在src/main.ts
项目总线执行注册操作:
javascript
import { createApp } from 'vue';
import App from './App.vue';
import { createPinia } from 'pinia';
import { registerStore } from '@/store';
const app = createApp(App);
app.use(createPinia());
// 注册pinia状态管理库
registerStore();
app.mount('#app');
打包解耦
为了让
appStore
实例与项目解耦,在构建时要把appStore
抽取到公共chunk,在vite.config.ts
做如下配置
javascript
export default defineConfig({
...
build: {
rollupOptions: {
output: {
manualChunks(id) {
// 将pinia的全局库实例打包进vendor,避免和页面一起打包造成资源重复引入
if (id.includes(path.resolve(__dirname, '/src/store/index.ts'))) {
return 'vendor'
}
}
}
}
},
参考
路由router
安装
sql
pnpm add vue-router@4
在 src
文件下新增 router
文件夹 => index.ts
文件和routes.ts
文件
配置
在routes.ts
中配置
javascript
//对外暴露配置路由
export const routes = [
{
path: '/',
name: 'Login',
component: () => import('@/pages/user/index.vue'), // 注意这里要带上 文件后缀.vue
meta:{}
},
]
在index.ts
中配置
javascript
//通过vue-router插件实现模板路由配置
import { createRouter, createWebHashHistory } from 'vue-router'
import { routes } from './routes'
//创建路由器
const router = createRouter({
//路由模式根据需求选择
history: createWebHashHistory(),
routes: routes,
//滚动行为
scrollBehavior() {
return {
left: 0,
top: 0,
}
},
})
export default router
路由模式根据需求选择
createWebHashHistory hash 路由 使用location.hash 通过hashchange事件监听url变化
createWebHistory 普通路由 使用history 通过popstate事件监听url变化
createMemoryHistory 服务端渲染使用
修改入口文件 mian.ts
:
javascript
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app = createApp(App)
app.use(router)
app.mount('#app')
更多路由配置信息可以查看 vue-router
官方文档:
按需引入Element Plus组件库
关于组件库这部分,有很多很好的组件库,我这里用的是Element Plus组件库
实现自动按需引入
利用unplugin-vue-components
插件实现组件自动按需导入, 利用unplugin-auto-import
插件实现自动按需引入 利用unplugin-vue-components
插件实现组件自动按需导入, 利用unplugin-auto-import
插件实现自动按需引入

具体配置
arduino
pnpm add element-plus
pnpm add -D unplugin-vue-components unplugin-auto-import
在vite.config.ts中加入以下代码
javascript
// 按需自动引入导入element plus。
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'
css
export default defineConfig({
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
})
配置 css 预处理器 scss
安装
sql
pnpm add sass --dev
配置全局 scss 样式文件
在 src/assets
下新增 style
文件夹,用于存放全局样式文件
新建 main.scss
, 设置一个用于测试的颜色变量
:
css
$test-color: red;
将这个全局样式文件全局注入
到项目,配置 vite.config.js
css
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/assets/style/mian.scss";'
}
}
},
组件中使用
不需要任何引入,可以直接使用全局
scss
定义的变量
css
.main{
color: $test-color;
}
Vite 配置
文件压缩
csharp
pnpm add vite-plugin-compression -D
javascript
//Gzip文件压缩
import viteCompression from 'vite-plugin-compression'
php
export default defineConfig({
plugins: [
//开启Gzip压缩
viteCompression({
verbose: true, // 是否在控制台中输出压缩结果
disable: false,
threshold: 1024, // 如果体积大于阈值,将被压缩,单位为b,体积过小时请不要压缩,以免适得其反
algorithm: 'gzip', // 压缩算法,可选['gzip',' brotliccompress ','deflate ','deflateRaw']
ext: '.gz',
deleteOriginFile: true // 源文件压缩后是否删除(我为了看压缩后的效果,先选择了true)
})
],
})
terser 压缩和去除console+debugger
npm i terser -D
php
export default defineConfig({
build: {
minify: 'terser',
// 清除所有console和debugger
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}
})
更多vite常规配置,请看我的另外一篇文章juejin.cn/post/731546...
也可以查看vite官网,了解更多知识
参考文章:
juejin.cn/post/703674... Vite2 + Vue3 + TypeScript + Pinia 搭建一套企业级的开发脚手架【值得收藏】
juejin.cn/post/694720... # GitHook 工具 ------ husky(格式化代码)
juejin.cn/post/708903... Pinia进阶:再谈Pinia函数式(composition API)用法
后期规划:
会继续学习,在这个封装基础上进行加强,包括但不限于以下:
- Pinia数据持久化
- 自动化生成项目基本模版
- 封装脚手架
- 多入口打包
- 路由动画的封装
- viewport 适配方案
- ......
题外话
如果这篇文章对于你有一些帮助,可以给个👍和star吗,小希与你一起进步,一起努力,加油!