“What will be hot and what to learn in 2022? This article is participating in the” Talk about 2022 Technology Trends “essay campaign.
π Basic template based on Vite2 + Vue3.2 + TypeScript + Pinia + Mock + sass + vantUI + Viewport adaptation + AXIos encapsulation
You are advised to view demo on a mobile phone
The foregoing
-
Vuecli project address: github.com/ynzy/vue3-h…
-
Vite-vue project address: github.com/ynzy/vite-v…
-
I wrote a template project with Vuecli a year ago when vue3 was just released. The article address is: Build mobile template scaffolding based on vue3 +TypeScript+ VUUE-Cli4.0
-
Last year, vite, a new work by The University of Utah, became a hit. I spent 8 nights writing 2-3 hours each night to reconstruct my template project during my off-hours.
-
I think it’s 2022. Vite’s a hit.
-
Used vite all say really sweet, in the end how sweet. Let’s take a look at the comparison of refactoring startup speed, hot update speed, and packaging speed
Development startup speed comparison
-
vue-cli
- Waiting for a few seconds
-
vite-vue
- Almost no waiting
- Summary: Vite starts up 5 times faster than VUE-CLI!
Develop hot update speed comparison
-
vue-cli
- You need to recompile the file
-
vite-vue
- It took almost no time for the code changes to take effect
- Summary: Vite is effective immediately
Production packaging speed comparison
- vue-cliΒ
- vite-vueΒ
- Conclusion: Hardly any difference
conclusion
- Vite in the development environment, greatly improve the development efficiency, really fragrant law!
- Now let’s refactor the project.
Project introduction
Node Version Requirements
This example is Node.js v17.2.0
Project installation/startup
- This project uses PNPM package manager, if not, please install PNPM first
- Use another package manager please delete
pnpm-lock.yaml
npm i -g pnpm // Install PNPM globally
pnpm install // Install dependencies
pnpm dev / / development
pnpm build / / packaging
pnpm preview // Preview the packaged project locally
Copy the code
directory
- β Initialize the project with create-vue
- β Configure IP access items
- β Configure multiple environment variables
- β Configure the alias
- β Sass global style
- Tick the Vue – the router
- β Pinia Status management
- β Use Mock data
- β Configure proxy across domains
- β Static resource usage
- β Axios encapsulation and interface management
- β Vue-request Management interface
- β Automatic import
- β Load VantUI components as required
- β Viewport Adaptation solution
- β Fit apple bottom safe distance
- β Dynamically set title
- Square root configuration Jssdk
- β Eslint + Prettier Unified development specification
- β HusKY + Lint-Staged submitted validations
- β Project packaging optimization
β initializes the project with create-vue
- Documents: github.com/vuejs/creat…
- To manually build a vite base template from 0 to 1, see vite-vue3-template
createVue
npm init vue@3True.js - The Progressive JavaScript Framework β€ Project Name:... Vite - vue3 - h5 - template β Add TypeScript? ... Yes stocking Add JSX Support? ... Right β€ Add Vue RouterforSingle Page Application development? ... Yes β Add Piniaforstate management? ... Yes β Add Cypressfortesting? ... No β Add ESLintforcode quality? ... Yes β Add Prettierforcode formatting? ... YesCopy the code
- Initializing the project contains
- Vite
- Vue3.2
- Vue-router4
- TypeScript
- Jsx
- Pinia
- Eslint
- Prettier
- @types/node // Identify the nodeJS built-in module
Bring back to the top
β Configure IP address access items
- “Network: Use –host to Expose” appears after Vite boots
vite v23.7. dev server running at:
> Local: http://localhost:3000/
> Network: use `--host` to expose
Copy the code
- The IP address is not configured, so the server cannot be started from the IP address. You need to configure the server to 0.0.0.0 in viet.config. js
export default defineConfig({
plugins: [vue()],
// Add the following content to the file
server: {
host: '0.0.0.0'}})Copy the code
- Displayed after the restart
vite v23.7. dev server running at:
> Local: http://localhost:3000/
> Network: http:/ / 192.168.199.127:3000 /
Copy the code
Bring back to the top
β Configure multiple environment variables
- Documents: cn. Vitejs. Dev/guide/env – a…
- In a production environment, the value of import.meta.env is converted to the corresponding value
- Add environment variable files, each file writes configuration, define env environment variables must be preceded by VITE_
.env.development
# must start with VITE_
VITE_ENV = 'development'
VITE_OUTPUT_DIR = 'dev'
Copy the code
.env.production
# must start with VITE_
VITE_ENV = 'production'
VITE_OUTPUT_DIR = 'dist'
Copy the code
.env.test
# must start with VITE_
VITE_ENV = 'test'
VITE_OUTPUT_DIR = 'test'
Copy the code
- Modify scripts command
--mode
To identify our environment
"dev": "vite --mode development"."test": "vite --mode test"."prod": "vite --mode production".Copy the code
- Access in the project
console.log(import.meta.env)
Copy the code
- Typescript smart tips
- Modify the
src/env.d.ts
File if one is not created
/// <reference types="vite/client" />
interface ImportMetaEnv extends Readonly<Record<string, string>> {
readonly VITE_ENV: string; / / environment
readonly VITE_OUTPUT_DIR: string; // Package directory
}
interface ImportMeta {
readonly env: ImportMetaEnv;
}
Copy the code
Dynamic import environment configuration
// config/env.development.ts
// Local environment configuration
export default {
env: 'development'.mock: true.title: 'development'.baseUrl: 'http://localhost:9018'.// Project address
baseApi: 'https://test.xxx.com/api'.// Local API request address, note: if you use proxy, please set to '/'
APPID: 'wx9790364d20b47d95'.APPSECRET: 'xxx'.$cdn: 'https://imgs.solui.cn'
}
Copy the code
// config/index.ts
export interface IConfig {
env: string // Development environmentmock? :string / / the mock data
title: string / / project titlebaseUrl? :string // Project addressbaseApi? :string // the API requests the addressAPPID? :string // Public appId is usually stored on the server sideAPPSECRET? :string // The public account appScript is stored on the server side
$cdn: string // CDN public resource path
}
const envMap = {}
const globalModules = import.meta.globEager('./*.ts')
Object.entries(globalModules).forEach(([key, value]) = > {
// key.match(/\.\/env\.(\S*)\.ts/)
const name = key.replace(/\.\/env\.(.*)\.ts$/.'$1')
envMap[name] = value
})
// Introduce different configurations depending on the environment
export const config = envMap[import.meta.env.VITE_ENV].default
console.log('Introduce different configurations depending on the environment', config)
Copy the code
Bring back to the top
β Configure the alias
- A SRC alias has been configured for project initialization
import { fileURLToPath } from 'url'
resolve: {
alias: {
The '@': fileURLToPath(new URL('./src'.import.meta.url))
}
},
Copy the code
Bring back to the top
β Sass global style
- Documents: cn. Vitejs. Dev/guide/featu…
- Install dependent use
dart-sass
, the installation speed is relatively fast, and there is a high probability that the installation will not fail
pnpm i -D sass
Copy the code
- Each page’s own style is written in its own.vue file
scoped
It adds the concept of a domain to CSS as the name suggests.
<style lang="scss">
/* global styles */
</style>
<style lang="scss" scoped>
/* local styles */
</style>
Copy the code
css modules
- Currently, tests can only be used in TSX, vue-template can be imported and used in JS,
<template>
Don’t know how to use it yet - To define a
*.module.scss
or*.module.css
file - Used in TSX
import { defineComponent } from 'vue'
import classes from '@/styles/test.module.scss'
export default defineComponent({
setup() {
console.log(classes)
return () = > {
return <div class={`rootThe ${classes.moduleClass} `} >Test the CSS - modules</div>}}})Copy the code
Vite recognizes sASS global variables
- Documents: cn. Vitejs. Dev/config / # CSS…
- Vite.config.js adds the configuration
css: {
preprocessorOptions: {
scss: {
additionalData: ` @import "@/styles/mixin.scss"; @import "@/styles/variables.scss"; `,}}},Copy the code
Bring back to the top
β Vue – router4
- Documents: next.router.vuejs.org/zh/installa…
- Composition – API used: next.router.vuejs.org/zh/guide/ad…
- The initialization project integrates vue-Router. We will only do configuration here
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
import { routes } from './router.config'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes
})
export default router
Copy the code
// router/router.config.ts
import { RouteRecordRaw, createRouter, createWebHistory } from 'vue-router'
import Layout from '@/views/layouts/index.vue'
export const routes: Array<RouteRecordRaw> = [
{
path: '/'.name: 'Home'.redirect: '/home'.meta: {
title: 'home'.keepAlive: false
},
component: Layout,
children: [{path: '/home'.name: 'Home'.component: () = > import('@/views/Home.vue'),
meta: { title: 'home'.keepAlive: false.showTab: true}}, {path: '/tsx'.name: 'Tsx'.component: () = > import('@/test/demo'),
meta: { title: 'test TSX'.keepAlive: false.showTab: true}}, {path: '/static'.name: 'Static'.component: () = > import('@/test/testStatic.vue'),
meta: { title: 'Testing static Resources'.keepAlive: false.showTab: true}}, {path: '/cssModel'.name: 'CssModel'.component: () = > import('@/test/testCssModel'),
meta: { title: 'test CSS - model'.keepAlive: false.showTab: true}}, {path: '/mockAxios'.name: 'MockAxios'.component: () = > import('@/test/testMockAxios'),
meta: { title: 'test the mock - axios'.keepAlive: false.showTab: true}}, {path: '/pinia'.name: 'Pinia'.component: () = > import('@/test/testPinia.vue'),
meta: { title: 'test pinia'.keepAlive: false.showTab: true}}]}]Copy the code
Bring back to the top
β Pinia Status management
- The initialization project integrates pinia, and we will only do configuration here
- Documents: pinia.vuejs.org/
- Reference: juejin.cn/post/704919…
- Pinia features:
- Full typescript support;
- Lightweight enough, compressed volume is only 1.6KB;
- Remove mutations, only state, getters, actions (one of my favorite features);
- Actions support synchronous and asynchronous;
- There is no module nesting, only the concept of stores, stores can be used freely, better code segmentation;
- There is no need to manually add stores, stores are automatically added once created;
Install dependencies
pnpm i pinia
Copy the code
Create the Store
- Create a SRC /store directory and create index.ts under it to export store
// src/store/index.ts
import { createPinia } from 'pinia'
const store = createPinia()
export default store
Copy the code
Introduced and used in main.ts
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import store from './store'
const app = createApp(App)
app.use(store)
Copy the code
Define the State
- Create a user.ts under SRC /store
//src/store/user.ts
import { defineStore } from 'pinia'
import { useAppStore } from './app'
export const useUserStore = defineStore({
id: 'user'.state: () = > {
return {
name: 'Joe'.age: 18}},getters: {
fullName: (state) = > {
return state.name + 'company'}},actions: {
updateState(data: any) {
this.$state = data
this.updateAppConfig()
},
updateAppConfig() {
const appStore = useAppStore()
appStore.setData('app-update')}}})Copy the code
//src/store/app.ts
import { defineStore } from 'pinia'
export const useAppStore = defineStore({
id: 'app'.state: () = > {
return {
config: 'app'}},actions: {
setData(data: any) {
console.log(data)
this.config = data
}
}
})
Copy the code
Get/update State
<script setup lang="ts"> import { useUserStore } from '@/store/user' import { useAppStore } from '@/store/app' import { storeToRefs } from 'pinia' import { computed } from 'vue' const userStore = useUserStore() const appStore = useAppStore() console.log(appStore.config) console.log(userStore) console.log(userStore.name) const name = computed(() => userStore.name) const { age } = storeToRefs(userStore) const updateUserState = () => { const { name, age } = userStore.$state userStore.updateState({ name: name + 1, age: The age + 1})} < / script > < template > < div > name: {{name}} < / div > < div > age: {{age}} < / div > < div > computing's name: {{userstore. fullName}}</div> <div>app config: </div> <button @click="updateUserState"> </button> </template> <style lang=" SCSS" scoped></style>Copy the code
Data persistence
- Documents: github.com/prazdevs/pi…
-
Pinia-plugin-persistedstate can assist in data persistence.
-
Data is stored in sessionStorage by default, and the store ID is used as the key.
-
Install dependencies
pnpm i pinia-plugin-persistedstate
Copy the code
- The plug-in
// src/store/index.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const store = createPinia()
store.use(piniaPluginPersistedstate)
export default store
Copy the code
- Simply enable Persist in the corresponding store
export const useUserStore = defineStore({
id: 'user'.state: () = > {
return {
name: 'Joe'}},// Enable data caching
persist: {
key: 'user'.storage: sessionStorage, // Data storage location, localStorage by default
paths: ['name'].// Array of dot notation paths for partial persistent state, indicating that no state will be persisted (default and keep the entire state)
overwrite: true}})Copy the code
Bring back to the top
β Use Mock data
- Documents: github.com/vbenjs/vite…
- Mock data is currently tested and is valid in both XHR and FETCH in the development environment. In the production environment, it can only be invoked using the XHR type request library, and fetch does not take effect
1. Install dependencies
pnpm i -D vite-plugin-mock mockjs @types/mockjs
Copy the code
2. Production environment-related packaging
// mock/_createProductionServer.ts
import { createProdMockServer } from 'vite-plugin-mock/es/createProdMockServer'
const modules = import.meta.globEager('./**/*.ts')
const mockModules: any[] = []
Object.keys(modules).forEach((key) = > {
if (key.includes('/ _')) {
return} mockModules.push(... modules[key].default) })/** * Used in a production environment. Need to manually import all modules */
export function setupProdMockServer() {
createProdMockServer(mockModules)
}
Copy the code
// mock/_util.ts
// Interface data format used to return a unified format
import { Recordable } from 'vite-plugin-mock'
export function resultSuccess<T = Recordable> (result: T, { message = 'ok' } = {}) {
return {
code: 0,
result,
message,
type: 'success'}}export function resultPageSuccess<T = any> (
page: number,
pageSize: number,
list: T[],
{ message = 'ok' } = {}
) {
const pageData = pagination(page, pageSize, list)
return {
...resultSuccess({
items: pageData,
total: list.length
}),
message
}
}
export function resultError(message = 'Request failed', { code = -1, result = null } = {}) {
return {
code,
result,
message,
type: 'error'}}export function pagination<T = any> (pageNo: number, pageSize: number, array: T[]) :T[] {
const offset = (pageNo - 1) * Number(pageSize)
const ret =
offset + Number(pageSize) >= array.length
? array.slice(offset, array.length)
: array.slice(offset, offset + Number(pageSize))
return ret
}
export interface requestParams {
method: string
body: anyheaders? : { authorization? :string }
query: any
}
/ * * *@description This function is used to obtain tokens from the request data. Please modify * */ according to the actual situation of the project
export function getRequestToken({ headers }: requestParams) :string | undefined {
returnheaders? .authorization }Copy the code
// mock/sys/user
import { MockMethod } from 'vite-plugin-mock'
import { resultError, resultSuccess, getRequestToken, requestParams } from '.. /_util'
export default[{url: '/basic-api/getUserInfo'.method: 'get'.response: (request: requestParams) = > {
console.log('---- requested getUserInfo-- ')
return resultSuccess({
name: 'chapter three'.age: 40.sex: 'male'}}})as MockMethod[]
Copy the code
3. Modify the configuration of vite.config.ts
export default ({ mode, command }: ConfigEnv): UserConfigExport= > {
const isBuild = command === 'build'
return defineConfig({
plugins: [
viteMockServe({
ignore: / / ^ _.// Re matches ignored files
mockPath: 'mock'.// Set the mock. Ts file storage folder
localEnabled: true.// Set whether to enable the local xxx.ts file, do not open it in production. Setting it to false disables the mock feature
prodEnabled: true.// Set whether the mock function is enabled in the production environment
watchFiles: true.// Sets whether to monitor changes in files in the folder corresponding to mockPath
// Code injection
injectCode: ` import { setupProdMockServer } from '.. /mock/_createProductionServer'; setupProdMockServer(); `})]})}Copy the code
Bring back to the top
β Configure proxy across domains
server: {
host: '0.0.0.0'.proxy: {
// Short for string
'/foo': 'http://localhost:4567'.// This is an option
'/api': {
target: 'http://jsonplaceholder.typicode.com'.changeOrigin: true.rewrite: (path) = > path.replace(/^\/api/.' ')},// Regular expression
'^/fallback/.*': {
target: 'http://jsonplaceholder.typicode.com'.changeOrigin: true.rewrite: (path) = > path.replace(/^\/fallback/.' ')}// Use a proxy instance
// "/api": {
// target: "http://jsonplaceholder.typicode.com",
// changeOrigin: true,
// configure: (proxy, options) => {
// // proxy is an instance of 'http-proxy'
/ /},
// },}},Copy the code
Bring back to the top
β Axios encapsulation and interface management
Utils /request.js encapsulates AXIOS and developers need to make changes based on the background interface.
service.interceptors.request.use
Request headers can be set, such as Settingstoken
config.hideloading
It is set in the interface parameters in the API folder, as described belowservice.interceptors.response.use
In the interface can return data processing, such as 401 delete local information, login again
/ * * *@description [axios requests encapsulation] */
import store from '@/store'
import axios, { AxiosResponse, AxiosRequestConfig } from 'axios'
// import {Message, Modal} from 'view-design' // UI component library
import { Dialog, Toast } from 'vant'
import router from '@/router'
// Introduce different API addresses according to the environment
import config from '@/config'
const service = axios.create({
baseURL: config.baseApi + '/api'.// url = base url + request url
timeout: 5000.withCredentials: false // send cookies when cross-domain requests
// headers: {
// // clear cors
// 'Cache-Control': 'no-cache',
// Pragma: 'no-cache'
// }
})
// Request interceptors
service.interceptors.request.use(
(config: AxiosRequestConfig) = > {
// Load the animation
if (config.loading) {
Toast.loading({
message: 'Loading... '.forbidClick: true})}// Add request headers here, such as token
// if (store.state.token) {
// config.headers['Authorization'] = `Bearer ${store.state.token}`
// }
return config
},
(error: any) = > {
Promise.reject(error)
}
)
// Response interceptors
service.interceptors.response.use(
async (response: AxiosResponse) => {
// await new Promise(resovle => setTimeout(resovle, 3000))
Toast.clear()
const res = response.data
if(res.code ! = =0) {
/ / token expired
if (res.code === 401) {
// Warning window
return
}
if (res.code == 403) {
Dialog.alert({
title: 'warning'.message: res.msg
}).then(() = > {})
return
}
// If the background returns an error value, the corresponding error object is returned here, and the following error is received
return Promise.reject(new Error(res.msg || 'Error'))}else {
// Note the return value
return response.data
}
},
(error: any) = > {
Toast.clear()
if (error && error.response) {
switch (error.response.status) {
case 400:
error.message = 'Request error (400)'
break
case 401:
error.message = 'Not authorized, please log in to (401)'
break
case 403:
error.message = 'Access denied (403)'
break
case 404:
error.message = 'Error requesting address:${error.response.config.url}`
break
case 405:
error.message = 'Requested method not allowed (405)'
break
case 408:
error.message = 'Request timed out (408)'
break
case 500:
error.message = 'Server internal error (500)'
break
case 501:
error.message = 'Service Not realized (501)'
break
case 502:
error.message = 'Network Error (502)'
break
case 503:
error.message = 'Service unavailable (503)'
break
case 504:
error.message = 'Network Timeout (504)'
break
case 505:
error.message = 'HTTP version not supported (505)'
break
default:
error.message = 'Connection error:${error.message}`}}else {
if (error.message == 'Network Error') {
error.message == 'Network exception, please check and try again! '
}
error.message = 'Failed to connect to server, please contact administrator'
}
Toast(error.message)
// store.auth.clearAuth()
store.dispatch('clearAuth')
return Promise.reject(error)
}
)
export default service
Copy the code
Interface management
Unify the management interface in the SRC/API folder
- You can set up multiple module docking interfaces, such as
home.ts
Here is the interface of the home pageauthController.ts
url
Interface address, which will be concatenated when requestedconfig
Under thebaseApi
method
Request methoddata
Request parametersqs.stringify(params)
Is the data serialization operationloading
The defaultfalse
, is set totrue
Some interfaces in the loading UI interaction need to be perceived by the user
import request from '@/utils/request'
export interface IResponseType<P = {}> {
code: number
msg: string
data: P
}
interface IUserInfo {
id: string
avator: string
}
interface IError {
code: string
}
export const fetchUserInfo = () = > {
return request<IResponseType<IUserInfo>>({
url: '/user/info'.method: 'get'.loading: true})}Copy the code
How to call
Because the awaitWrap type derivation is cumbersome, try catch is used to catch errors, both interface errors and business logic errors
onMounted(async() = > {try {
let res = await fetchUserInfo()
console.log(res)
} catch (error) {
console.log(error)
}
})
Copy the code
Bring back to the top
β vue-request Management interface
- Documents: cn.attojs.org/
- Vue-request makes it easier to manage interfaces
1. Install dependencies
pnpm i vue-request
Copy the code
2. Use AXIos to obtain data and vue-Request for management
// axios
export const fetchUserInfo = () = > {
return request<IResponseType<IUserInfo>>({
url: '/user/info'.method: 'get'.loading: true})}// vue-request
const { data: res, run } = useRequest(fetchUserInfo)
// If the request is not completed, data is undefined. Use run to wait for the request to complete
await run()
console.log(res.value? .data)Copy the code
3. Use vue-request to make periodic requests
// axios
export const getTimingData = () = > {
return request({
url: '/getTimingData'.method: 'GET'})}// vue-request
const { data: resultData, run } = useRequest(getTimingData, {
pollingInterval: 5000.onSuccess: (data) = > {
console.log('onSuccess', data)
}
})
Copy the code
β unplugin-xxx Automatic import
- Reference: juejin.cn/post/701244…
- Custom components automatically introduce unplugin-vue-components
- Plugins such as vue3 automatically introduce unplugin-auto-import/vite
- Message, notification, etc. import styles automatically import viet-plugin-style-import
- Eslint plug-in vue – global – API
unplugin-vue-components
- Automatic import of popular library components and custom components
- Install dependencies
pnpm i -D unplugin-vue-components
Copy the code
- Modify the vite. Config. Ts
Components({
// Specify the location of the component, SRC /components by default
dirs: ['src/components'].// UI library parser
// resolvers: [ElementPlusResolver()],
extensions: ['vue'.'tsx'].// Configuration file generation location
dts: 'src/components.d.ts'.// Search for subdirectories
deep: true.// Allow subdirectories to be used as namespace prefixes for components.
directoryAsNamespace: false
// include:[]
}),
Copy the code
unplugin-auto-import
- Automatically import vuE3 apis
- Install dependencies
pnpm i -D unplugin-auto-import
Copy the code
- Configuration vite. Config. Ts
AutoImport({
include: [
/\.[tj]sx? $/.// .ts, .tsx, .js, .jsx
/\.vue$/./\.vue\? vue/.// .vue
/\.md$/ // .md].imports: ['vue'.'vue-router'.'@vueuse/core'].SRC /auto-import.d.ts' SRC /auto-import.d.ts'
dts: 'src/auto-import.d.ts'.// eslint globals Docs - https://eslint.org/docs/user-guide/configuring/language-options#specifying-globals
// Generate a global declaration file for esLint
eslintrc: {
enabled: true.// Default `false`
filepath: './.eslintrc-auto-import.json'.// Default `./.eslintrc-auto-import.json`
globalsPropValue: true // Default `true`, (true | false | 'readonly' | 'readable' | 'writable' | 'writeable')}})Copy the code
- Configuration eslintrc
// .eslintrc.js
module.exports = {
/ *... * /
extends: [
// ...
'./.eslintrc-auto-import.json',]}Copy the code
vue-global-api
- Use unplugin-auto-import/vite to automatically introduce hooks if not already introduced. The extends in eslintrc.js introduces vue- global-API. This plugin is supported by vue3hooks. Check for the rest. If you can’t find it, manually configure globals
- Install dependencies
pnpm i -D vue-global-api
Copy the code
- Configuration eslintrc
// .eslintrc.js
module.exports = {
extends: [
'vue-global-api']};Copy the code
β VantUI components are loaded on demand
- Documents: vant – contrib. Gitee. IO/vant/v3 / # / z…
1. Install dependencies
pnpm add vant@3
pnpm add vite-plugin-style-import -D
Copy the code
2. Import configurations as required
- vite.config.ts
import vue from '@vitejs/plugin-vue'
import styleImport, { VantResolve } from 'vite-plugin-style-import'
export default {
plugins: [
vue(),
styleImport({
resolves: [VantResolve()]
})
]
}
Copy the code
- plugins/vant.ts
import { App as VM } from 'vue'
import { Button, Cell, CellGroup, Icon, Tabbar, TabbarItem, Image as VanImage } from 'vant'
const plugins = [Button, Icon, Cell, CellGroup, Tabbar, TabbarItem, VanImage]
export const vantPlugins = {
install: function (vm: VM) {
plugins.forEach((item) = > {
vm.component(item.name, item)
})
}
}
Copy the code
- main.ts
// Global import Import UI library vant on demand
import { vantPlugins } from './plugins/vant'
app.use(vantPlugins)
Copy the code
In 3.
- If you use this method, you do not need to register the above
plugins/vant.ts
δΊ
<script setup>
import { Button } from 'vant';
</script>
<template>
<Button />
</template>
Copy the code
plugins/vant.ts
δΊ<script setup>
import { Button } from 'vant';
</script>
<template>
<Button />
</template>
Copy the code
4. Vant components can be used directly in JSX and TSX without component registration.
- If you use this method, you do not need to register the above
plugins/vant.ts
δΊ
import { Button } from 'vant'
export default {
render() {
return <Button />}}Copy the code
Bring back to the top
β Viewport adaptation solution
- see
lib-flexible
Lib-flexible is a transition option that can be abandoned because viewport units are compatible with many browsers. We recommend that you start using viewPort instead - Reference documents: blog.csdn.net/weixin_4642…
- Vant official document says how to match, first according to the official document to match
- Postcss-px-to-viewport Documentation: github.com/evrone/post…
1. Install dependencies
pnpm i -D postcss-px-to-viewport autoprefixer
Copy the code
2. Add. Postcssrc. Js
module.exports = {
plugins: {
-webkit-, -moz-, etc
autoprefixer: {
overrideBrowserslist: ['the Android 4.1'.'iOS 7.1'.'Chrome > 31'.'ff > 31'.'ie >= 8']},'postcss-px-to-viewport': {
unitToConvert: 'px'.// The unit to convert
viewportWidth: 375.// Width of UI design draft
unitPrecision: 6.// The precision of the conversion, i.e. the number of decimal places
propList: [The '*'].// Specify the unit of the CSS property to be converted. * indicates that all CSS properties are converted
viewportUnit: 'vw'.// Specify the window unit to convert to, default vw
fontViewportUnit: 'vw'.// Specify the window unit to convert the font to, default vw
selectorBlackList: ['wrap'].// Specify the class name that is not converted to window units,
minPixelValue: 1.// The default value is 1, and the conversion is not performed if the value is less than or equal to 1px
mediaQuery: true.// Whether the media query is also converted in the CSS code, the default is false
replace: true.// Whether to replace the attribute value directly after conversion
exclude: [/node_modules/].// Sets the file to be ignored and the re to match the directory name
landscape: false // Whether to handle landscape}}}Copy the code
Bring back to the top
β for Apple bottom safe distance
-
The meta of index.html specifies viewport-fit=cover
-
The bottom safe distance parameter comes with vant
<! Add meta tag to head tag and set viewport-fit=cover --><meta
name="viewport"
content="Width =device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover"
/><! -- Enable the top safety zone adaptation --><van-nav-bar safe-area-inset-top /><! -- Enable bottom safety zone adaptation --><van-number-keyboard safe-area-inset-bottom />
Copy the code
If you don’t use an adaptation in Vant, you can write it yourself. I wrote a generic style in SCSS
.fixIphonex {
padding-bottom: $safe-bottom ! important;
&::after {
content: ' ';
position: fixed;
bottom: 0 ! important;
left: 0;
height: calc(#{$safe-bottom} + 1px);
width: 100%;
background: #ffffff; }}Copy the code
Bring back to the top
β Dynamically sets the title
// utils/index.ts
import { config } from '@/config'
/** * Dynamically sets the browser title *@param title* /
export const setDocumentTitle = (title? : string) = > {
document.title = title || config.title
}
Copy the code
The router/index. Ts is used
router.beforeEach((to, from, next) = > {
setDocumentTitle(to.meta.title as string)
next()
})
Copy the code
Bring back to the top
β configuration Jssdk
- Installation:
yarn add weixin-js-sdk
Copy the code
The type declaration is written in model/ weixin-js-sdK.d. ts
Since Apple Browser only recognizes the route entered for the first time, you need to configure the URL used first
- router.ts
The JSSDK configuration here is for demonstration only. Normal service logic needs to be written with the back-end
Copy the code
import { defineStore } from 'pinia'
export interface ILinkState {
initLink: string
}
export const useAuthStore = defineStore({
id: 'auth'.// id must be unique
state: () = >
({
initLink: ' '
} as ILinkState),
actions: {
setInitLink(data: any) {
this.$state.initLink = data
},
setIsAuth(data) {
this.$state.isAuth = data
},
setCode(code) {
this.$state.code = code
}
},
// Enable data caching
persist: {
key: 'auth'.storage: window.localStorage,
// paths: ['name'],
overwrite: true}}Copy the code
Since the window does not have an entryUrl variable, you need to declare it in a declaration file
// typings/index.d.ts
declare interface Window {
entryUrl: any
}
Copy the code
Create the hooks function
hooks/useWxJsSdk.ts
UseWxJsSdk needs to be called once for each page that uses JSSDK, and then the other wrapped functions are used
Call:
Copy the code
Bring back to the top
β Eslint + Prettier Unified development specification
- The initialization project integrates ESLint + Prettier, so we just do configuration here
- .eslintrc.js
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution')
module.exports = {
root: true.extends: [
'plugin:vue/vue3-essential'.'eslint:recommended'.'@vue/eslint-config-typescript/recommended'.'@vue/eslint-config-prettier'].env: {
'vue/setup-compiler-macros': true
},
rules: {
'prettier/prettier': 'warn'.'@typescript-eslint/no-explicit-any': 'off'.'@typescript-eslint/no-unused-vars': 'off'.'vue/multi-word-component-names': 'off'}}Copy the code
- .prettier.js
module.exports = {
// Customize the formatting requirements
overrides: [{files: '.prettierrc'.options: {
parser: 'json'}}].printWidth: 100.// A line of up to 100 characters
tabWidth: 2.// Use 4 Spaces for indentation
semi: false.// A semicolon is required at the end of the line
singleQuote: true.// Use single quotes instead of double quotes
useTabs: false.// Use tabs instead of space indentations
quoteProps: 'as-needed'.// Add quotes around object attributes only when needed
jsxSingleQuote: false.// Use single quotes instead of double quotes in JSX
trailingComma: 'none'.// Do not need a comma at the end
bracketSpacing: true.// Spaces are required at the beginning and end of braces
bracketSameLine: false.// Backangle brackets for multi-line HTML (HTML, JSX, Vue, Angular) elements require line breaks
arrowParens: 'always'.// The arrow function, which has only one argument, also needs the parentheses avoid
rangeStart: 0.// Each file format ranges from beginning to end
rangeEnd: Infinity.// The range in which each file is formatted is the entire content of the file
requirePragma: false.// There is no need to write @prettier at the beginning of the file
insertPragma: false.// There is no need to automatically insert @prettier at the beginning of a file
proseWrap: 'preserve'.// Use the default line folding standard always
htmlWhitespaceSensitivity: 'css'.// Depending on the display style, HTML should be folded or not
vueIndentScriptAndStyle: false.// (default) For.vue files, do not indent
endOfLine: 'lf'.// The newline character uses LF in Linux and macOS as well as git repositories
embeddedLanguageFormatting: 'auto' // (default) allows automatic formatting of embedded code blocks
}
Copy the code
Bring back to the top
β husky + Lint-staged validation submission
1. Install dependencies
pnpm i -D husky lint-staged
Copy the code
2. Add script commands
npm set-script prepare "husky install" // Add the "prepare": "husky install" command to package.json/scripts. This command is available only on Linux /uinx operating systems
npm run prepare // Initialize husky, pass the git hooks to husky to execute, and create the.husky folder in the root directory
npx husky add .husky/pre-commit "npx lint-staged" // pre-commit Execute NPX Lint-staged directives
Copy the code
3. Create. Lintstagedrc. Json
{
"**/*.{js,ts,tsx,jsx,vue,scss,css}": [
"prettier --write \"src/**/*.ts\" \"src/**/*.vue\""."eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix"]}Copy the code
Bring back to the top
β project packaging optimization
- The project packaging optimization mainly extracts the configuration from viet.config. ts into a folder dedicated to packaging configuration
- Build folder directory
- build - vite vite environment related configuration - | - plugin plug-in configuration - | -- - | | - autocomponents automatic import components - | -- - | - | autoImport automatic import API - Compress compressed package - | - | - mock mock services - | - | - styleImport style automatic import - | | - index plug-in configuration entry - | - build. Ts - | - build configuration Proxy. ts Proxy configuration - utils tool functionCopy the code