From my first contact
vue3
It has been one year since the release. Becausevue3.2Release of version,<script setup&
Amp; Amp; Gt; The experimental mark of has been removed, and many companies have started to use itvue3.2
Development project. This article will help you how to use it quicklyvue3.x
,typeScript
,vite
Set up an enterprise level development scaffold. Don’t talk too much nonsense, just get started. There is a project address at the end of the article!!!
Preparation before construction
-
Vscode
: a necessary code writing artifact for front-end users -
Chrome
: a developer friendly browser (I rely on it anyway) -
Nodejs&npm
: configure the local development environment. After installing node, you will find that NPM will be installed together -
Vue.js devtools
: Browser debug plug-in -
Vue Language Features (Volar)
: vscade develops the necessary plug-in for vue3, and provides syntax highlighting prompt, which is very easy to use -
Vue 3 Snippets
: vue3quick input
The difference between vue2 and vue3
Vue3
Due to the fact thatTS
Rewrite, which has a strong performance in the definition and use of type judgment in applications. Multiple key return values of the same object must be typed by defining corresponding interfaces. Otherwise, an error will be reported in eslint.
vue2
The bidirectional data binding ofES5
One ofAPI Object.definePropert()
Data hijacking is implemented in combination with publish subscribe mode.Vue3
Used ines6
ofProxyAPI
For data brokers.
Vue3
Support fragment(Fragments
)
Vue2
AndVue3
The biggest difference:Vue2
applyOptions API
andVue3
UsedComposition API
Lifecycle hook changes:
Vue2 ~~~~~~~~~~~ vue3
beforeCreate -> setup()
created -> setup()
beforeMount -> onBeforeMount
mounted -> onMounted
beforeUpdate -> onBeforeUpdate
updated -> onUpdated
beforeDestroy -> onBeforeUnmount
destroyed -> onUnmounted
activated -> onActivated
deactivated -> onDeactivated
Introducing vite
Vite: the next generation front-end development and construction tool
- Extremely fast development server startup
- ⚡ ¢ lightweight and fast thermal module reload (HMR)
– rich features - Built in optimization
- Universal plug-in interface
Vite
(French for “quick”, pronounced /vit/) is a new front-end building tool that greatly improves the front-end development experience.
It mainly consists of two parts
- A development server based on native
ES
The module provides a wealth of built-in functions, such as the amazing module hot update (HMR).
A set of build instructions that useRollup
Package your code, and it is pre configured to output optimized static resources for the production environment. - Vite is intended to provide out of the box configuration. At the same time, its plug-in API and JavaScript API bring a high degree of scalability and complete type support.
Using vite to quickly create scaffolding
Compatibility Note: vite requires node JS version > = 12.0.0.
1. step 1: open CMD under the directory where the project file needs to be created and run the following command
# npm 6.x
npm init @vitejs/app vite_vue3_ts --template
#NPM 7+, additional double horizontal lines are required:
npm init @vitejs/app vite_vue3_ts -- --template
# yarn
yarn create @vitejs/app vite_vue3_ts --template
-
Here I use
yarn
To install1638941494(1).png -
Select Vue enter = >
vue-ts
enter

- Open the project folder, install dependencies, and start the project
#Enter project folder
CD to your project folder
#Installation dependency
yarn
#Start
yarn dev

Constraint code style
Eslint support
#Eslint installation
yarn add eslint --dev
#Eslint plug-in installation
yarn add eslint-plugin-vue --dev
yarn add @typescript-eslint/eslint-plugin --dev
yarn add eslint-plugin-prettier --dev
# typescript parser
yarn add @typescript-eslint/parser --dev
Note: ifeslint
Installation error:

You can try the following command:
yarn config set ignore-engines true
Execute again after successful operationeslint
Installation command
New under item Eslintrc js
allocation
eslint
Verification rules:
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',
//Abbreviation for eslint config prettier
'prettier',
],
parserOptions: {
ecmaVersion: 12,
parser: '@typescript-eslint/parser',
sourceType: 'module',
ecmaFeatures: {
jsx: true,
},
},
//Eslint plugin Vue @typescript eslint/eslint-plugin short for 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',
//Disable console
'no-console': 'warn',
//Disable debugger
'no-debugger': 'warn',
//Prohibit duplicate case labels
'no-duplicate-case': 'warn',
//Suppress empty statement blocks
'no-empty': 'warn',
//Prohibit unnecessary parentheses
'no-extra-parens': 'off',
//Disallow reassignment of function declarations
'no-func-assign': 'warn',
//Disable unreachable codes after return, throw, continue, and break statements
'no-unreachable': 'warn',
//Force all control statements to use a consistent bracket style
curly: 'warn',
//Require default branch in switch statement
'default-case': 'warn',
//Force point numbers to be used whenever possible
'dot-notation': 'warn',
//Requires = = = and==
eqeqeq: 'warn',
//Disable else block after return statement in if statement
'no-else-return': 'warn',
//Null functions are prohibited
'no-empty-function': 'warn',
//Disable unnecessary nested blocks
'no-lone-blocks': 'warn',
//Prohibit multiple spaces
'no-multi-spaces': 'warn',
//Multiple declarations of the same variable are prohibited
'no-redeclare': 'warn',
//Assignment statements are prohibited in return statements
'no-return-assign': 'warn',
//Disable unnecessary return await
'no-return-await': 'warn',
//Prohibit self assignment
'no-self-assign': 'warn',
//Prohibit self comparison
'no-self-compare': 'warn',
//Suppress unnecessary catch clauses
'no-useless-catch': 'warn',
//Prohibit redundant return statements
'no-useless-return': 'warn',
//Prohibit variable declarations from having the same name as variables in the outer scope
'no-shadow': 'off',
//Allow delete variables
'no-delete-var': 'off',
//Force consistent spaces in array square brackets
'array-bracket-spacing': 'warn',
//Force consistent brace style in code blocks
'brace-style': 'warn',
//Enforce camel spelling naming conventions
camelcase: 'warn',
//Force consistent indentation
indent: 'off',
//Force consistent use of double or single quotes in JSX attributes
// 'jsx-quotes': 'warn',
//Force the maximum depth of a nested block 4
'max-depth': 'warn',
//Force maximum rows 300
// "max-lines": ["warn", { "max": 1200 }],
//Force function maximum lines of code 50
// 'max-lines-per-function': ['warn', { max: 70 }],
//Force the maximum number of statements allowed for a function block 20
'max-statements': ['warn', 100],
//Force maximum nesting depth of callback function
'max-nested-callbacks': ['warn', 3],
//Force the maximum number of parameters allowed in a function definition
'max-params': ['warn', 3],
//Force the maximum number of statements allowed per row
'max-statements-per-line': ['warn', { max: 1 }],
//Require a newline character for each call in the method chain
'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 3 }],
//Disable if as the only statement in else statements
'no-lonely-if': 'warn',
//Prohibit mixed indentation of spaces and tabs
'no-mixed-spaces-and-tabs': 'warn',
//Multiple blank lines are prohibited
'no-multiple-empty-lines': 'warn',
//Prohibited;
semi: ['warn', 'never'],
//Force consistent whitespace before blocks
'space-before-blocks': 'warn',
//Force consistent spaces before the left parenthesis of function
// 'space-before-function-paren': ['warn', 'never'],
//Force consistent spaces within parentheses
'space-in-parens': 'warn',
//Require spaces around operators
'space-infix-ops': 'warn',
//Force consistent spaces before and after unary operators
'space-unary-ops': 'warn',
//Force consistent spaces // or / * in comments
// "spaced-comment": "warn",
//Force a space around the colon of the switch
'switch-colon-spacing': 'warn',
//Force consistent spaces before and after arrows in arrow functions
'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',
},
}
New under item Eslintignore
#Eslint ignore the check (add it yourself according to the needs of the project)
node_modules
dist
Prettier support
#Installing prettier
yarn add prettier --dev
Resolve eslint and prettier conflicts
solve
ESLint
Style specifications andprettier
Conflicts with style specifications inprettier
The style specification in eslint will automatically become invalid
#Install the plug-in eslint config prettier
yarn add eslint-config-prettier --dev
New under item Prettier js
allocation
prettier
Formatting rules:
module.exports = {
tabWidth: 2,
jsxSingleQuote: true,
jsxBracketSameLine: true,
printWidth: 100,
singleQuote: true,
semi: false,
overrides: [
{
files: '*.json',
options: {
printWidth: 200,
},
},
],
arrowParens: 'always',
}
New under item Prettierignore
#Ignore the format file (add it yourself according to the needs of the project)
node_modules
dist
Package JSON configuration:
{
"script": {
"lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx",
"prettier": "prettier --write ."
}
}
After the above configuration is completed, you can run the followingcommand
Test the following code to check the formatting effect:
#Eslint check
yarn lint
#Prettier auto format
yarn prettier
Configure husky + lint staged
apply
husky
+lint-staged
Code specification for help team, recommended for husky & lint staged installationmrm
, it willpackage.json
Depend on the code quality tools in the to install and configure husky and lint staged, so please ensure that all code quality tools are installed and configured before that, such asPrettier
andESlint
Install MRM first
npm i mrm -D --registry=https://registry.npm.taobao.org
husky
Is an add-on for git clientshook
Tools for. After installation, it will be automatically installed in the warehouse.git/
Add corresponding hooks under the directory; such aspre-commit
The hook will execute on yougit commit
Trigger of.
So we canpre-commit
For exampleLint check
、unit testing
、Code beautification
Etc. Of course,pre-commit
Of course, the speed of the commands executed in the phase should not be too slow. It is not a good experience to wait a long time for each commit.
lint-staged
, a file that only filters out git code staging area (bygit add
The tools of; This is very practical, because if we check the code of the whole project, it may take a long time. If it is an old project, it may be troublesome to check and modify the code specification of the previous code, which may lead to great changes in the project.
So thislint-staged
, which is a good tool for team projects and open source projects. It is a specification and constraint for the code to be submitted by individuals
Lint mounted
mrm
installlint-staged
Will automaticallyhusky
Installed together
npx mrm lint-staged
After successful installation, you will findpackage.json
The following configurations are added in:

Because we have to combineprettier
Code formatting. Modify the following configurations:
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"*.{js,jsx,vue,ts,tsx}": [
"yarn lint",
"prettier --write",
"git add"
]
}
OK, here the code formatting configuration is basically completed!!!
Profile reference alias alias
directly modify
vite.config.ts
File configuration:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
})
modify
tsconfig.json
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "node",
"strict": true,
"jsx": "preserve",
"sourceMap": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"lib": ["esnext", "dom"],
"baseUrl": ".",
"paths": {
"@/*":["src/*"]
}
},
"include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"]
}
Configure CSS preprocessor SCSS
although
vite
Native supportless/sass/scss/stylus
, but you must manually install their preprocessor dependencies
install
yarn add dart-sass --dev
yarn add sass --dev
Configure global SCSS style file
staysrc/assets
Add nextstyle
Folder for global style files
Newmain.scss
, set a color variable for testing:
$test-color: red;
How to globally inject this global style file into the project? allocationVite
That is:
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/assets/style/mian.scss";'
}
}
},
Used in components
You can directly use global without any import
scss
Defined variables
.test{
color: $test-color;
}
route
#Install routing
yarn add [email protected]
staysrc
New under filerouter
Folder =>router.ts
Document, as follows:
import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'
const routes: RouteRecordRaw[] = [
{
path: '/',
name: 'Login',
Component: () = > Import ('@/pages/login/login.vue'), // note the file suffix vue
},
]
const router = createRouter({
history: createWebHistory(),
routes,
})
export default router
Modify entry filemian.ts
:
import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
const app = createApp(App)
app.use(router)
app.mount('#app')
The basic configuration of routes here has been completed. You can view more configuration informationvue-router
Official documents:
vue-router: https://next.router.vuejs.org/zh/guide/
vue-router4.x
supporttypescript
, the type of configured route isRouteRecordRaw
, heremeta
It can give us more room to play. Here are some references:
-
title:string
; Page title, usually required. -
icon?:string
; Icon, usually used with menus. -
auth?:boolean
; Whether login permission is required. -
ignoreAuth?:boolean
; Whether to ignore permissions. -
roles?:RoleEnum[]
; Accessible roles -
keepAlive?:boolean
; Whether to enable page caching -
hideMenu?:boolean
; Some routes we do not want to display in the menu, such as some edit pages. -
order?:number
; Menu sorting. -
frameUrl?:string
; Nested outer chain.
Only some ideas are provided here. There will be some differences in the businesses involved in each project. I won’t explain them in detail here. You can configure them according to your own business needs.
Unified request encapsulation
Used vue2 Students of X should be familiar with Axios. Here we directly use Axios for packaging:
#Installing Axios
yarn add axios
#Install nprogress to request loading
#You can also customize other loading according to project requirements
yarn add nprogress
#Type declaration, or add one containing `declare module'nprogress'
yarn add @types/nprogress --dev
In actual use, it can be modified according to the project. For example, put and delete requests can be added in the restful API, and the restype can also be dynamically modified according to the general return value of the back end
Add a service folder, and add http TS file and API folder:

http.ts
: foraxios
encapsulation
//http.ts
import axios, { AxiosRequestConfig } from 'axios'
import NProgress from 'nprogress'
//Set request header and request path
axios.defaults.baseURL = '/api'
axios.defaults.timeout = 10000
axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8'
axios.interceptors.request.use(
(config): AxiosRequestConfig<any> => {
const token = window.sessionStorage.getItem('token')
if (token) {
//@ts-ignore
config.headers.token = token
}
return config
},
(error) => {
return error
}
)
//Response interception
axios.interceptors.response.use((res) => {
if (res.data.code === 111) {
sessionStorage.setItem('token', '')
//Token expiration
}
return res
})
interface ResType<T> {
code: number
data?: T
msg: string
err?: string
}
interface Http {
get<T>(url: string, params?: unknown): Promise<ResType<T>>
post<T>(url: string, params?: unknown): Promise<ResType<T>>
upload<T>(url: string, params: unknown): Promise<ResType<T>>
download(url: string): void
}
const http: Http = {
get(url, params) {
return new Promise((resolve, reject) => {
NProgress.start()
axios
.get(url, { params })
.then((res) => {
NProgress.done()
resolve(res.data)
})
.catch((err) => {
NProgress.done()
reject(err.data)
})
})
},
post(url, params) {
return new Promise((resolve, reject) => {
NProgress.start()
axios
.post(url, JSON.stringify(params))
.then((res) => {
NProgress.done()
resolve(res.data)
})
.catch((err) => {
NProgress.done()
reject(err.data)
})
})
},
upload(url, file) {
return new Promise((resolve, reject) => {
NProgress.start()
axios
.post(url, file, {
headers: { 'Content-Type': 'multipart/form-data' },
})
.then((res) => {
NProgress.done()
resolve(res.data)
})
.catch((err) => {
NProgress.done()
reject(err.data)
})
})
},
download(url) {
const iframe = document.createElement('iframe')
iframe.style.display = 'none'
iframe.src = url
iframe.onload = function () {
document.body.removeChild(iframe)
}
document.body.appendChild(iframe)
},
}
export default http
api
: unified management of interfaces in the project, divided according to modules
stayapi
New under filelogin
The folder is used to store the request interface of the login module. The login folder is added separatelylogin.ts types.ts
:
login.ts
:
import http from '@/service/http'
import * as T from './types'
const loginApi: T.ILoginApi = {
login(params){
return http.post('/login', params)
}
}
export default loginApi
types.ts
:
export interface ILoginParams {
userName: string
passWord: string | number
}
export interface ILoginApi {
login: (params: ILoginParams)=> Promise<any>
}
At this point, a simple request encapsulation is completed!!!!
In addition to manually encapsulating Axios, a vue3 request library is recommended:VueRequest
, very easy to use, let’s take a lookVueRequest
What are the easier functions to use!!!
- All data is responsive
- poll request
- Auto process error retry
- Built in request cache
- Throttling request and anti shake request
- Automatic re request when focusing on page
- ⚙️ Powerful paging extensions and loading more extensions
- Completely written in typescript, with powerful type prompt
- ⚡ Compatible with vite
- Lightweight
- Out of the box
Is it powerful
Official website link:https://www.attojs.com/
State management Pinia
Because the typescript support of vuex 4 is sad, the state management abandons vuex and adopts pinia Pinia’s author is a member of Vue’s core team
You da seems to saypinia
May replacevuex
, so please feel free to use.
-
id
It is necessary to connect the used store to devtools. - Creation method:
new Vuex.Store(...)(vuex3)
,createStore(...)(vuex4)
。 - Compared with vuex3, state is now a
Function return object
。 - absence
mutations
, don’t worry. State changes are still recorded in devtools.
#Installation
yarn add [email protected]
Main Added in TS
#Introduction
import { createPinia } from "pinia"
#Create a root repository and pass it to the application
app.use(createPinia())
staysrc
New under folderstore
Folder, followed by adding in the storemain.ts
establishstore
, mian.ts :
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () =>({
Name: 'super administrator'
})
})
Get the store in the build:
<template>
<div>{{mainStore.name}}</div>
</template>
<script setup lang="ts">
import { useMainStore } from "@/store/mian"
const mainStore = useMainStore()
</script>
Getters usage introduction
Getters in Pinia have the same functions as getters in vuex and calculation attributes in components
store
=>mian.ts
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () => ({
Name: 'super administrator',
}),
// getters
getters: {
nameLength: (state) => state.name.length,
}
})
Used in components:
<template>
<div> user name: {{mainstore.name} <br / > length: {{mainstore.namelength} </div>
<hr/>
<button @click= "updatename" > Modify name</button>
</template>
<script setup lang="ts">
import { useMainStore } from '@/store/mian'
const mainStore = useMainStore()
const updateName = ()=>{
//$patch modify the data in the store
mainStore.$patch({
Name: 'the name has been modified, and the namelength has also been changed accordingly'
})
}
</script>
actions
Here and
Vuex
It’s very different,Pinia
Only one method is provided to define the rules of how to change the state. Discardmutations
Rely only onActions
This is a major change.
Pinia
offerActions
More flexible:
- You can use components or other
action
call - From other
store
ofaction
Call in - Directly in
store
Call on instance - Support synchronous or asynchronous
- There are any number of parameters
- It can contain logic about how to change the state (that is, the function of vuex’s changes)
- Yes
$patch
Method to change state properties directly
import { defineStore } from 'pinia'
export const useMainStore = defineStore({
id: 'mian',
state: () => ({
Name: 'super administrator',
}),
getters: {
nameLength: (state) => state.name.length,
},
actions: {
async insertPost(data:string){
//Can be asynchronous
// await doAjaxRequest(data);
this.name = data;
}
},
})
Environment variable configuration
vite
Two modes are provided: with development serverDevelopment mode
(Development) andProduction mode
(production)
Project root directory new:.env.development
:
NODE_ENV=development
VITE_APP_WEB_URL= 'YOUR WEB URL'
Project root directory new:.env.production
:
NODE_ENV=production
VITE_APP_WEB_URL= 'YOUR WEB URL'
Used in components:
console.log(import.meta.env.VITE_APP_WEB_URL)
allocationpackage.json
:
Packaging distinguishes development environment from production environment
"build:dev": "vite build --mode development",
"build:pro": "vite build --mode production",
Use the naive UI of the component library (you can also choose according to your own technology stack)
Component library selection, here we select
Naive UI
Why did you choose it? Can I just say what you da da recommended?
#Install component library
yarn add naive-ui
#Install fonts
yarn add vfonts
How to use
import { NButton } from "naive-ui"
<n-button>naive-ui</n-button>
Global configuration config provider
Global configuration sets the theme, language of internal components and the class name of DOM where components are unloaded in other locations.
<n-config-provider :locale="zhCN" :theme="theme">
<!-- Container -- >
</n-config-provider>
Vite common basic configuration
Basic configuration
function
agent
andpack
allocation
server: {
host: '0.0.0.0',
port: 3000,
open: true,
https: false,
proxy: {}
},
Removing the console debugger in the production environment
build:{
...
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true
}
}
}
Production environment generation GZ file
open
gzip
It can greatly compress static resources and play a significant role in the speed of page loading.
applyvite-plugin-compression
Yesgzip
orbrotli
This step requires the cooperation of the server. Vite can only help you package.gz
Documents. This plug-in is easy to use. You can even import it without configuring parameters.
#Installation
yarn add --dev vite-plugin-compression
Add to plugins:
import viteCompression from 'vite-plugin-compression'
//Gzip compression production environment generation GZ file
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
}),
Final vite config. TS
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'
//@ts-ignore
import viteCompression from 'vite-plugin-compression'
// https://vitejs.dev/config/
export default defineConfig({
Base:'./'// Packaging path
plugins: [
vue(),
//Gzip compression production environment generation GZ file
viteCompression({
verbose: true,
disable: false,
threshold: 10240,
algorithm: 'gzip',
ext: '.gz',
}),
],
//Configure alias
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
css:{
preprocessorOptions:{
scss:{
additionalData:'@import "@/assets/style/mian.scss";'
}
}
},
//Start service configuration
server: {
host: '0.0.0.0',
port: 8000,
open: true,
https: false,
proxy: {}
},
//Production environment packaging configuration
//Remove the console debugger
build: {
terserOptions: {
compress: {
drop_console: true,
drop_debugger: true,
},
},
},
})
Common plug-ins
You can view official documents:https://vitejs.cn/plugins/