Vue3发布这么久了,还不会用Vite构建项目()

本次构建的项目技术栈: Vite+Vue3+Volar+Pinia+Vue-Router+TS+JSX+Scss+Script setup

  1. Vite: 下一代前端开发与构建工具,极速的热更新开发体验★★★★★
  2. Vue3.2: 超多的黑魔法
  3. Volar: Vue3必备开发神器
  4. Pinia: 新一代的轻量状态管理器
  5. Vue-Router4: Vue3的官方路由
  6. #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; }
    1. 安装 sass
    npm install sass -D npm install node-sass -D npm install sass-loader -D

    1. 安装 @types/node
    npm install @types/node -D

    1. 配置路径别名
      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" }] }

    1. 安装 pinia轻量状态管理器
    npm install pinia

    1. 创建 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 } })

    1. 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')

    1. 安装 @vitejs/plugin-vue-jsx
    npm install @vitejs/plugin-vue-jsx -D

    1. 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") } } });

    1. 修改 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" }] }

    1. 改造 App.vueApp.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')

    1. 项目安装 axios
    npm install --save axios vue-axios

    1. 封装 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

    1. 【Vue3发布这么久了,还不会用Vite构建项目()】配置脚本启动参数命令 --mode 环境变量值
      "dev": "vite --host --mode development",

    项目打包的相关问题
    1. 打包遇到对node_modules中的类型进行了检查,可以修改npm build 命令, 增加 --skipLibCheck 参数,如下:
      "build": "vue-tsc --noEmit --skipLibCheck && vite build",

    2. 执行打包命令时,vue-tsc 语法检查报错时,请检查 IDEVolar插件版本和 vue-tsc 版本是否兼容,如遇到新语法不兼容时可升级 vue-tscVolar 的版本,我这里出现的是 vue-tsc 无法识别自定义指令,但是 Volar 是支持的(开发过程不报错),所以我将 vue-tsc 升级到了 0.33.9 版本。
    3. 有时候 vue-tsc 报打包错误,检查 node 版本是否为 14.0.0+ ,使用最新的构建工具建议把 node 版本升级到比较新的版本。

      推荐阅读