行业知识
vite + vue + typscript + pinia + axios + vue-router + elementPlus
npm create vite@latest
创建项目后
npm inpm run dev
"dependencies": { "vue": "^3.4.21" },"devDependencies": { "@vitejs/plugin-vue": "^5.0.4", "typescript": "^5.2.2", "vite": "^5.2.0", "vue-tsc": "^2.0.6"} 需要安装的插件表格(希望需要安装的插件越来越少!!!)
| 插件名称 | 备注 |
|---|---|
| pinia | 等同与 vuex |
| pinia-plugin-persistedstate | pinia持久化插件 |
| axios | api请求库 |
| vue-router | 路由 |
| elementPlus | UI框架 |
| unplugin-auto-import | 为 Vite、Webpack、Rollup 和 esbuild 按需自动导入 API。支持 TypeScript。 |
| unplugin-vue-components | Vue 的按需组件自动导入。 |
| vite-plugin-compression | 压缩大文件 |
| vite-plugin-style-import | 它会根据需要自动导入组件的样式文件 |
| rollup-plugin-visualizer | 这是一个依赖分析插件,它提供了多种模式的依赖分析,包括直观的视图分析,sunburst(循环层次图,像光谱)、treemap(矩形层次图,看起来比较直观,也是默认参数)、network(网格图,查看包含关系)、raw-data(原数据模式,json格式), list(列表模式) |
| eslint | eslint针对的是javascript,他是一个检测工具,包含js语法以及少部分格式问题,在eslint看来,语法对了就能;保证代码正常允许,格式问题属于其次; |
| prettier | prettier属于格式化工具,它看不惯格式不统一,所以它就把eslint没干好的事接着干,另外,prettier支持,包含js在内的多种语言 |
| @vitejs/plugin-legacy | 为打包后的文件提供传统浏览器兼容性支持。 |
| unplugin-icons | 自动按需加载在图标,包括element plus 但是不仅仅时 element plus;使用教程请点击,具体包含图标内容查看iconify官网请点击,unplugin-icons github请点击 |
添加基础路径
TS版本需要安装@types/node,不然会警告找不到对应的类型声明
npm install @types/node --save-dev
vite.config.ts
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import { fileURLToPath, URL } from 'node:url'// https://vitejs.dev/config/export default defineConfig({ plugins: [vue()], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } },}) 引入TS 文件会报错找不到相应类型声明,因为在配置好 vite.config.ts 文件后
tsconfig.json 文件 或者 jsconfig.json 文件也要进行文件系统路径别名设置。需要配置baseUrl和paths字段
tsconfig.json
{ "compilerOptions": { "target": "ESNext", "useDefineForClassFields": true, "module": "ESNext", "moduleResolution": "Node", "strict": true, "jsx": "preserve", "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["ESNext", "DOM"], "skipLibCheck": true, "noEmit": true, "types": ["element-plus/global"], "baseUrl": "./", // 解析非相对模块的基础地址,默认是当前目录 "paths": { "@/*": ["./src/*"] // 路径映射,相对于baseUrl } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }]} 安装 pinia
pnpm install --save pinianpm i pinia-plugin-persistedstate
"dependencies": { "pinia": "^2.1.7", "pinia-plugin-persistedstate": "^3.2.1", "vue": "^3.4.21" }, 创建文件夹:src\store\index.ts
主要是创建一个实例
import type { App } from 'vue'import { createPinia } from 'pinia'import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' //数据持久化const store = createPinia()store.use(piniaPluginPersistedstate)export const setupStore = (app: App) => { app.use(store)}export { store } 挂载vue
import { createApp } from 'vue'import './style.css'import App from './App.vue'import { setupStore } from '@/store'const app = createApp(App)setupStore(app)app.mount('#app') 使用时:
创建:src/store/modules/user.ts
import { defineStore } from 'pinia'interface UserState { userInfo?: string tokenKey: string token: string roleRouters?: string[] rememberMe: boolean loginInfo?: string}export const useUserStore = defineStore('user', { state: (): UserState => { return { userInfo: undefined, tokenKey: '', token: '', roleRouters: undefined, rememberMe: true, loginInfo: undefined } }, getters: { getTokenKey(): string { return this.tokenKey }, getToken(): string { return this.token }, }, actions: { setTokenKey(tokenKey: string) { this.tokenKey = tokenKey }, setToken(token: string) { this.token = token }, }, // persist: true // 一键开启数据持久化,使用默认配置 // 开启数据持久化,自定义配置 persist: { // Key 用于引用 storage 中的数据 // 这个 Store 将被持久化存储在 localStorage 中的 my-custom-key key 中。 key: 'my-custom-key', // 将数据持久化到 storage 中,必须具有 getItem: (key: string) => string | null 和 setItem: (key: string, value: string) => void 两个方法。// 这个 store 将被持久化存储在 sessionStorage中。 storage: sessionStorage, // 用于指定 state 中哪些数据需要被持久化。[] 表示不持久化任何状态,undefined 或 null 表示持久化整个 state。 // 该 store 中, 只有userInfo 和 rememberMe 被持久化,而其他不会被持久化。 paths: ['userInfo', 'rememberMe'], // 该 hook 将在从 storage 中恢复数据之前触发,并且它可以访问整个 PiniaPluginContext,这可用于在恢复数据之前强制地执行特定的操作。 beforeRestore: (ctx) => { console.log(`即将恢复 '${ctx.store.$id}'`) }, // 该 hook 将在从 storage 中恢复数据之后触发,并且它可以访问整个 PiniaPluginContext,这可用于在恢复数据之后强制地执行特定的操作。 afterRestore: (ctx) => { console.log(`刚刚恢复完 '${ctx.store.$id}'`) }, // 当设置为 true 时,持久化/恢复 Store 时可能发生的任何错误都将使用 console.error 输出。 debug: true },}) 在组件中使用
import {useUserStore} from '@/store/modules/user';const store = useUserStore();// ...store.setTokenKey({...}); // 直接调用是不是很方便// ...store.user.page; // 直接获取 更多详细使用请点击此处
安装axios
pnpm i axios// 或者npm i axios
创建文件: src\utils\request.ts
import axios from 'axios';// 配置新建一个 axios 实例const service = axios.create({baseURL: import.meta.env.VITE_API_URL, // 环境变量timeout: 50000,headers: { 'Content-Type': 'application/json' },});// 添加请求拦截器service.interceptors.request.use((config) => {// 在发送请求之前做些什么return config;},(error) => {// 对请求错误做些什么return Promise.reject(error);});// 添加响应拦截器service.interceptors.response.use((response) => {// 对响应数据做点什么const res = response.data;const {status, data, message} = response || {};if (status !== 200) {const {message: messageErr} = service.interceptors.response.data || {};return Promise.reject(messageErr);} else {return {status, data};}},(error) => {const {data, status} = error.response || {};// 对响应错误做点什么 ...return Promise.reject(messageErr);});// 导出 axios 实例export default service; 使用时:
创建
import request from "../../utils/request";export function userlist(params) { return request({ url: `/userlist`, method: "GET", params, });}export function addUser(params) { return request({ url: `/addUser`, method: "POST", data: { ...params } });} 在组件中使用
import {deleteRoleApi} from '/@/api/...';deleteRoleApi(id).then(res => {}) 安装vue-router
pnpm install vue-router --save
创建文件:src\router\index.ts
import { createRouter, createWebHashHistory } from 'vue-router'import type { RouteRecordRaw } from 'vue-router'import type { App } from 'vue'import { NO_RESET_WHITE_LIST } from '@/assets/constants'const Layout = () => import('@/layout/Layout.vue')export const constantRouterMap: AppRouteRecordRaw[] = [ { path: '/', component: Layout, redirect: '/dashboard/analysis', name: 'Root', meta: { hidden: true } }, { path: '/login', component: () => import('@/views/Login/Login.vue'), name: 'Login', meta: { hidden: true, noTagsView: true } }, { path: '/personal', component: Layout, redirect: '/personal/personal-center', name: 'Personal', meta: { hidden: true, canTo: true }, children: [ { path: 'personal-center', component: () => import('@/views/Personal/PersonalCenter/PersonalCenter.vue'), name: 'PersonalCenter', meta: { hidden: true, canTo: true } } ] }, { path: '/404', component: () => import('@/views/Error/404.vue'), name: 'NoFind', meta: { hidden: true, title: '404', noTagsView: true } }]export const asyncRouterMap: AppRouteRecordRaw[] = [ { path: '/error', component: Layout, redirect: '/error/404', name: 'Error', meta: { icon: 'ci:error', alwaysShow: true }, children: [ { path: '404-demo', component: () => import('@/views/Error/404.vue'), name: '404Demo', meta: { title: '404' } }, { path: '403-demo', component: () => import('@/views/Error/403.vue'), name: '403Demo', meta: { title: '403' } }, { path: '500-demo', component: () => import('@/views/Error/500.vue'), name: '500Demo', meta: { title: '500' } } ] }, ]const router = createRouter({ history: createWebHashHistory(), strict: true, routes: constantRouterMap as RouteRecordRaw[], scrollBehavior: () => ({ left: 0, top: 0 })})export const resetRouter = (): void => { router.getRoutes().forEach((route) => { const { name } = route if (name && !NO_RESET_WHITE_LIST.includes(name as string)) { router.hasRoute(name) && router.removeRoute(name) } })}export const setupRouter = (app: App) => { app.use(router)}export default router 挂载到vue
import { createApp } from 'vue'import '@/style.css'import App from '@/App.vue'import { setupStore } from '@/store'import { setupRouter } from '@/router'const app = createApp(App)setupStore(app)setupRouter(app)app.mount('#app') 安装scss
直接安装不需要node-sass 和 sass-loader
npm install -D sass
安装 按需加载 element plus
npm install element-plus
安装相关按需加载的插件
npm install -D unplugin-vue-components unplugin-auto-import unplugin-icons vite-plugin-style-import consola
vite.config.ts
import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import { fileURLToPath, URL } from 'node:url'import AutoImport from 'unplugin-auto-import/vite'import Components from 'unplugin-vue-components/vite'import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'import { FileSystemIconLoader } from 'unplugin-icons/loaders'import Icons from 'unplugin-icons/vite'import IconsResolver from 'unplugin-icons/resolver'import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'// https://vitejs.dev/config/export default defineConfig({ plugins: [ vue(), AutoImport({ imports: ['vue', 'vue-router'], // 自动引入相关api resolvers: [ ElementPlusResolver(), IconsResolver({ // 设置自动导入的图标组件前缀 prefix: 'icon', // 标识自定义图标集 customCollections: ['ci'] }) ], }), Components({ resolvers: [ ElementPlusResolver(), IconsResolver({ // 设置自动导入的图标组件前缀 prefix: 'icon', // 标识自定义图标集 customCollections: ['ci'] }) ], }), Icons({ compiler: 'vue3', autoInstall: true, // 自定义配置 customCollections: { ci: FileSystemIconLoader('./src/assets/svg', svg => svg.replace(/^ resolves: [ElementPlusResolve()], libs: [ { libraryName: 'element-plus', esModule: true, resolveStyle: (name) = { if (name === 'click-outside') { return '' } return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css` } } ] }), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } },}) 使用方式,直接用不需要import
import IconBaseline5g from '~icons/ep/edit' ci: FileSystemIconLoader...) vue是自定义目录下的svg文件的名称 -->
静态资源动态引用:图片
vite官方推荐
使用require的可以用上面的方法替换
@vitejs/plugin-legacy
安装
必须安装 Terser,因为插件遗留版使用 Terser 进行缩小。
npm i -D @vitejs/plugin-legacy terser
// vite.config.jsimport legacy from '@vitejs/plugin-legacy'export default { plugins: [ legacy({ targets: ['defaults', 'not IE 11'], }), ],} vite-plugin-compression 压缩大文件
安装
npm i -D vite-plugin-compression
import viteCompression from "vite-plugin-compression";plugins: [viteCompression({verbose: true,disable: false,deleteOriginFile: false,// 文件大于 100Kb 开启压缩 threshold: 100000,algorithm: "gzip",ext: "gz",}),], 压缩文件需要搭配nginx 配置,详情请点击
rollup-plugin-visualizer 这是一个依赖分析插件
参考链接:https://blog.csdn.net/g18204746769/article/details/127431733
安装
pnpm install vite-plugin-cdn-import --save-dev
import { visualizer } from 'rollup-plugin-visualizer';plugins: [visualizer()] vite.config.js全部的配置
想了解配置想请点击
import { defineConfig, loadEnv } from 'vite'import vue from '@vitejs/plugin-vue'import { fileURLToPath, URL } from 'node:url'import AutoImport from 'unplugin-auto-import/vite'import Components from 'unplugin-vue-components/vite'import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'import { FileSystemIconLoader } from 'unplugin-icons/loaders'import Icons from 'unplugin-icons/vite'import IconsResolver from 'unplugin-icons/resolver'import { createStyleImportPlugin, ElementPlusResolve } from 'vite-plugin-style-import'import legacy from '@vitejs/plugin-legacy'import viteCompression from "vite-plugin-compression";// https://vitejs.dev/config/export default defineConfig((mode): any => { const env = loadEnv(mode.mode, process.cwd()) return { plugins: [ vue(), AutoImport({ imports: ['vue', 'vue-router'], // 自动引入相关api resolvers: [ ElementPlusResolver(), IconsResolver({ // 设置自动导入的图标组件前缀 prefix: 'icon', // 标识自定义图标集 customCollections: ['ci'] }) ], }), Components({ resolvers: [ ElementPlusResolver(), IconsResolver({ // 设置自动导入的图标组件前缀 prefix: 'icon', // 标识自定义图标集 customCollections: ['ci'] }) ], }), Icons({ compiler: 'vue3', autoInstall: true, // 自定义配置 customCollections: { ci: FileSystemIconLoader('./src/assets/svg', svg => svg.replace(/^ resolves: [ElementPlusResolve()], libs: [ { libraryName: 'element-plus', esModule: true, resolveStyle: (name) = { if (name === 'click-outside') { return '' } return `element-plus/es/components/${name.replace(/^el-/, '')}/style/css` } } ] }), legacy({ targets: ['defaults', 'not IE 11'], }), viteCompression({ verbose: true, disable: false, deleteOriginFile: false, // 文件大于 100Kb 开启压缩 threshold: 100000, algorithm: "gzip", ext: "gz", }), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)) } }, server: { host: '0.0.0.0', port: env.VITE_PORT, open: false, proxy: { '/api': { target: 'https://gitee.com', ws: true, changeOrigin: true, rewrite: (path:string) => path.replace(/^\/gitee/, ''), }, }, }, build: { outDir: 'dist', chunkSizeWarningLimit: 1500, rollupOptions: { output: { entryFileNames: `assets/[name].${new Date().getTime()}.js`, chunkFileNames: `assets/[name].${new Date().getTime()}.js`, assetFileNames: `assets/[name].${new Date().getTime()}.[ext]`, compact: true, // manualChunks: { // vue: ['vue', 'vue-router', 'pinia'], // echarts: ['echarts'], // antvG6: ['@antv/g6'], // elementPlus: ['element-plus'], // }, manualChunks(id:string[]) { // if (id.includes("style.css")) { // // 需要单独分割那些资源 就写判断逻辑就行 // return 'src/style.css'; // } // if (id.includes("HelloWorld.vue")) { // // 单独分割hello world.vue文件 // return 'src/components/HelloWorld.vue'; // } // // 最小化拆分包 if (id.includes('node_modules')) { return id .toString() .split('node_modules/')[1] .split('/')[0] .toString() } }, }, }, minify: 'terser', terserOptions: { compress: { drop_console: mode.mode === 'prd', drop_debugger: mode.mode === 'prd', }, }, sourcemap: mode.mode !== 'prd', }, css: { devSourcemap: true, preprocessorOptions: { css: { charset: false } }, }, }}) 找不到模块“@/xxx/xxx.vue”或其相应的类型声明。ts(2307)
配置tsconfig.json:确保你的tsconfig.json文件中包含了对.vue文件的支持。
{ "compilerOptions": { "types": ["vue/vue3"] // 如果你使用的是Vue 3 // 或者 "types": ["vue/vue2"] 如果你使用的是Vue 2 }} 创建类型声明文件(如果自动处理不起作用):如果自动处理不起作用,你可以手动创建一个声明文件,例如shims-vue.d.ts,并在其中添加以下内容
declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent}, {}, any export default component} 安装eslint && prettier
根据个人需求,我参考的这几个链接:
https://blog.csdn.net/m0_53022813/article/details/137379423
https://juejin.cn/post/7118294114734440455#heading-1
https://blog.csdn.net/weixin_43459866/article/details/124249172
https://blog.csdn.net/weixin_43993776/article/details/132564724
无法找到模块 vite-plugin-eslint 插件中的 TS 声明文件,隐式含有 “any” 类型。
vscode使用eslint