从0到1搭建vue3项目,完成vite.config.ts配置,集成router,pinia,axios,sass等

使用vite搭建vue3项目

1,使用命令创建项目

创建条件:1,node 版本需要 20+ 以上 ;2,全局安装vite: npm install vite -g

  • 使用命令创建项目
npm create vite@latest
// 使用命令创建项目
1,项目命名
   Project name:
|  vite-vue3-demo
2,选择框架
	 Select a framework:
|    Vanilla
|  > Vue
|    React
|    Preact
|    Lit
|    Svelte
|    Solid
|    Qwik
|    Angular
|    Others
3,选择项目使用语法
 Select a variant:
|  > TypeScript
|    JavaScript
|    Official Vue Starter ↗
|    Nuxt ↗
4,项目创建完成
—  Done. Now run:

  cd vite-vue3-demo
  npm install  // 下载更新项目依赖
  npm run dev //  运行命令
  

就此vue3项目算是运行成功

在这里插入图片描述

项目文件结构:
在这里插入图片描述

2,处理项目文件中报错

  1. vue3.0找不到模块“./App.vue”或其相应的类型声明
    在这里插入图片描述

报错原因/解决:

```
因为 TypeScript 编译器无法识别 Vue 单文件组件 (.vue 文件) 的内容,要解决在随意一个vite-env.d.ts文件中添加配置,告诉 TypeScript 编译器,当它遇到 .vue 文件时,应该将其视为一个 Vue 组件,并导出一个默认的组件实例。

// vite-env.d.ts 文件
declare module '*.vue' {
    import type { DefineComponent } from 'vue'
    const component: DefineComponent<{}, {}, any>
    export default component
  }
```
  1. 导入内置模块错误

    在vite.config.ts 配置 报错 找不到模块“path”或其相应的类型声明

    在这里插入图片描述

    或 在定义环境变量时,process出现报错

    在这里插入图片描述

    解决方法:

    npm install @types/node --save-dev
    

3,配置vite.config.ts

​ 初始vite.config.ts 文件中是没有多少内容,如下图,
在这里插入图片描述

​ 接下来就是对vite.config.ts进行改造

注:

  • export default defineConfig({}):适用于配置固定不变的场景,代码简洁,易于理解和维护。

  • export default defineConfig(({ command, mode }) => { return {} }):适用于需要根据不同的命令和模式动态调整配置的场景,提供了更大的灵活性。

1,配置别名(此处有两步,vite.config.ts和ts编译 都需要配置)
// vite.config.ts
import { defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
import path from "node:path";
import { fileURLToPath } from "node:url";

// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
    // mode 表示是那个环境 process.cwd() 当前工作目录的根目录
  // 这句代码表示: 在那个环境下加载那个文件
  let env = loadEnv(mode, process.cwd()) // vite支持loadEnv 执行此方法能够获取当前环境变量
  return {
    plugins: [vue()],
    resolve: {
      // 1, 先配置别名
      alias: {
        // 第一种方式(最简洁)
        "@": path.resolve("./src"),
        // 第二种方式
        "@style": fileURLToPath(new URL("./src/assets/style", import.meta.url)),
        "@images": fileURLToPath(
          new URL("./src/assets/images", import.meta.url)
        ),
      },
    },
  };
});


**TypeScript 编译配置**
// tsconfig.json
{
  "compilerOptions": {
    "baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
    "paths": { //路径映射,相对于baseUrl
      "@/*": ["src/*"] 
    }
  }
}
注: 在你的 tsconfig.json 文件中,你使用了 references 字段来包含其他 tsconfig 文件。确保这些被引用的文件(如 tsconfig.app.json 和 tsconfig.node.json)也正确地继承了根 tsconfig.json 文件中的配置,所以【references】字段来判断,是在(tsconfig.json)还是在(tsconfig.app.json) 配置

使用方式:

组件:import HelloWorld from '@/components/HelloWorld.vue'
图片:<img src="@images/1.png" alt="" srcset="">
2,配置环境变量
创建 三个文件,如果有uat环境则是四个文件 分别是:
 # 变量必须以 VITE_ 为前缀才能暴露给外部读取
.env.loc  // 本地开发环境
 NODE_ENV = 'development'
 VITE_APP_MODE = 'loc'
.env.test // 测试环境
 NODE_ENV = 'test'
 VITE_APP_MODE = 'test'
.env.prd // 生产环境
 NODE_ENV = 'production'
 VITE_APP_MODE = 'prd'
 
 在vue等文件中通过console.log('env', import.meta.env) 获取环境变量

配置运行命令:package.json

"scripts": {
    "dev": "vite --open --mode loc",
    "build:test": "vue-tsc && vite build --mode test",
    "build:pro": "vue-tsc && vite build --mode prd",
    "preview": "vite preview"
  },
  mode 后面的值是创建文件名的后置,例如:本地文件是.env.loc  若--mode dev 则打印环境变量是为空

在vite.config.ts中需要使用环境变量通过参数的方式来使用

export default defineConfig(({ command, mode }) => {
	// 通过这样获取环境变量
	let env = loadEnv(mode, process.cwd())
 	return {} 
 })
3,vite插件配置 vite-plugin-vue-setup-extend 应用

VueSetupExtend允许在<script setup>语法中直接定义组件的name属性,并支持自动暴露组件的导出,从而简化了组件的定义和使用‌。

安装命令:
npm i vite-plugin-vue-setup-extend -D
在vite.config.ts中配置插件

在这里插入图片描述

**目的: ** 可以通过扩展的方式,给 setup 函数添加新的功能,例如

1.允许在 setup 函数中使用 ES6 模块语法
2.允许在 setup 函数中使用 async/await 异步操作
3.支持在 setup 函数中使用源代码映射(source map)

在这里插入图片描述

4,集成sass 或者 less
安装命令:
npm install -D sass sass-loader
  • 删除项目中style.css, 创建style文件将样式文件都存放在这个文件夹

  • 去npm官网搜scss-reset插件,在里面复制出清除默认样式的代码,在style文件夹中创建reset.scss文件,将代码复制进去

  • ​ 在style文件夹中新建index.scss 文件并将清除默认样式引入进去

    如果@import 在编译时报错则使用@use

  • 在main.ts中引入index.scss,这样系统就可以使用全局样式

  • 在vite.config.ts中配置全局样式变量

	export default defineConfig((config) => {
		css: {
	      preprocessorOptions: {
	        scss: {
	          javascriptEnabled: true, // 允许使用 JavaScript 表达式
	          additionalData: '@use "./src/styles/variable.scss";',
	          // 或者在assets中创建
	          // additionalData: `@use "@/assets/styles/variables.scss" as *;`,
	        },
	      },
	    },
		}
	}

注: 在配置sass全局变量时,一直出现报错,通常是由于 Sass 无法找到你要导入的样式表文件导致的, 首先去核实文件名和路径是否没问题! ! !

​ 我在这里是上面设置了@styles和@images两个别名,我把这两个别名注释后再去接入就没报错,后面再将注释放开
在这里插入图片描述

5,createSvgIconsPlugin 全局注册svg
安装命令:
npm install vite-plugin-svg-icons -D
在vite.config.ts中配置插件
import { defineConfig, loadEnv } from "vite";
import vue from "@vitejs/plugin-vue";
// import path from "node:path";
import { fileURLToPath, resolve } from "node:url";
import VueSetupExtend from "vite-plugin-vue-setup-extend";

import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import path from "node:path";

// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
  return {
    plugins: [
      vue(),
      VueSetupExtend(),
      createSvgIconsPlugin({
        // 指定图标文件夹路径
        iconDirs: [path.resolve(process.cwd(), "src/assets/icons")],
        // 指定symbolId格式
        symbolId: "icon-[name]",
      }),
    ],
    resolve: {
      // 1, 先配置别名
      alias: {
        // 第一种方式(最简洁)
        // "@": path.resolve("./src"),
        // 第二种方式
        "@": fileURLToPath(new URL("./src", import.meta.url)),
        "@styles": fileURLToPath(new URL("./src/styles", import.meta.url)),
        "@images": fileURLToPath(
          new URL("./src/assets/images", import.meta.url)
        ),
      },
    },
    // 3, 配置全局css样式
    css: {
      // 全局 css样式
      preprocessorOptions: {
        scss: {
          javascriptEnabled: true, // 允许使用 JavaScript 表达式
          additionalData: `@use "@/styles/variable.scss" as *;`,
        },
      },
    },
  };
});

安装配置好后,启动项目会有一个报错: Cannot find package ‘fast-glob’

在这里插入图片描述

解决: 重新安装一下这个插件就能运行项目

cnpm i fast-glob -D
在入口文件main.ts中导入
import 'virtual:svg-icons-register'

在入口文件这里导入时也可能存在一个ts错误提示:

在这里插入图片描述

解决方式:

在项目中找到一个env.d.ts的文件,在里面添加这窜代码

declare module "virtual:svg-icons-register" {
  const component: any;
  export default component;
}
创建svgIcon.vue组件,并全局挂载,直接通过标签的形式使用
// 在components 文件夹中新增一个svgIcon.vue文件
<template>
  <svg class="svg-icon" :style="'width:' + size + ';height:' + size">
    <use :xlink:href="symbolId" :fill="color" />
  </svg>
</template>

<script setup lang="ts">
import { computed } from 'vue'

const props = defineProps({
  prefix: { // 前缀
    type: String,
    default: 'icon',
  },
  name: { // svg图标名称
    type: String,
    required: false,
    default: '',
  },
  color: { // svg图标颜色
    type: String,
    default: '',
  },
  size: { // svg图标大小
    type: String,
    default: '16px',
  },
})
console.log('props', props)
const symbolId = computed(() => `#${props.prefix}-${props.name}`)
</script>

<style scoped>
.svg-icon {
  display: inline-block;
  width: 1em;
  height: 1em;
  overflow: hidden;
  vertical-align: -0.15em;
  /* 因icon大小被设置为和字体大小一致,而span等标签的下边缘会和字体的基线对齐,故需设置一个往下的偏移比例,来纠正视觉上的未对齐效果 */
  outline: none;
  fill: currentcolor;
  /* 定义元素的颜色,currentColor是一个变量,这个变量的值就表示当前元素的color值,如果当前元素未设置color值,则从父元素继承 */
}
</style>

在components文件中新增一个index.ts文件
import type { App, Component } from 'vue'
import SvgIcon from './svgIcon.vue'

// 定义一个对象,用于存储组件映射关系,键为组件名称,值为组件对象
const components: { [name: string]: Component } = {
  SvgIcon,
  // ...
}

// 导出默认的插件
export default {
  // install 方法在插件安装时被调用,参数为 Vue 应用实例
  install(app: App) {
    Object.keys(components).forEach((key: string) => {
      // 以 key 的名字在全局注册每个组件
      app.component(key, components[key]);
    });
  },
};

将在入口文件(main.ts)引入全局注册的插件
// 注册封装的组件
import gloablComponent from '@/components'

app.use(gloablComponent)
使用svg图标: 在asset文件夹中新增icons文件存放svg图标
全局通过标签的形式使用
<svgIcon name="phone" size="50" color="#ccc" />
6,配置代理 serve

看 【集成axios封装请求方法中】

4,配置路由

1.安装路由
npm install vue-router@4
2.创建路由文件和定义路由

在vue项目文件中src下新增一个router的文件夹,里面包含两个文件,index.ts和router.ts

index.ts文件

import { createRouter, createWebHistory } from 'vue-router'
// 项目中定义的路由对象 
import { constantRoutes } from './router'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: constantRoutes, 
})

export default router

router.ts

// 在这个文件中定义所以的路由对象,并将其导出
export const constantRoutes = [
  {
    path: "/home",
    name: "home",
    component: () => import("@/views/home/index.vue"),
    meta: {
      title: "首页", // 菜单标题
      hidden: true, // 在左侧菜单中是否隐藏 true: 隐藏  false:显示
      icon: "",
    },
  },
  {
    path: "/about",
    name: "about",
    component: () => import("@/views/about/index.vue"),
    meta: {
      title: "关于", // 菜单标题
      hidden: true, // 在左侧菜单中是否隐藏 true: 隐藏  false:显示
      icon: "",
    },
  },
];
3.在入口文件中挂载路由
// 挂载路由
import router from '@/router';

app.use(router);
4.使用路由

此处根据系统来做布局,目前只是简单使用路由跳转.说明路由添加成功
这里使用router-link 和 router-view 两个标签来实现路由跳转和显示,不过多描述

5,集成状态管理 pinia

1, 安装命令
npm install pinia
2, 在src下新建文件夹 stores,包含 index.ts文件和modules文件夹

index.ts文件

// 创建大仓库
import { createPinia } from "pinia";

// 创建
const pinia = createPinia();

// 对外暴露: 入口文件需要安装仓库
export default pinia;

modules文件夹中存放各个功能的小仓库

//创建用户相关的小仓库
import { defineStore } from "pinia";

// 各个小仓库定义的数据类型
import type { UserState } from "./type";

const useUserStore = defineStore("user", {
  //小仓库存储数据地方  也需要定义数据类型
  state: (): UserState => ({
    name: "张三",
    age: 18,
  }),
  // 异步|逻辑的地方
  actions: {
    setAge(age: number) {
      this.age = age;
    },
  },
});

export default useUserStore;

type.ts

// 各个小仓库需要定义的ts类型,统一放在这里,方便维护
export interface UserState {
  name: string
  age: number
}
3, 在入口文件中挂载 pinia 状态管理
// 挂载pinia
import pinia from '@/stores';

app.use(pinia);
4, 使用状态管理
<template>
  <div class="text">
    姓名: <span>{{ UserStore.name}}</span>  ;
    年龄: <span>{{ UserStore.age }}</span>
  </div>
</template>
<script lang='ts' setup name="home">
// 引入小仓库
import useUserStore from '@/stores/modules/user';

// 定义变量接收小仓库
  let UserStore = useUserStore()
  console.log('userStore', UserStore)
</script>

6,集成axios封装请求方法

1,安装命令
npm install axios
2,封装axios,在utils文件夹中新增http.ts文件
//进行axios的 二次封装: 使用请求和响应拦截器
import axios from 'axios'
import { ElMessage } from 'element-plus'
import useUserStore from '@/stores/modules/user'
import { showLoading, hideLoading } from './loading'

// 1,使用axios 对象的create方法,去创建axios 实现做些配置
const request = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API, // 基础路径上带上api
  timeout: 5000,
})

// 2, axios 示例添加请求和响应拦截器
request.interceptors.request.use(config => {
  // 判断请求头中是否需要显示laoding
  if (config.headers.loading) {
    showLoading()
  }
  // 从config配置对象中header属性请求头,经常给服务器端携带公共参数
  // 从仓库中获取token将其放到header中
  const userStore = useUserStore()
  if (userStore.token) {
    config.headers.token = userStore.token
  }
  console.log('config', config)
  //需要返回配置对象
  return config
})

// axios 示例添加响应拦截器
request.interceptors.response.use(
  response => {
    // 响应拦截进来隐藏loading效果,此处采⽤延时处理是合并loading请求效果,避免多次请求loading关闭⼜开启
    setTimeout(() => {
      hideLoading()
    }, 200)
    // 成功回调
    return response.data
  },
  error => {
    setTimeout(() => {
      hideLoading()
    }, 200)
    console.log('err', error)

    // 失败回调: 处理http 网络错误
    let message = '' // 定义一个错误提示问题
    const status = error.response ? error.response.status : 888 // 错误状态码
    switch (status) {
      case 401:
        message = 'TOKEN过期'
        break
      case 403:
        message = '无权访问'
        break
      case 404:
        message = '请求地址错误'
        break
      case 500:
        message = '服务器异常'
        break

      default:
        message = '网络异常'
        break
    }
    //提示错误信息
    ElMessage({
      type: 'error',
      message,
    })
    return Promise.reject(error)
  },
)

// 对外暴露
export default request

3,封装全局loading组件,在二次封装axios中使用
/**
 * 全局loading效果:合并多次loading请求,避免重复请求
 * 当调⽤⼀次showLoading,则次数+1;当次数为0时,则显⽰loading
 * 当调⽤⼀次hideLoading,则次数-1; 当次数为0时,则结束loading
 */
import { ElLoading } from 'element-plus'
// 定义⼀个请求次数的变量,⽤来记录当前页⾯总共请求的次数
// import loading from '@/assets/icons/loading.svg'
let loadingRequestCount = 0
// 初始化loading
let loadingInstance: any = null
// 显⽰loading的函数并且记录请求次数 ++
const showLoading = () => {
  if (loadingRequestCount === 0) {
    // 全局实现loading效果,不⽤每个页⾯单独去v-loading
    // loading样式
    loadingInstance = ElLoading.service({
      lock: true,
      text: '正在加载中,请稍后....',
      background: 'rgba(0, 0, 0, 0.6)',
      customClass: 'loading',
    })
  }
  loadingRequestCount++
}
// 隐藏loading的函数,并且记录请求次数 --
const hideLoading = () => {
  if (loadingRequestCount <= 0) return
  loadingRequestCount--
  if (loadingRequestCount === 0) {
    loadingInstance.close()
  }
}
export { showLoading, hideLoading }

4,新建文件夹API存放各个模块的接口里面有多个文件,每个文件下包含index.ts和type.ts

index.ts


import http from '@/utils/http';
import type { reqUserData } from "./type";


// 定义接口
enum API {
  GET_USERLISET_URL = "admin/acl/user", // 手机号登入
}

export const getUserList = (page:any,size:any, username:string) => {
  return http.get<any, reqUserData>(
    API.GET_USERLISET_URL + `/${page}/${size}`,
    {
      headers: { loading: true },
      params: { username }
    }
  );
};


type.ts

// 接口类型

export interface reqUserData {
  code: number;
  message: string;
  ok: boolean;
  data: {
    records: records[];
    size: number;
    pages:number;
    total: number;
  };
} 
// 接口返回列表中对象的类型
export interface records {
  createTime: string;
  id: number;
  name: string;
  password: string;
  phone: null;
  roleName: string;
  updateTime: string;
  username: string;
}

5,在vite.config.ts中配置代理
import { defineConfig, loadEnv, type build } from "vite";
import vue from "@vitejs/plugin-vue";
// import path from "node:path";
import { fileURLToPath, resolve } from "node:url";
import VueSetupExtend from "vite-plugin-vue-setup-extend";

import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
import path from "node:path";

// https://vite.dev/config/
export default defineConfig(({ command, mode }) => {
  // mode 表示是那个环境 process.cwd() 当前工作目录的根目录
  //2, 这句代码表示: 在那个环境下加载那个文件
  let env = loadEnv(mode, process.cwd()); // vite支持loadEnv 执行此方法能够获取当前环境变量
  console.log("当前环境", env); // 打印出当前环境变量)
  return {
    base: env.VITE_BASE_URL,
    build: {
      outDir: "dist",
    },
    plugins: [
      vue(),
      VueSetupExtend(),
      createSvgIconsPlugin({
        // 指定图标文件夹路径
        iconDirs: [path.resolve(process.cwd(), "src/assets/icons")],
        // 指定symbolId格式
        symbolId: "icon-[dir]-[name]",
      }),
    ],
    resolve: {
      // 1, 先配置别名
      alias: {
        // 第一种方式(最简洁)
        // "@": path.resolve("./src"),
        // 第二种方式
        "@": fileURLToPath(new URL("./src", import.meta.url)),
        "@styles": fileURLToPath(new URL("./src/styles", import.meta.url)),
        "@images": fileURLToPath(
          new URL("./src/assets/images", import.meta.url)
        ),
      },
    },
    // 3, 配置全局css样式
    css: {
      // 全局 css样式
      preprocessorOptions: {
        scss: {
          javascriptEnabled: true, // 允许使用 JavaScript 表达式
          additionalData: `@use "@/styles/variable.scss" as *;`,
        },
      },
    },
    // 配置代理
    server: {
      proxy: {
        "/api": {
          target: "http://sph-api.atguigu.cn", // 目标服务器地址
          changeOrigin: true, // 是否跨域
          rewrite: (path) => path.replace(/^\/api/, ""), // 重写路径
        },
      },
    },
  };
});
6, 调接口获取数据
//调接口获取列表
const getuserData = async () => {
  try{
    let res: reqUserData = await getUserList(1, 10, '')
    console.log('res', res)
    list.value = res.data.records
  }catch(e){
    console.log('xxxx',e)
  }
}

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值