Use Vite to quickly create scaffolding

1. Run the installation command using YARN

Install yarn create @vitejs/app vue3_ts_vite_pinia

2. Choosevue vue-tsComplete the installation

3. Go to the vue3_ts_vite_pinia project and run the yarn command to install dependencies. After the dependencies are installed, use yarn dev to start the project

Start the project yarn dev

2. Route Configuration (vue-router@4)

The basic configuration

1. Use YARN to install vue-router@4

Install yarn add vue-router@4

2. Create a router folder under the SRC folder and create index.ts under the router folder

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
    {
        path: '/'.name: 'Index'.component: () = > import('@/pages/index/Index.vue'),}]const router = createRouter({
    history: createWebHistory(),
    routes,
})

export default router
Copy the code

Note :RouteRecordRaw is a built-in type

3. Import and register the router in main.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')
Copy the code

<template>
    // <img alt="Vue logo" src="./assets/logo.png" />
    // <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />
    <router-view></router-view>
</template>
Copy the code

Routing guard

Add router/index.ts router/index.ts router/index.ts

import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw[] = [
    {
        path: '/'.name: 'Index'.component: () = > import('@/pages/index/Index.vue'),}]const router = createRouter({
    history: createWebHistory(),
    routes,
})
router.beforeEach((to,from) = >{
        if(pass){
        console.log('pass')
          // No further release with next()
        }else{
            return false}})export default router
Copy the code

(2) The routing guard within the component

New composite API can replace the original component inside guard, onBeforeRouteLeave(triggered when leaving the current page route), onBeforeRouteUpdate(triggered when route update)

onBeforeRouteLeave((to,form) = >{})Copy the code

Page using

1. Basically use (1) jump within the page

import { useRouter,useRoute } from 'vue-router';
 const go=() = >{
     const Router=useRouter()
     const Route=useRoute()
     Router.push({
         name:'/login'.query: {id:'123456'}})}Copy the code

3. State Management (Pinia configuration)

Js state management library Pinia is a lightweight state management library recommended by the Vue core team. As Pinia is also a product of Vuex R&D team and supported by Vue, it is highly likely to replace Vuex. Even if the promotion of Pinia is not smooth, we don’t need to worry too much. Many of its uses will most likely be ported to VEX5. Compared to Vuex,Pinia is easier to get started, mutations, and Actions support synchronous or asynchronous.

The basic configuration

1. Use YARN to install pinia@next

Install yarn add pinia@next

2. Create a store folder in the SRC folder and create main.ts folder in the store folder

import { defineStore } from 'pinia'

export const useUserStore = defineStore({
    id: 'user'.state: () = > ({
        name: 'Username'
    }),
    getters: {
        nameLength: (state) = > state.name.length,
    },
    actions: {
        updataUser(data: any) {
            console.log(data)
        }
    }
})
Copy the code

Note :RouteRecordRaw is a built-in type

3. In main.ts, introduce createPinia

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
Copy the code

The basic use

1. Access to the state
  • Direct access to
<template>
    <div>{{userStore.name}}</div>
</template>
<script setup lang="ts">
import { useUserStore } from "@/store/user.ts"
const userStore = useUserStore()

</script>
Copy the code
  • The computed for
<template>
    <div>{{name}}</div>
</template>
<script setup lang="ts">
import { useUserStore } from "@/store/user.ts"
const userStore = useUserStore()
const name=computed(() = >{
    userStore.name
})
</script>
Copy the code
  • Structure, but will not be responsive, need to use storeToRefs
<template>
    <div>{{name}}</div>
</template>
<script setup lang="ts">
import { useUserStore } from "@/store/user.ts"
import {storeToRefs} from 'pinia'
const userStore = useUserStore()
const name=storeToRefs(userStore)
</script>
Copy the code
2. Set up the state
  • Directly modifying
<template>
    <div>{{userStore.name}}</div>
    <div @click="updateName">Modify the name</div>
</template>
<script setup lang="ts">
import { useUserStore } from "@/store/user.ts"
const userStore = useUserStore()
const updateName = () = > {
    userStore.name = 'Directly modified name'
}
</script>
Copy the code
  • $patch Modifies data in the store
<template>
    <div>{{userStore.name}}</div>
    <div @click="updateName">Modify the name</div>
</template>
<script setup lang="ts">
import { useUserStore } from "@/store/user.ts"
const userStore = useUserStore()
const updateName = () = > {
    userStore.$patch({
       name: '$patch modified name '})}</script>
Copy the code
  • Actions Modifies data in the store
<template>
    <div>{{userStore.name}}</div>
    <div @click="updateName">Modify the name</div>
</template>
<script setup lang="ts">
import { useUserStore } from "@/store/user.ts"
const userStore = useUserStore()
const updateName = () = > {
    userStore.updataUser('Actions changed name')}</script>
Copy the code

Use this in actions to modify state data

import { defineStore } from 'pinia'

export const useUserStore = defineStore({
    id: 'user'.state: () = > ({
        name: 'Username'
    }),
    getters: {
        nameLength: (state) = > state.name.length,
    },
    actions: {
        updataUser(newName: string) {
           this.name=newName
        }
    }
})
Copy the code
3. Use Getters
import { defineStore } from 'pinia'

export const useUserStore = defineStore({
    id: 'user'.state: () = > ({
        name: 'Username'
    }),
    getters: {
        nameLength: (state) = > state.name.length,
    },
})
Copy the code
<template>
    <div>{{userStore.nameLength}}</div>
</template>
Copy the code
4. Use the Actions
  • Sync actions using

If you use the same method in setting state, you can directly use this to set the data in state

  • Use asynchronous actions

Support async await. This can be used between actions in the same store. Hooks can be used between actions in different stores

import { defineStore } from 'pinia'
import {userOtherStore} from './otherStore'
export const useUserStore = defineStore({
    id: 'user'.state: () = > ({
        name: 'Username'
    }),
    actions: {
        async login(params){
            const {data}=await api.login(params)
            this.updataUser(data) // This can be used between actions in the same store
        },
        updataUser(newName: string) {
           this.name=newName
           const otherStore=userOtherStore() // Actions in different stores can be called using hooks
           otherStore.setName(newName)
        }
    }
})
Copy the code

4. Unified Request Encapsulation (Axios Encapsulation)

1. Use yarn to install axiOSCopy the code

Install yarn add axios

2. Under the SRC folder, create the service folder, and under the service folder, create http.ts

import axios, { AxiosRequestConfig } from 'axios'
// Set the request header and request path
axios.defaults.baseURL = '/api';
// Now, all requests using this instance will wait 2.5 seconds before they time out
axios.defaults.timeout = 2500;
axios.defaults.headers.post['Content-Type'] = 'application/json; charset=UTF-8';


// Add request interceptor
axios.interceptors.request.use(function (config) :AxiosRequestConfig<any> {
    // What to do before sending the request
    config.headers.token = 'your token'
    return config;
}, function (error) {
    // What to do about the request error
    return Promise.reject(error);
});

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // all status codes in the 2xx range trigger this function.
    // What to do with the response data
    return response;
}, function (error) {
    // Any status code outside the 2xx range triggers this function.
    // Do something about the response error
    return Promise.reject(error);
});
interface ResType<T> {
    code: number data? : Tmsg: 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) = > {
            axios
                .get(url, { params })
                .then((res) = > {
                    resolve(res.data)
                })
                .catch((err) = > {
                    reject(err.data)
                })
        })
    },
    post(url, params) {
        return new Promise((resolve, reject) = > {
            axios
                .post(url, JSON.stringify(params))
                .then((res) = > {
                    resolve(res.data)
                })
                .catch((err) = > {
                    reject(err.data)
                })
        })
    },
    upload(url, file) {
        return new Promise((resolve, reject) = > {
            axios
                .post(url, file, {
                    headers: { 'Content-Type': 'multipart/form-data' },
                })
                .then((res) = > {
                    resolve(res.data)
                })
                .catch((err) = > {
                    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
Copy the code

3. Create an API folder under the service folder to manage requests in a unified manner. Create login under API and login.ts and type.ts under login

  • The directory structure

  • login.ts
import http from '@/service/http'
import { ILoginApi } from './type'
const loginApi: ILoginApi = {
    login(params) {
        return http.post('/login', params)
    }
}
Copy the code
  • type.ts
export interface DataType {
    name: string
}
export interface ResType<T> {
    code: number data? : Tmsg: string err? : string }export interface ILoginApiParams {
    id: number
}
export interface ILoginApi {
    login: (params: ILoginApiParams) = > Promise<ResType<DataType>>
}
Copy the code

5. UI Component Library (Naive UI, Ant Design Vue, Element Plus)

At present, there are many choices of UI component libraries. Naive UI is a component library recommended by Naive UI. The content style is beautiful and novel, but it is a new component library after all. Some of the most popular open source backend, vben-Admin, use Ant Design Vue. As for Element Plus, it has just been developed, so it is more reasonable to choose Ant Design Vue.

The basic configuration

1. Use YARN to install ant-design-vue@next

Install yarn add ant-design-vue@next

2. Global registration in main.ts

import { createApp } from 'vue'
import App from './App.vue'
import router from './router/index'
import { createPinia } from 'pinia'
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';

const app = createApp(App)
app.use(createPinia())
app.use(router)
app.use(Antd);
app.mount('#app')
Copy the code

3. Use within components


<template>
    <div :style="{ background: 'rgb(190, 200, 200)', padding: '26px 16px 16px' }">
        <a-button type="primary" ghost>Primary</a-button>
        <a-button ghost>Default</a-button>
        <a-button type="dashed" ghost>Dashed</a-button>
        <a-button danger ghost>Danger</a-button>
        <a-button type="link" ghost>Link</a-button>
    </div><! --<img alt="Vue logo" src="./assets/logo.png" />
    <HelloWorld msg="Hello Vue 3 + TypeScript + Vite" />-->
</template>
Copy the code

Vi. Environment variable configuration and vite basic configuration

Environment Variable Configuration

  1. The outermost file location is created.env.developmentand.env.productionfile

.env.development

NODE_ENV=development

VITE_APP_WEB_URL= 'YOUR WEB URL'
Copy the code

.env.production

NODE_ENV=production

VITE_APP_WEB_URL= 'YOUR WEB URL'
Copy the code

2. Console. Log (import.meta.env.vite_app_web_URL)

Vite environment configuration

1. Configure the type alias

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: {
            The '@': path.resolve(__dirname, 'src'),}}})Copy the code

If path reports an error, install @types/node

2. Introduce global styles such as SCSS

export default defineConfig({
    plugins: [vue()],
    css: {
        preprocessorOptions: {
            scss: {
                additionalData: '@import "@/assets/style/main.scss"; '}}}})Copy the code

3. Configure the proxy

server: {
      port: VITE_PORT,
      // Load proxy configuration from .env
      proxy: {},},Copy the code

4. Dependencies that are forced out of the prebuild.

optimizeDeps: {
      // @iconify/iconify: The dependency is dynamically and virtually loaded by @purge-icons/generated, so it needs to be specified explicitly
      include: [
        '@iconify/iconify'.'ant-design-vue/es/locale/zh_CN'.'moment/dist/locale/zh-cn'.'ant-design-vue/es/locale/en_US'.'moment/dist/locale/eu',].exclude: ['vue-demi'],},Copy the code

5. Build package

 build: {
      target: 'es2015'.outDir: OUTPUT_DIR,
      terserOptions: {
        compress: {
          keep_infinity: true.// The production environment removes the console debugger value to a Boolean value
          drop_console: VITE_DROP_CONSOLE, 
          drop_debugger: VITE_DROP_DEBUGGER 
        },
      },
      // Turning off brotliSize display can slightly reduce packaging time
      brotliSize: false.chunkSizeWarningLimit: 1500,},Copy the code

Vben-admin inside the framework configuration to do a detailed interpretation, especially vite configuration

Hand vben – admin

Write in the end: this article is just my learning record, there may be many problems and imperfect place, welcome you big boss criticism and correction, the opportunity will continue to update the content, in addition to thank big @ front-end small dish chicken chicken pecking article inspiration and guidance, we can also go to read big guy article address