Step by step to build Vue3+Vite project template
1 Introduction
This project is a project template Vite3
built based on Vue3
, integrating TypeScript
, , ESLint
, Prettier
, Stylelint
, Husky
, Commitlint
package pnpm
management tools, element-plus
, Vue Router
, Pinia
, SVG
icon configuration, SASS
, Axios
etc.
Running environment: VSCode
, Node16+
, VSCode
Plug-ins: TypeScript
Vue Plugin (Volar)
, Vue Language Features (Volar)
, Prettier - Code formatter
.
Note: Need to close Vetur
the plug-in
2. Build a backend management system template
2.1 Project initialization
Today I will show you how to build a vue3 version of the backend management system from scratch. To have a unified specification for a project, we need to use eslint+stylelint+prettier to detect and repair our code quality. We need to use husky to do commit interception. We need to use commitlint to unify submission specifications. We need to use preinstall to unify package management tools. .
Next, we will use this set of specifications to initialize our project and integrate a standardized template.
2.1.1 Environment preparation
- node v16.14.2
- pnpm 8.0.0
2.1.2 Initialize project
This project is built using vite. Reference to the official Chinese documentation of vite: https://cn.vitejs.dev/guide/
pnpm: performant npm
, meaning "high performance npm
". pnpm
Derived from npm/yarn
it, it solves npm/yarn
internal potential problems bug
, greatly optimizes performance, and expands usage scenarios. Known as "the most advanced package management tool"
pnpm installation instructions
npm i -g pnpm
Project initialization command:
pnpm create vite
Go to the project root directory pnpm install
to install all dependencies. After installing the dependencies, run the program:pnpm run dev
After running the project http://127.0.0.1:5173/
, you can access your project!
2.2 Project configuration
2.2.1 eslint configuration
eslint
Chinese official website: http://eslint.cn/
ESLint
Originally an open source project created by Nicholas C. Zakas in June 2013. Its goal is to provide a plug-in javascript
code detection tool
Install firsteslint
pnpm i eslint -D
Generate configuration file:.eslint.cjs
npx eslint --init
.eslint.cjs配置文件
module.exports = {
//运行环境
"env": {
"browser": true,//浏览器端
"es2021": true,//es2021
},
//规则继承
"extends": [
//全部规则默认是关闭的,这个配置项开启推荐规则,推荐规则参照文档
//比如:函数不能重名、对象不能出现重复key
"eslint:recommended",
//vue3语法规则
"plugin:vue/vue3-essential",
//ts语法规则
"plugin:@typescript-eslint/recommended"
],
//要为特定类型的文件指定处理器
"overrides": [
],
//指定解析器:解析器
//Esprima 默认解析器
//Babel-ESLint babel解析器
//@typescript-eslint/parser ts解析器
"parser": "@typescript-eslint/parser",
//指定解析器选项
"parserOptions": {
"ecmaVersion": "latest",//校验ECMA最新版本
"sourceType": "module"//设置为"script"(默认),或者"module"代码在ECMAScript模块中
},
//ESLint支持使用第三方插件。在使用插件之前,您必须使用npm安装它
//该eslint-plugin-前缀可以从插件名称被省略
"plugins": [
"vue",
"@typescript-eslint"
],
//eslint规则
"rules": {
}
}
vue3 environment code verification plug-in
# 让所有与prettier规则存在冲突的Eslint rules失效,并使用prettier进行代码检查
"eslint-config-prettier": "^8.6.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-node": "^11.1.0",
# 运行更漂亮的Eslint,使prettier规则优先级更高,Eslint优先级低
"eslint-plugin-prettier": "^4.2.1",
# vue.js的Eslint插件(查找vue语法错误,发现错误指令,查找违规风格指南
"eslint-plugin-vue": "^9.9.0",
# 该解析器允许使用Eslint校验所有babel code
"@babel/eslint-parser": "^7.19.1",
Installation instructions
pnpm install -D eslint-plugin-import eslint-plugin-vue eslint-plugin-node eslint-plugin-prettier eslint-config-prettier eslint-plugin-node @babel/eslint-parser
Modify .eslintrc.cjs
configuration file
// @see https://eslint.bootcss.com/docs/rules/
module.exports = {
env: {
browser: true,
es2021: true,
node: true,
jest: true,
},
/* 指定如何解析语法 */
parser: 'vue-eslint-parser',
/** 优先级低于 parse 的语法解析配置 */
parserOptions: {
ecmaVersion: 'latest',
sourceType: 'module',
parser: '@typescript-eslint/parser',
jsxPragma: 'React',
ecmaFeatures: {
jsx: true,
},
},
/* 继承已有的规则 */
extends: [
'eslint:recommended',
'plugin:vue/vue3-essential',
'plugin:@typescript-eslint/recommended',
'plugin:prettier/recommended',
],
plugins: ['vue', '@typescript-eslint'],
/*
* "off" 或 0 ==> 关闭规则
* "warn" 或 1 ==> 打开的规则作为警告(不影响代码执行)
* "error" 或 2 ==> 规则作为一个错误(代码不能执行,界面报错)
*/
rules: {
// eslint(https://eslint.bootcss.com/docs/rules/)
'no-var': 'error', // 要求使用 let 或 const 而不是 var
'no-multiple-empty-lines': ['warn', {
max: 1 }], // 不允许多个空行
'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
'no-unexpected-multiline': 'error', // 禁止空余的多行
'no-useless-escape': 'off', // 禁止不必要的转义字符
// typeScript (https://typescript-eslint.io/rules)
'@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量
'@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore
'@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型
'@typescript-eslint/no-non-null-assertion': 'off',
'@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。
'@typescript-eslint/semi': 'off',
// eslint-plugin-vue (https://eslint.vuejs.org/rules/)
'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词
'vue/script-setup-uses-vars': 'error', // 防止<script setup>使用的变量<template>被标记为未使用
'vue/no-mutating-props': 'off', // 不允许组件 prop的改变
'vue/attribute-hyphenation': 'off', // 对模板中的自定义组件强制执行属性命名样式
},
}
.eslintignore
ignore file
dist
node_modules
run script
package.json
Added two new run scripts
"scripts": {
"lint": "eslint src",
"fix": "eslint src --fix",
}
2.2.2 Configure prettier
If you already have it eslint
, why do you still have it prettier
? eslint
What it is aimed at is that javascript
it is a detection tool, including js
grammar and a small number of format issues. It eslint
seems that correct grammar can ensure the normal operation of the code, and format issues are secondary; but prettier
it is a formatting tool, which cannot tolerate the inconsistent format. , so it eslint
continues to do what it didn't do well. In addition, prettier
it supports js
multiple languages included.
To sum up, eslint
with prettier
these two brothers, one ensures the quality of the js code, and the other ensures the beauty of the code.
Install dependency packages
pnpm install -D eslint-plugin-prettier prettier eslint-config-prettier
.prettierrc.json
Add rules
{
"singleQuote": true,
"semi": false,
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "ignore",
"endOfLine": "auto",
"trailingComma": "all",
"tabWidth": 2
}
.prettierignore
ignore file
/dist/*
/html/*
.local
/node_modules/**
**/*.svg
**/*.sh
/public/*
By pnpm run lint
checking the grammar, if there is an irregular format, pnpm run fix
modify it by
2.2.3 Configuring stylelint
stylelint
Tools for css lint
. You can format css
the code, check for css
grammatical errors and unreasonable writing, specify css
the writing order, etc.
scss
Used as a preprocessor in our project , install the following dependencies:
pnpm add sass sass-loader stylelint postcss postcss-scss postcss-html stylelint-config-prettier stylelint-config-recess-order stylelint-config-recommended-scss stylelint-config-standard stylelint-config-standard-vue stylelint-scss stylelint-order stylelint-config-standard-scss -D
.stylelintrc.cjs
Configuration file
Official website: https://stylelint.bootcss.com/
// @see https://stylelint.bootcss.com
module.exports = {
extends: [
'stylelint-config-standard', // 配置stylelint拓展插件
'stylelint-config-html/vue', // 配置 vue 中 template 样式格式化
'stylelint-config-standard-scss', // 配置stylelint scss插件
'stylelint-config-recommended-vue/scss', // 配置 vue 中 scss 样式格式化
'stylelint-config-recess-order', // 配置stylelint css属性书写顺序插件,
'stylelint-config-prettier', // 配置stylelint和prettier兼容
],
overrides: [
{
files: ['**/*.(scss|css|vue|html)'],
customSyntax: 'postcss-scss',
},
{
files: ['**/*.(html|vue)'],
customSyntax: 'postcss-html',
},
],
ignoreFiles: [
'**/*.js',
'**/*.jsx',
'**/*.tsx',
'**/*.ts',
'**/*.json',
'**/*.md',
'**/*.yaml',
],
/**
* null => 关闭该规则
* always => 必须
*/
rules: {
'value-keyword-case': null, // 在 css 中使用 v-bind,不报错
'no-descending-specificity': null, // 禁止在具有较高优先级的选择器后出现被其覆盖的较低优先级的选择器
'function-url-quotes': 'always', // 要求或禁止 URL 的引号 "always(必须加上引号)"|"never(没有引号)"
'no-empty-source': null, // 关闭禁止空源码
'selector-class-pattern': null, // 关闭强制选择器类名的格式
'property-no-unknown': null, // 禁止未知的属性(true 为不允许)
'block-opening-brace-space-before': 'always', //大括号之前必须有一个空格或不能有空白符
'value-no-vendor-prefix': null, // 关闭 属性值前缀 --webkit-box
'property-no-vendor-prefix': null, // 关闭 属性前缀 -webkit-mask
'selector-pseudo-class-no-unknown': [
// 不允许未知的选择器
true,
{
ignorePseudoClasses: ['global', 'v-deep', 'deep'], // 忽略属性,修改element默认样式的时候能使用到
},
],
},
}
.stylelintignore
ignore file
/node_modules/*
/dist/*
/html/*
/public/*
run script
"scripts": {
"lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
}
Finally configure a unified format to format prettier
our sum js
and codecss
html
"scripts": {
"dev": "vite --open",
"build": "vue-tsc && vite build",
"preview": "vite preview",
"lint": "eslint src",
"fix": "eslint src --fix",
"format": "prettier --write \"./**/*.{html,vue,ts,js,json,md}\"",
"lint:eslint": "eslint src/**/*.{ts,vue} --cache --fix",
"lint:style": "stylelint src/**/*.{css,scss,vue} --cache --fix"
},
When we run it pnpm run format
, the code will be formatted directly
2.2.4 Configure husky
We have integrated our code verification tool above, but we need to manually execute the command each time to format our code. If someone submits it to the remote repository without formatting it, then this specification is of little use. So we need to force developers to submit according to code specifications.
To do this, we need to trigger ( a hook on the client side) husky
before the code is submitted , and then execute it to automatically format our code.git hook
git
pnpm run format
Installhusky
pnpm install -D husky
implement
npx husky-init
A .husky
directory will be generated in the root directory. There will be a file under this directory pre-commit
. The commands in this file commit
will be executed when we execute it.
.husky/pre-commit
Add the following command to the file:
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm run format
When we operate the code commit
, we will execute the command, format the code, and then submit it.
2.2.5 Configure commitlint
There are also unified standards for our commit
information. We cannot write it casually. We need everyone to implement it according to unified standards. We can use it to commitlint
achieve this.
Installation package
pnpm add @commitlint/config-conventional @commitlint/cli -D
Add the configuration file, create a new one commitlint.config.cjs
(note yes cjs
), and then add the following code:
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
Configure scripts
commands in
# 在scrips中添加下面的代码
{
"scripts": {
"commitlint": "commitlint --config commitlint.config.cjs -e -V"
},
}
The configuration is over. Now when we fill in commit
the information, we need to bring the followingsubject
'feat',//新特性、新功能
'fix',//修改bug
'docs',//文档修改
'style',//代码格式修改, 注意不是 css 修改
'refactor',//代码重构
'perf',//优化相关,比如提升性能、体验
'test',//测试用例修改
'chore',//其他修改, 比如改变构建流程、或者增加依赖库、工具等
'revert',//回滚到上一个版本
'build',//编译相关的修改,例如发布版本、对项目构建或者依赖的改动
Configurationhusky
npx husky add .husky/commit-msg
commit-msg
Add the following command to the generated file
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
pnpm commitlint
When we commit
submit information, we can no longer write it casually. It must git commit -m 'fix: xxx'
conform to the type. It should be noted that the type needs to be followed by English:, and there needs to be a space after the colon. This cannot be omitted.
2.2.6 Force the use of pnpm package manager tool
When a team develops a project, it is necessary to unify the package manager tool, because different package manager tools may download the same dependency in different versions.
This causes bug
problems in the project, so the package manager tool needs to be managed uniformly! ! !
Create scritps/preinstall.js
a file in the root directory and add the following content
if (!/pnpm/.test(process.env.npm_execpath || '')) {
console.warn(
`\u001b[33mThis repository must using pnpm as the package manager ` +
` for scripts to work properly.\u001b[39m\n`,
)
process.exit(1)
}
Configuration commands
"scripts": {
"preinstall": "node ./scripts/preinstall.js"
}
When we use npm or yarn to install the package, an error will be reported. The principle is that the code in the preinstall (life cycle hook provided by npm) file will be triggered during installation.
3. Project integration
3.1 Integrate element-plus
Official website address: https://element-plus.gitee.io/zh-CN/
Installelement-plus
pnpm install element-plus @element-plus/icons-vue
The default supported language main.ts
for global installation of the entry file is set to Chinese. English is set to Chinese.element-plus, element-plus
import ElementPlus from 'element-plus';
import 'element-plus/dist/index.css'
//@ts-ignore忽略当前文件ts类型的检测否则有红色提示(打包会失败)
import zhCn from 'element-plus/dist/locale/zh-cn.mjs'
app.use(ElementPlus, {
locale: zhCn
})
Element Plus
Global component type declaration
// tsconfig.json
{
"compilerOptions": {
// ...
"types": ["element-plus/global"]
}
}
After the configuration is completed, you can test element-plus
the use of components and icons.
3.2 Integrate Vue Router
Installvue-router
pnpm i vue-router@4
Routing configuration
// `src\router\index.ts`
// 通过vue-router插件实现模板路由配置
import {
createRouter, createWebHashHistory } from 'vue-router'
import {
constantRoute } from './router'
//创建路由器
const router = createRouter({
//路由模式hash
history: createWebHashHistory(),
routes: constantRoute,
//滚动行为
scrollBehavior() {
return {
left: 0,
top: 0,
}
},
})
export default router
// `src\router\router.ts`
// 对外暴露配置路由(常量路由)
export const constantRoute = [
{
//登录路由
path: '/login',
component: () => import('@/views/login/index.vue'),
name: 'login', //命名路由
},
{
//登录成功以后展示数据的路由
path: '/',
component: () => import('@/views/home/index.vue'),
name: 'layout',
},
{
path: '/404',
component: () => import('@/views/404/index.vue'),
name: '404',
},
{
//重定向
path: '/:pathMatch(.*)*',
redirect: '/404',
name: 'Any',
},
]
routing exit
src\App.vue
3.3 Integrating Pinia
Install pinia:pnpm i [email protected]
// `src\store\index.ts`
// 仓库大仓库
import {
createPinia } from 'pinia'
//创建大仓库
const pinia = createPinia()
//对外暴露:入口文件需要安装仓库
export default pinia
// `src\store\modules\user.ts`
//创建用户相关的小仓库
import {
defineStore } from 'pinia'
//创建用户小仓库
const useUserStore = defineStore('User', {
//小仓库存储数据地方
state: () => {
},
//处理异步|逻辑地方
actions: {
},
getters: {
},
})
//对外暴露小仓库
export default useUserStore
3.4 Configuration of src alias
When developing a project, the relationship between files may be complicated, so we need to src
configure an alias for the folder! ! !
// vite.config.ts
import {
defineConfig} from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve("./src") // 相对路径别名配置,使用 @ 代替 src
}
}
})
TypeScript
Compile configuration
// tsconfig.json
{
"compilerOptions": {
"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
"paths": {
//路径映射,相对于baseUrl
"@/*": ["src/*"]
}
}
}
3.5 Configuration of environment variables
During the project development process, it will go through at least three stages: development environment, test environment and production environment (ie formal environment). The status of requests (such as interface addresses, etc.) at different stages is different. Manually switching the interface address is quite tedious and error-prone. So the need for environment variable configuration emerged. We only need to do simple configuration and leave the work of switching environment states to the code.
Development environment ( development
)
As the name suggests, in the development environment, each developer works on his or her own dev branch. When development reaches a certain level, colleagues will merge the code and conduct joint debugging.
Test environment ( testing
)
The environment in which test colleagues work is usually deployed by the test colleagues themselves and then tested in this environment.
Production environment ( production
)
The production environment refers to the official provision of external services. Generally, error reporting is turned off and error logs are turned on. (Environment officially provided to customers.)
Note: Generally, one environment corresponds to one server, and some companies' development and testing environments are one server! ! !
Add files for development, production and test environments to the project root directory respectively!
.env.development
.env.production
.env.test
document content
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'development'
VITE_APP_TITLE = 'XX平台'
VITE_APP_BASE_API = '/dev-api'
NODE_ENV = 'production'
VITE_APP_TITLE = 'XX平台'
VITE_APP_BASE_API = '/prod-api'
# 变量必须以 VITE_ 为前缀才能暴露给外部读取
NODE_ENV = 'test'
VITE_APP_TITLE = 'XX平台'
VITE_APP_BASE_API = '/test-api'
Configure running command:package.json
"scripts": {
"dev": "vite --open",
"build:test": "vue-tsc && vite build --mode test",
"build:pro": "vue-tsc && vite build --mode production",
"preview": "vite preview"
},
import.meta.env
Get environment variables by
3.6 SVG icon configuration
Vector graphics are often used when developing projects svg
, and after we use them SVG
, image resources are no longer loaded on the page. This is a great improvement for page performance, and our SVG
file ratio img
is much smaller. Almost no resources are used in the project.
Install SVG
dependent plugins
pnpm install vite-plugin-svg-icons -D
vite.config.ts
Configure the plugin in
import {
createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import path from 'path'
export default () => {
return {
plugins: [
createSvgIconsPlugin({
// Specify the icon folder to be cached
iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
// Specify symbolId format
symbolId: 'icon-[dir]-[name]',
}),
],
}
}
Entry file import
import 'virtual:svg-icons-register'
svg
Encapsulated as a global component
Because many modules of the project need to use icons, they are encapsulated as global components! ! !
src/components
Create a component in the directory SvgIcon
: represented as follows
<template>
<div>
<svg :style="{ width: width, height: height }">
<use :xlink:href="prefix + name" :fill="color"></use>
</svg>
</div>
</template>
<script setup lang="ts">
defineProps({
//xlink:href属性值的前缀
prefix: {
type: String,
default: '#icon-'
},
//svg矢量图的名字
name: String,
//svg图标的颜色
color: {
type: String,
default: ""
},
//svg宽度
width: {
type: String,
default: '16px'
},
//svg高度
height: {
type: String,
default: '16px'
}
})
</script>
<style scoped></style>
Create a file in src
the folder directory index.ts
: used to register components
all global components inside the folder! ! !
import SvgIcon from './SvgIcon/index.vue';
import type {
App, Component } from 'vue';
const components: {
[name: string]: Component } = {
SvgIcon };
export default {
install(app: App) {
Object.keys(components).forEach((key: string) => {
app.component(key, components[key]);
})
}
}
Introduce files in the entry file and install custom plug-ins src/index.ts
through methodsapp.use
import gloablComponent from './components/index';
app.use(gloablComponent);
3.7 Integrating sass
We can currently use styles inside the component scss
because styleLint
it has been installed in the project when configuring the tool sass sass-loader
, so we can use the syntax inside the component scss
! ! ! Need to addlang="scss"
<style scoped lang="scss"></style>
Next we add some global styles to the project
src/styles
Create a file in the directory . index.scss
Of course, the project needs to clear the default style, so when index.scss
introducingreset.scss
@import reset.scss
Imported in the entry file
import '@/styles'
But you will find that src/styles/index.scss
there is no way to use variables in the global style file. Therefore, you need to introduce global variables into the project.
Creating style/variable.scss
a variable.scss
file!
The file configuration is vite.config.ts
as follows:
export default defineConfig((config) => {
css: {
preprocessorOptions: {
scss: {
javascriptEnabled: true,
additionalData: '@import "./src/styles/variable.scss";',
},
},
},
}
}
@import "./src/styles/variable.less"
Don't forget the ";" at the end, otherwise an error will be reported!
After the configuration is completed, you will find scss
that these global variables can be used in component styles! ! !
3.8 axios secondary packaging
When developing a project, it is inevitable to interact with the backend, so we need to use axios
plug-ins to send network requests. When developing a project
We often carry axios
out secondary packaging.
Purpose:
1: Using the request interceptor, you can handle some business in the request interceptor (start progress bar, request header carries public parameters)
2: Using the response interceptor, you can handle some business in the response interceptor (end of progress bar, simplifying the data returned by the server, handling http
network errors)
Create in root directoryutils/request.ts
import axios from "axios";
import {
ElMessage } from "element-plus";
//创建axios实例
let request = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 5000
})
//请求拦截器
request.interceptors.request.use(config => {
return config;
});
//响应拦截器
request.interceptors.response.use((response) => {
return response.data;
}, (error) => {
//处理网络错误
let msg = '';
let status = error.response.status;
switch (status) {
case 401:
msg = "token过期";
break;
case 403:
msg = '无权访问';
break;
case 404:
msg = "请求地址错误";
break;
case 500:
msg = "服务器出现问题";
break;
default:
msg = "无网络";
}
ElMessage({
type: 'error',
message: msg
})
return Promise.reject(error);
});
export default request;