Create a project

# yarn & npm
yarn create @vitejs/app
npm init @vitejs/app
Copy the code

The project structure

When vite is created, the project directory structure is as follows. Vite.config. ts is the configuration file of vite project. Vite supports VUE in the form of plug-ins

To use TS, you need to install the type declaration file

# yarn && npm
yarn add -D @types/node
npm install -D @types/node
Copy the code
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

export default defineConfig({
  plugins: [vue()] // The introduced vue plug-in
})
Copy the code

TypeScript configuration file changes

Ts folder alias set, project folder create types folder for project declaration define TS declaration and interface, add project text path and file support in tsconfig.json

// tsconfig.json{... .'baseUrl': '. '.// Base directory
    'paths': {
      '@ / *': ['src/*'].// SRC /* Alias Settings
      '# / *': ['types/*'] // types/* Alias Settings}},'include': [...'types/**.ts'.// Add types/**.ts directory file dependencies
    'types/**.d.ts' // Add types/**.d.ts directory file dependencies]}// vite.config.ts
import { defineConfig } from 'vite'
import { resolve } from 'path'.export defaultdefineConfig({ ... .resolve: {
    // Configure the alias
    alias: {
      The '@': resolve(__dirname, './src'),
      The '#': resolve(__dirname, './types'),}}})Copy the code

Axios support

Install axios

# yarn && npm
yarn add axios
npm install --save axios
Copy the code

SRC/utils/ HTTP/utils/ HTTP/utils/ HTTP/utils/ HTTP/utils/ HTTP/utils/ HTTP/utils/ HTTP/utils

# loadsh-es 
yarn add -S loadsh-es && yarn add -D @types/loadsh-es
npm install --save loadsh-es && npm install --save-dev @types/loadsh-es
Copy the code

2. The Types directory starts by creating axios requests for customizable interfaces

export interface CustomResqusetOptions {
  // Customize the request setting parametersjoinTime? :boolean
}

export interface CustomResponseResult {
  // Customize the returned parametersdata? :any[]}Copy the code

3, implement index.ts and axios.ts

// axios.ts
import type { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'
import type { CustomResqusetOptions, CustomResponseResult } from '#/axios'
import axios from 'axios'
import { cloneDeep, isFunction } from 'lodash-es'

export interface CreateAxiosConfig extendsAxiosRequestConfig { transform? : AxiosTransform customResquestOptions? : CustomResqusetOptions }// Abstract interface
export abstract class AxiosTransform { beforeRequestHook? :(config: AxiosRequestConfig, options: CustomResqusetOptions) = >AxiosRequestConfig requestInterceptor? :(config: AxiosRequestConfig, options: CreateAxiosConfig) = >AxiosRequestConfig transformResponseHook? :(res: AxiosResponse<any>, options: CustomResqusetOptions) = > AxiosResponse<any> | anyresqonseInterceptors? :(res: AxiosResponse<any>, options: CreateAxiosConfig) = > AxiosResponse<any> | Promise<AxiosResponse<any>> | any
}

// Create an Axios class that internally implements the hook functions that request the interceptor, respond to the interceptor execution timing, and create classes using the singleton pattern
export class Aixos {
  private axiosInstance: AxiosInstance
  private readonly options: CreateAxiosConfig

  constructor(options: CreateAxiosConfig) {
    this.options = options
    this.axiosInstance = axios.create()
    this.setup()
  }

  private setup() {
    const transform = this.getTransform()
    if(! transform)return

    const { requestInterceptor, resqonseInterceptors } = transform

    // Request interceptor
    this.axiosInstance.interceptors.request.use((config) = > {
      // Add additional priority processing logic

      / / the interceptor
      if (requestInterceptor && typeof isFunction(requestInterceptor)) {
        config = requestInterceptor(config, this.options)
      }
      return config
    })
    // Response interceptor
    this.axiosInstance.interceptors.response.use((res) = > {
      if (resqonseInterceptors && isFunction(resqonseInterceptors))
        res = resqonseInterceptors(res, this.options)
      return res
    })
  }

  private getTransform() {
    const { transform } = this.options
    return transform
  }

  getAxios() {
    return this.axiosInstance
  }

  configAxios(config: CreateAxiosConfig) {
    if (!this.axiosInstance) return
    this.axiosInstance = axios.create(config)
  }

  setHeader(header? :any) {
    if (!this.axiosInstance) return
    Object.assign(this.axiosInstance.defaults.headers, header)
  }

  request<T = any>(config: AxiosRequestConfig, options? : CustomResqusetOptions):Promise<T> {

    let conf: CreateAxiosConfig = cloneDeep(config)
    const { customResquestOptions } = this.options
    let opt: CustomResqusetOptions = Object.assign({}, customResquestOptions, options) // Merge default Settings with incoming configurations
    const transform = this.getTransform()
    const { beforeRequestHook, transformResponseHook } = transform || {}
    // The hook function
    if (beforeRequestHook && isFunction(beforeRequestHook)) {
      conf = beforeRequestHook(config, opt)
    }

    conf.customResquestOptions = opt // Merge the configuration
    // Add some common processing logic here

    return new Promise((reslove, reject) = > {
      this.axiosInstance
        .request<any, AxiosResponse<CustomResponseResult>>(conf)
        .then((res: AxiosResponse<CustomResponseResult>) = > {
          if (transformResponseHook && isFunction(transformResponseHook)) {
            try {
              const transformResponse = transformResponseHook(res)
              reslove(transformResponse)
            }
            catch (err) {
              reject(err)
            }
            return
          }
        }).catch((e: Error) = > reject(e))
    })
  }

  get<T = any>(config: AxiosRequestConfig, options? : CustomResqusetOptions):Promise<T> {
    return this.request({ ... config,method: 'GET' }, options)
  }

  psot<T = any>(config: AxiosRequestConfig, options? : CustomResqusetOptions):Promise<T> {
    return this.request({ ... config,method: 'POST' }, options)
  }

  put<T = any>(config: AxiosRequestConfig, options? : CustomResqusetOptions):Promise<T> {
    return this.request({ ... config,method: 'PUT' }, options)
  }

  delete<T = any>(config: AxiosRequestConfig, options? : CustomResqusetOptions):Promise<T> {
    return this.request({ ... config,method: 'DELETE' }, options)
  }
}

// index.ts
import type { CreateAxiosConfig, AxiosTransform } from './aixos'
import type { CustomResqusetOptions } from '#/axios'

import { Aixos } from './aixos'
import { objectDeepMerge } from '@/utils'

const transform: AxiosTransform = {

  beforeRequestHook(config, options) {
    // The hook function before the request
    console.log(Hook function: transformResponseHook)
    return config
  },
  transformResponseHook(res, options) {
    // Respond to the intercepting hook function
    console.log('4. Hook function: transformResponseHook')
    return res
  },
  requestInterceptor(config, options) {
    // Request interception
    console.log('requestInterceptor')
    return config
  },
  resqonseInterceptors(res) {
    // Response interception
    console.log('resqonseInterceptors')
    return res
  },
}

export const customDefaultOptins: CustomResqusetOptions | CreateAxiosConfig = {
  transform, / / to the transform
  joinTime: true
}

export function createAxios(opt? : CreateAxiosConfig) {
  return new Aixos(objectDeepMerge(customDefaultOptins, opt || {})) // Merge the configuration
}

export const defHttp = createAxios({})
Copy the code

Create index.ts under utils and write objectDeepMerge

// utils/index.ts
import { isObject } from 'lodash-es'

export function objectDeepMerge<T = any> (src: any = {}, target: any = {}) :T {
  let key: string
  for (key in target) {
    src[key] = isObject(src[key]) ? objectDeepMerge(src[key], target[key]) : (src[key] = target[key])
  }
  return src
}
Copy the code

ENOTSUP: Operation not supported on socket, read

The requested development server interface returns 500 result

vue-router

Install vue-Router. Vue-router4 has not been converted to the official version, so we need to add next

# yarn & npm
yarn add vue-router@next
npm install --save vue-router@next
Copy the code

Create a router folder in SRC and create index.ts

// router/index.ts
import { createRouter, createWebHashHistory } from 'vue-router'

const mainRoutes: RouteRecordRaw[] = [
{
 name: 'Home'.path: '/home'.component: () = > import('@/views/Home.vue'),
 meta: {
   title: 'home'}}]export const router = createRouter({
history: createWebHashHistory(),
routes: mainRoutes
})

export function setupRouter(app: App<Element>) {
app.use(router)
}


Copy the code
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { router, setupRouter } from './router'

async function bootstrap() {

const app = createApp(App)

// Add additional logic

setupRouter(app)

await router.isReady()

app.mount('#app'.true)}void bootstrap()
Copy the code

vuex

1. Add vuex

# yarn & npm
yarn add vuex@next
npm install --save vuex@next
Copy the code

2. Create a store in the SRC directory

// store.ts
import type { App } from 'vue'
import { createStore } from 'vuex'

export const store = createStore({
state: {
 sidebarOpen: false
},
mutations: {
 SET_SIDEBAR(state: any){ state.sidebarOpen = ! state.sidebarOpenlocalStorage.setItem('SIDEBAR_OPEN', state.sidebarOpen.toString())
 },
 GET_SIDEBAR(state: any) {
   const rSidebarOpen = localStorage.getItem('SIDEBAR_OPEN')
   if (rSidebarOpen) {
     state.sidebarOpen = rSidebarOpen === 'true' ? true : false}}},actions: {
 set({ commit }) {
   commit('SET_SIDEBAR')},get({ commit }) {
   commit('GET_SIDEBAR')}}})export function setupStore(app: App<Element>) {
app.use(store)
}
Copy the code
// Home.vue
<template>
<h2>{{ store.state.sidebarOpen }}</h2>
<button style='width: 30pxheight: 20px' @click='store.dispatch('set')'></button>
</template>

<script setup lang='ts'>
import { useStore } from 'vuex'
const store = useStore()

</script>
Copy the code

less

1. Install less. Vite supports CSS preprocessing without installing less-Loader

# yarn & npm
yarn add less -D
npm install --save-dev less 
Copy the code

2, test,

// global import
// styles/index.less
@import 'variables.less' // Introduce global variables

h2 {
background-color: red
}
Copy the code
// mian.ts
import '@styles/index.less' // global import
Copy the code

sass

1, install SASS, Vite native support CSS preprocessing, do not need to install sass- Loader

# yarn & npm
yarn add sass -D
npm install --save-dev sass
Copy the code

2, test,

// styles/index.scss
@import 'variables.sass'// add global h2 {background-color: red
}
Copy the code
// mian.ts
import '@styles/index.scss' // global import
Copy the code

stylus

1, install stylus, Vite native already supports CSS preprocessing, do not need to install stylus-Loader

# yarn & npm
yarn add stylus -D
npm install --save-dev stylus
Copy the code

2, test,

// styles/index.styl
@import 'variables.styl'  // Introduce global variables

h2 {
background-color: red
}
Copy the code
// mian.ts
import '@styles/index.styl' // global import
Copy the code

mock

Install viet-plugin-mock and mockJS

# yarn && npm
yarn add -D vite-plugin-mock mockjs
npm install --save-dev vite-plugin-mock mockjs
Copy the code

2. Import the vite configuration file vite-config.ts and configure the plug-in

// vite-config.ts
import { defineConfig } from 'vite'
import { viteMockServe } from 'vite-plugin-mock'

export default defineConfig({
  plugins: [
	...,
    viteMockServe({
      ignore: / ^ \ _ /.// Ignore the _ file
      mockPath: 'mock'.// Mock folder
      supportTs: true,})],... ,})Copy the code

3. Mock

// mock/index.ts
import { MockMethod } from 'vite-plugin-mock'

export default[{url: '/'.method: 'get'.response: () = > {
      return {
        code: 20000.msg: 'success'.'data': ['Hello Mock'],})},},]as MockMethod[]


Copy the code

4. Test it out

// api/home.ts
import { defHttp } from '@/utils/http'

enum API {
 HOME = '/home'
}

export function getHome() {
 return defHttp.get({ url: API.HOME })
}
Copy the code
// view/Home.vue <template> <h2>{{ msg }}</h2> </template> <script setup lang='ts'> import { getHome } from '@/api/home'  import { ref } from '@vue/reactivity' const msg = ref(null) getHome().then(res => { home.value = res.data.data }) </script>Copy the code
// App.vue

<template>
 <HomeVue></HomeVue>
</template>

<script setup lang='ts'>
import HomeVue from './views/Home.vue'
 
</script>
Copy the code

The environment variable

1. Create environment variable files.env.development and.env.production in the project directory

// .env.development
VITE_APP_ENV = 'development'

// .env.production
VITE_APP_ENV = 'production'
Copy the code

2. Modify package.json configuration

//package.json. .'scripts': {
  'dev': 'cross-env NODE_ENV=development vite'.'build': 'vite build'.'build:dev': 'vite build --mode development'.'build:pro': 'vite build --mode production'},... .Copy the code

Integrate the Vant component library

Install dependencies

yarn add vant@next
npm install --save vant@next
Copy the code

The Vite version does not require the on-demand loading of configuration components, because all modules within Vant 3 are written based on ESM and naturally have the ability to be imported on demand, but styles must be imported entirely.

Create new ant. Ts in the plugins directory

import type { App } from 'vue'
import Vant from 'vant'
import 'vant/lib/index.css'

export function setupVant (app:App<Element>) {
  app.use(Vant)
}
Copy the code

Modify the main ts

// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { router, setupRouter } from './router'
import { setupStore } from './store'
import { setupVant } from 'plugins/vant'

async function bootstrap() {
  const app = createApp(App)
  / / mount stroe
  setupStore(app)
  // Add additional logic
  setupVant(app)
  / / mount the router
  setupRouter(app)
  await router.isReady()
  app.mount('#app'.true)}void bootstrap()
Copy the code

Integrate eslint, Prettier specification code

Install dependencies

yarn add babel-eslint -D
yarn add @vue/eslint-config-prettier -D
yarn add eslint -D
yarn add eslint-define-config -D
yarn add eslint-plugin-prettier -D
yarn add eslint-plugin-vue -D
yarn add prettier -D
Copy the code

Create.eslintrc.js in the root directory

//.eslintrc.js
module.exports = {
  root: true.env: {
    node: true,},extends: ['plugin:vue/vue3-essential'.'eslint:recommended'].parserOptions: {
    parser: 'babel-eslint',},rules: {
    // Write rules here
    'no-unused-vars': 0.// Define unused variables}},Copy the code

Create.prettierrc.json in the root directory

// .prettierrc.json
{
  // Fill in the rules here
  'singleQuote': true./ / single quotation marks
  'seme': true./ / a semicolon
  'tabWidth': 2./ / the indentation
  'TrailingCooma': 'all'.// The trailing element has a comma
  'bracketSpacing': true.// Whitespace in the object
}
Copy the code

This is combined with vscode’s save automatic formatting

 // .vscode/settings.json
'editor.formatOnSave': true.// Format when saving
'files.autoSave': 'onFocusChange'.// Save when you lose focus
'editor.codeActionsOnSave': {
  'source.fixAll.eslint': true
},
'eslint.validate': [
  'javascript'.'javascriptreact'.'typescript'].Copy the code

Configure GZIP compression

Install dependencies

Yarn add vite-plugin-compression -d Copy the codeCopy the code

Modify the vite. Config. Js

// vite.config.js

import viteCompression from 'vite-plugin-compression'
plugins:[
  ...,
  viteCompression({
      verbose: true.disable: false.threshold: 10240.algorithm: 'gzip'.ext: '.gz'})]Copy the code

Deployment of release

Run the corresponding command

'dev': 'cross-env NODE_ENV=development vite'.'serve': 'vite preview'.'build:dev': 'vite build --mode development'.'build:pro': 'vite build --mode production'
Copy the code

The project address

Github.com/frezs/vite-…