大家好,我是苏先生,一名热爱钻研、乐于分享的前端工程师,跟大家分享一句我很喜欢的话:人活着,其实就是一种心态,你若觉得快乐,幸福便无处不在
github与好文
你可以学到什么?
- 如何使用 vite 搭建项目
- 如何集成与使用 web-localstorage-plus
- 如何集成与使用 vue-router4
- 如何集成与使用 pinia
- 如何集成与使用 element-plus
- 如何封装axios
- 如何借力 eslint 和 prettier 保证代码质量
- 如何借力 commitlint 规范git提交信息
源码地址
1.创建项目
按提示选择:
1.运行vite
yarn create vite
2.输入自定义的项目名称
name: › your-project-name
3.选择你想要的技术框架
? Select a framework: › - Use arrow-keys. Return to submit.
❯ Vanilla
Vue
React
Preact
Lit
Svelte
Others
4.选择ts模板
? Select a variant: › - Use arrow-keys. Return to submit.
❯ TypeScript
JavaScript
Customize with create-vue ↗
Nuxt ↗
5.按提示安装并运行项目
Done. Now run:
cd vite-project
yarn
yarn dev
一键初始化
除了上述问答形式创建外,vite官方也提供了快捷语法:通过命令行参数创建
# npm 6.x
npm create vite@latest my-vue-app --template vue
# npm 7+, extra double-dash is needed:
npm create vite@latest my-vue-app -- --template vue
# yarn
yarn create vite my-vue-app --template vue
# pnpm
pnpm create vite my-vue-app --template vue
2.优化项目结构
修剪vite默认生成的项目结构
1.保留public文件夹,删除vite.svg文件,同时删除index.html
中对该文件的引入
2.删除HelloWorld.vue
文件,同时从App.vue
中删除引入
3.删除App.vue
中的默认代码,只保留默认的三个根元素
我个人习惯将template
放到最前边
<template>
</template>
<script setup lang="ts">
</script>
<style scoped>
</style>
4.清空assets文件夹
定制化目录
1.创建store文件夹
放置关于pinia的数据状态
2.创建directive文件夹
放置我们的自定义指令,如:v-auth
3.创建utils文件夹
项目中的公共方法或常量
4.创建styles文件夹
管理公共css样式文件,如:reset.css
5.创建http文件夹
处理axios的封装和调用
6.创建router文件夹
管理
vue-router
的路由模块
7.创建pages文件夹
管理业务代码
3.配置vite.config.ts
配置别名
项目中,不同模块之间往往需要互相引入,使用别名能够帮助我们省去一级一级查找的繁琐
...
import { resolve } from 'node:path'
export default defineConfig({
plugins: [vue()],
resolve:{
alias:{
'@':resolve(__dirname,'src')
}
}
})
此时,node:path
和__dirname
会报错,我们还需要安装下对应的ts类型包
yarn add @types/node --D
设置代理
我们本地开发完跟后端联调阶段,经常会遇到跨域的问题,需要我们暂时的在前端进行下处理
export default defineConfig({
...
server: {
proxy: {
"/api": {
target: "http url",
changeOrigin: true,
rewrite: (path: string) => path.replace(/^\/api/, ""),
},
},
},
});
其中"/api"
是我们要代理的接口标识,target是我们实际要访问的接口地址
设置自动导入
每次都手动导入依赖项是一件很麻烦的事情,幸运的是,我们可以借助第三方库来帮我们实现,它内置了常见的库,比如vue
1.安装
yarn add unplugin-auto-import -D
2.在vite.config.ts中导入并作为plugin使用
...
import AutoImport from 'unplugin-auto-import/vite'
export default defineConfig({
plugins: [...,AutoImport()],
...
});
4.集成web-storage-plus
对于需要使用到持久缓存的地方,localstorage
是优选的方案,不过原生接口比较难用,而该npm包对其进行了二次封装,使其支持了命名空间、过期时间、监听变化、批量操作等特性,且其为我们提供了发布订阅模式来弥补vue3中对bus的缺失,文档看这里:传送门
1.安装
yarn add web-localstorage-plus
2.在main.ts中引入并初始化根存储
...
import createStorage from 'web-localstorage-plus'
createStorage({
rootName:'spp-storage'
})
...
3.在.vue文件中引入并使用
<script lang="ts" setup>
import { useStorage } from 'web-localstorage-plus'
const storage = useStorage()
storage.setItem('user',{
name:'spp',
age:28
})
</script>
5.集成pinia
对于非持久化数据,我们选择使用pinia来进行管理,它帮我们托管了全局状态并且提供了响应式能力,文档看这里:传送门
1.安装pinia
yarn add pinia
2.在store文件夹下新建index.ts文件作为pinia的根仓库文件
import { createPinia } from "pinia";
const pinia = createPinia()
export default pinia
3.在main.ts中导入并将 pinia 作为 plugin 注册给 vue
import { createApp } from 'vue'
...
import pinia from '@/store'
...
const app = createApp(App)
app.use(pinia)
...
4.在store文件夹下新建xxx.ts文件作为子存储模块
import { defineStore } from 'pinia'
export default defineStore('spp', {
state() {
return {
spp:''
}
},
actions:{
updateSpp(spp:string){
this.spp = spp
}
}
})
5.在.vue文件中使用或修改pinia的状态
<script lang="ts" setup>
...
import useLoginStore from '@/store/login.ts'
// 获取状态
const store = useLoginStore()
// 修改状态
store.updateSpp('spp')
...
</script>
6.集成vue-router4
作为spa项目,路由是我们进行页面切换的必备工具,文档看这里:传送门
1.使用yarn安装
yarn add vue-router@4
2.在router文件夹下新建index.ts文件作为根路由
import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
const routes: Array<RouteRecordRaw> = [
{
path: "/login",
name: "Login",
component: () => import("@/pages/login/index.vue")
},
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;
3.在main.ts中导入并作为plugin注册给vue
import { createApp } from 'vue'
import router from '@/router';
...
const app = createApp(App)
app.use(router)
...
4.将根App.vue作为路由出口
<template>
<RouterView/>
</template>
7.集成less
1.安装
yarn add less -D
2.使用
<style lang="less" scoped>
.root-app {
.spp {
// 自定义样式
}
}
</style>
8.集成element-plus
element-plus是vue侧比较流行的pc端ui框架之一,文档看这里:传送门
1.安装
yarn add element-plus
2.按需自动导入
- 安装依赖包
yarn add unplugin-vue-components unplugin-auto-import -D
- 修改vite.config.ts
import { defineConfig } from "vite";
...
import AutoImport from "unplugin-auto-import/vite";
import Components from "unplugin-vue-components/vite";
import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
export default defineConfig({
plugins: [
...
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
...
});
3.在.vue文件夹下直接使用即可
9.集成axios(仅提供封装思路,可选)
axios是目前最流行的前端发起ajax请求的库,其基于promise实现,同时支持在浏览器和nodejs中使用,文档看这里:传送门
1.安装
yarn add axios
2.在http文件夹下新建index.ts文件
该文件对我们业务中的请求进行基类封装
import request from "./request";
import getPrefix from "./urlPrefix";
import { TgroupType } from '@/utils/types'
import { warn } from '@/utils/function'
class Http{
protected prefix:string=getPrefix(undefined);
protected config:any={}
constructor(group?:TgroupType){
this.prefix = getPrefix(group)
}
private combineUrl(url:string){
return this.prefix + url
}
setExtraConfig(config:any){
this.config = config
}
get<T>(url: string, arg?: T,message?:string){
return new Promise((resolve, reject) => {
request
.get(this.combineUrl(url), {
params: arg,
...this.config
})
.then((res:any)=>{
// 根据与后端的约定format数据,并做resolve或reject
...
})
.catch(reject)
.finally(()=>{
this.config={}
})
});
}
post<T>(url: string, message?: string | T, arg?: T) {
const isFull = arguments.length === 3
if (!isFull) {
arg = message as T;
}
const errMessage = '你的自定义错误'
return new Promise((resolve, reject) => {
request
.post(this.combineUrl(url), arg,{
...this.config,
})
.then((res: any) => {
// 根据与后端的约定format数据,并做resolve或reject
...
})
.catch(()=>{
warn(errMessage)
reject(errMessage);
})
.finally(()=>{
this.config={}
})
});
}
}
export const http = new Http()
export const httpRequest = Http
export const usePrefix = getPrefix
3.在http文件夹下新建request.ts文件
该文件用于配置axios,并通过拦截器对接口状态进行检测和错误的统一处理
import axios from "axios";
axios.defaults.timeout = 10000000;
axios.defaults.withCredentials = true;
axios.interceptors.request.use(
(config) => {
config.headers = Object.assign(config.headers,{
// 配置header
})
return config;
},
(error) => {
// 处理错误
return Promise.reject(error);
}
);
axios.interceptors.response.use(
(response) => {
// 统一拦截验证
return response;
},
(error) => {
// 处理错误
return Promise.reject(error);
}
);
export default axios;
4.在http文件夹下新建urlPrefix.ts文件
该文件用于统一管理不同域名对应的不同环境下的url
import { IurlConfig,TgroupType} from '@/utils/types'
const mode = import.meta.env.MODE;
const urlConfig:IurlConfig = {
// 前缀-{dev:'',pro:''}
}
const getPrefix = (key:TgroupType)=>{
if(key === undefined){
key = ''
urlConfig[key][mode]
}
return urlConfig[key][mode]
}
export default getPrefix;
5.在业务中引入并使用
import { http } from "@/http";
http
.post<传递与当前接口参数匹配的类型>(url, "添加成功", params)
.then(() => {
// 请求成功的业务处理
});
10.常用工具推荐
- 时间处理:moment
- 万能工具库:lodash-es
11.代码质量与提交规范
eslint
因为eslint无法识别.vue文件,因此我们还需要一个定制化插件:eslint-plugin-vue
,文档看这里:传送门
1.安装依赖
yarn add eslint eslint-plugin-vue -D
2.创建.eslintignore忽略文件
node_modules
dist
yarn.lock
index.html
3.添加ts支持
eslint-plugin-vue
只针对.vue文件或者.js文件中的vue写法,我们还需要对ts进行兼容
文档传送门:@typescript-eslint/parser、@typescript-eslint/eslint-plugin
yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin -D
4.在根目录下创建.eslintrc.cjs配置文件
module.exports = {
parser: 'vue-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser',
ecmaVersion: 2020,
sourceType: 'module',
ecmaFeatures: {
jsx: true
}
},
extends: [
'plugin:vue/vue3-recommended',
'plugin:@typescript-eslint/recommended',
],
rules: {
"no-console": "error",
}
};
5.按环境区分
实际项目中,我们一般会根据不同的开发环境来区分规则,比如console应在开发阶段可用,生产时禁用
1-安装依赖
文档看这里:cross-env、@rollup/plugin-eslint
yarn add cross-env @rollup/plugin-eslint -D
2-修改命令行
在打包阶段配置环境变量,我这里以production为例子
"scripts": {
...
"build": "cross-env NODE_ENV=production && vue-tsc --noEmit && vite build"
},
3-将rollup插件加入vite的plugin
...
import eslint from '@rollup/plugin-eslint';
export default defineConfig({
plugins: [
...
eslint({
include:['src/**']
})
],
...
});
4-修改.eslintrc.cjs
cross-env
会将定义的环境变量暴露在env上,我们获取并做三元判断即可
const mode = process.env.NODE_ENV
module.exports = {
...
rules: {
"no-console": mode === 'production' ? "error" : "off",
...
}
};
prettier
相关文档看这里:prettier、eslint-config-prettier、eslint-plugin-prettier
1.安装依赖
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
2.创建配置文件:.prettierrc.js
以我司的某个项目为例
module.exports = {
// 一行最多 150 个字符
printWidth: 150,
// 使用 4 个空格缩进
tabWidth: 4,
// 不使用 tab 缩进,而使用空格
useTabs: false,
// 行尾需要有分号
semi: true,
// 使用单引号代替双引号
singleQuote: true,
// 末尾使用逗号
trailingComma: 'es5',
// 箭头函数,只有一个参数的时候,也需要括号
arrowParens: 'always',
}
3.修改 .eslintrc.js
配置
强制当和eslint冲突时,以prettier为准
module.exports = {
...
extends: [
...
'prettier',
'plugin:prettier/recommended'
],
...
};
提交规范
我们需要在提交代码前对代码质量、代码格式和commit信息进行约束,为此,我们需要先注册commit提交前钩子
1-安装husky
文档看这里:传送门
yarn add husky -D
2-初始化husky
在package.json文件夹下新增prepare
脚本,并立即运行一次
"scripts": {
...
"prepare": "husky install"
},
3-注册hook
我们使用pre-commit
钩子来拦截提交行为,
npx husky add .husky/pre-commit "npm run check"
git add .husky/pre-commit
此时,当git commit
发生时,将会调用check
脚本,但这默认事针对全部文件的,因此我们需要借助另一个npm包帮我们把当前更改的文件提取出来单独校验
1-安装lint-staged
文档看这里:传送门
yarn add lint-staged -D
2-修改package.json配置
"lint-staged": {
"*.{js,ts,vue}": [
"npm run eslint",
"prettier --parser=typescript --write"
]
}
3-与husky关联
将lint-staged作为check的指向脚本
"scripts": {
...
"check": "lint-staged"
},
最后我们来对commit提交格式进行约束,这可以通过commitlint来帮我们完成,文档看这里:传送门
1-安装
yarn add @commitlint/config-conventional @commitlint/cli -D
2-将其校验位置放在check
脚本执行前
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'
3-创建配置文件commitlint.config.cjs
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
[
'feature', // 迭代功能
'conf', // 修改构建配置
'fixbug', // 修复bug
'refactor', // 代码重构
'optimize', // 代码优化
'style', // 仅修改样式文件
'docs', // 文档补充说明
],
],
'header-max-length': [0, 'always', 72], //限制最长72
},
};
4-测试使用
迭代更新
2023-6-28
有jy反馈使用less会报错(将eslint插件替换成了@nabla/vite-plugin-eslint
),已修复,需要的jy重新从仓库clone哦🥰
2023-7-28
增加pinia
持久化存储
- 安装依赖
yarn add @web-localstorage-plus/pinia
- 在
main.ts
中设置持久化
import createStorage from 'web-localstorage-plus';
import setPiniaPersist from '@web-localstorage-plus/pinia';
// 设置根存储库
createStorage({
rootName: 'spp-storage',
});
// 将pinia中的数据持久化到本地
setPiniaPersist(pinia);
- 在
vite.config.ts
中引入热更新插件
import { getPlugin } from '@web-localstorage-plus/pinia';
const piniaHmrPlugin = getPlugin('vite');
export default defineConfig({
...,
plugins:[piniaHmrPlugin(resolve(__dirname, 'src/store'))]
})
如果本文对您有用,希望能得到您的点赞和收藏
订阅专栏,每周更新2-3篇类型体操,等你哟😎