本次构建的项目技术栈: Vite
+Vue3
+Volar
+Pinia
+Vue-Router
+TS
+JSX
+Scss
+Script setup
- Vite: 下一代前端开发与构建工具,极速的热更新开发体验★★★★★
- Vue3.2: 超多的黑魔法
- Volar: Vue3必备开发神器
- Pinia: 新一代的轻量状态管理器
- Vue-Router4: Vue3的官方路由
#app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; }
- 安装
sass
npm install sass -D npm install node-sass -D npm install sass-loader -D
- 安装
@types/node
npm install @types/node -D
- 配置路径别名
在vite.config.ts
添加配置
// vite.congfig.ts import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import eslintPlugin from 'vite-plugin-eslint'; import {join} from "path"; export default defineConfig({ plugins: [vue(), eslintPlugin()], resolve: { alias: { "@": join(__dirname, "src"), "~": join(__dirname, "node_modules") } } });
在tsconfig.json
在配置
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["esnext", "dom"], "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] }
- 安装
pinia
轻量状态管理器
npm install pinia
- 创建
stores/user.ts
全局状态store
import { defineStore } from 'pinia' import { ref } from 'vue' export const useUserStore = defineStore('counter', () => { const count = ref(0) function increment() { count.value++ }return { count, increment } })
- vue启用
pinia
,修改main.ts
代码
import { createApp } from 'vue' import App from './App.vue' import {router} from './router' import { createPinia } from 'pinia'createApp(App).use(router).use(createPinia()).mount('#app')
- 安装
@vitejs/plugin-vue-jsx
npm install @vitejs/plugin-vue-jsx -D
- 在
vite.config.ts
中启用jsx
// vite.congfig.ts import { defineConfig } from 'vite'; import vue from '@vitejs/plugin-vue'; import eslintPlugin from 'vite-plugin-eslint'; import {join} from "path"; import vueJsx from "@vitejs/plugin-vue-jsx"; export default defineConfig({ plugins: [vue(), eslintPlugin(), vueJsx()], resolve: { alias: { "@": join(__dirname, "src"), "~": join(__dirname, "node_modules") } } });
- 修改
tsconfig.json
规则,包括src
下所有的.tsx
文件
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["esnext", "dom"], "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src/**/*.ts", "src/*.tsx", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }] }
- 改造
App.vue
为App.tsx
,并在main.ts
引入
// App.tsx import { defineComponent } from 'vue'; import {RouterLink, RouterView} from 'vue-router'; import './style/app.scss'export default defineComponent({ name: 'App', setup() { return () => ( <>
Home |Login > ); } });
// main.ts import { createApp } from 'vue' import App from './App' import {router} from './router' import { createPinia } from 'pinia'createApp(App).use(router).use(createPinia()).mount('#app')
- 项目安装
axios
npm install --save axios vue-axios
- 封装
axios
构造一个通用的request
方法
// src/request/base.tslet BASE_URL = '' const TIME_OUT = 30000 if (process.env.NODE_ENV === 'dev') { BASE_URL = '开发环境IP' } else if (process.env.NODE_ENV === 'prod') { BASE_URL = '生产环境IP' } else { BASE_URL = '其它环境IP' } export { BASE_URL, TIME_OUT }
// src/request/type.tsimport type { AxiosRequestConfig, AxiosResponse } from 'axios'export interface LJRequestInterceptors
{ requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig requestInterceptorCatch?: (error: any) => any responseInterceptor?: (res: T) => T responseInterceptorCatch?: (error: any) => any }export interface LJRequestConfig extends AxiosRequestConfig { showLoading?: boolean interceptors?: LJRequestInterceptors }
// src/request/request.tsimport axios from 'axios' import type { AxiosInstance } from 'axios' import { LJRequestInterceptors, LJRequestConfig } from './type' class LJRequest {instance: AxiosInstance interceptors?: LJRequestInterceptorsconstructor(config: LJRequestConfig) {//创建axios实例 this.instance = axios.create(config) //保存基本信息 this.interceptors = config.interceptors//使用拦截器 //从config钟取出的拦截器是对应的实例的拦截器 this.instance.interceptors.request.use(this.interceptors?.requestInterceptor, this.interceptors?.requestInterceptorCatch) this.instance.interceptors.response.use(this.interceptors?.responseInterceptor, this.interceptors?.requestInterceptorCatch) //所有的实例都有的拦截器 this.instance.interceptors.request.use((config) => { console.log('所有的实例都有的拦截器: 请求拦截成功') console.log(config) return config }, (err) => { console.log('所有的实例都有的拦截器: 请求拦截失败') return err })this.instance.interceptors.response.use( (res) => { console.log('所有的实例都有的拦截器: 响应拦截成功') return res.data }, (err) => { console.log('所有的实例都有的拦截器: 响应拦截失败') //例子:判断不同httpErrorCode显示不同错误信息 if (err.response.status === 404) { console.log('404错误~') } return err } ) }request
(config: LJRequestConfig ): Promise { return new Promise((resolve, reject) => { //单个请求对请求config的处理 if (config.interceptors?.requestInterceptor) { config = config.interceptors.requestInterceptor(config) } this.instance .request(config) .then((res) => { //单个请求对数据的处理 if (config.interceptors?.responseInterceptor) { res = config.interceptors.responseInterceptor(res) } console.log(res) //将结果返回出去 resolve(res) }) .catch((err) => { reject(err) }) }) }get (config: LJRequestConfig ): Promise { return this.request ({ ...config, method: 'GET' }) }post (config: LJRequestConfig ): Promise { return this.request ({ ...config, method: 'POST' }) }delete (config: LJRequestConfig ): Promise { return this.request ({ ...config, method: 'DELETE' }) }patch (config: LJRequestConfig ): Promise { return this.request ({ ...config, method: 'PATCH' }) } }export default LJRequest
// src/request/index.tsimport LJRequest from './request' import { BASE_URL, TIME_OUT } from './base' const ljRequest = new LJRequest({ baseURL: BASE_URL, timeout: TIME_OUT, interceptors: { requestInterceptor: (config) => { let _config = { ...config, } _config.headers = { ...config.headers, token: sessionStorage.getItem("token") as any, app: 'visionary' } console.log('请求成功拦截') return _config },requestInterceptorCatch: (err) => { console.log('请求失败拦截') return err }, responseInterceptor: (config) => { console.log('响应成功拦截') return config }, responseInterceptorCatch: (err) => { console.log('响应失败拦截') return err } } })export default ljRequest
// src/views/index.vue
- 【Vue3发布这么久了,还不会用Vite构建项目()】配置脚本启动参数命令
--mode 环境变量值
"dev": "vite --host --mode development",
- 打包遇到对node_modules中的类型进行了检查,可以修改npm
build
命令, 增加--skipLibCheck
参数,如下:
"build": "vue-tsc --noEmit --skipLibCheck && vite build",
- 执行打包命令时,
vue-tsc
语法检查报错时,请检查IDE
的Volar
插件版本和vue-tsc
版本是否兼容,如遇到新语法不兼容时可升级vue-tsc
或Volar
的版本,我这里出现的是vue-tsc
无法识别自定义指令,但是Volar
是支持的(开发过程不报错),所以我将vue-tsc
升级到了0.33.9
版本。 - 有时候
vue-tsc
报打包错误,检查node
版本是否为14.0.0+
,使用最新的构建工具建议把node
版本升级到比较新的版本。
推荐阅读
- 安装