• 手把手,完整的从0搭建vite-vue3-ts项目框架:配置less+svg+pinia+vant+axios


    项目同步git:https://gitee.com/lixin_ajax/vue3-vite-ts-pinia-vant-less.git

     觉得有帮助的小伙伴请点下小心心哦

     

    为避免赘述,过于基础的点会直接省略或贴图,比如创建文件夹/文件的路径/路由一类

    配置相应功能,也尽量只贴相关代码,并不代表整个文件内容

    我会尽量把每一步都记录下来,让跟随文档操作的朋友也能还原项目

    项目不尽完美,但是主体功能应该都可以有所参考

    一.本地初始环境

     

    二.使用vite脚手架,创建vue3+ts

    yarn create vite

    输入项目名,回车确认

     

    选择Vue和TypeScript

     

    文件目录如下,项目创建成功!

     

     三.启动项目:根据提示进入项目运行项目,或自行使用编码器输入指令进行启动

    yarn    // 安装依赖
    yarn dev // 运行项目

     

    浏览器打开地址,运行成功!

     

    四.必备依赖

    This package contains type definitions for Node.js (http://nodejs.org/)

    yarn add @types/node -S -D

     

    五.配置路径别名@

    1.位置:直接改写vite.config.ts -- 顺便就添加alias

    复制代码
    // vite.config.ts
    
    import vue from "@vitejs/plugin-vue";
    import { resolve } from "path";
    
    function pathResolve(dir: string) {
      return resolve(process.cwd(), ".", dir);
    }
    
    // https://vitejs.dev/config/
    export default () => {
      return {
        resolve: {
          alias: [
            {
              find: "@",
              replacement: pathResolve("src"),
            },
            {
              find: "views",
              replacement: pathResolve("src/views"),
            },
          ],
        },
        plugins: [vue()],
      };
    };
    复制代码

     

    2.位置:tsconfig.json -- 修改baseUrl及paths

    复制代码
    // tsconfig.json
    
    {
      "compilerOptions": {
         ......
      "baseUrl": "./",
        "paths": {
          "@/*": ["src/*"],
          "views/*": ["src/views/*"],
          "components/*": ["src/components/*"],
          "assets/*": ["src/assets/*"]
        }
      },
      "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"],
      "references": [{ "path": "./tsconfig.node.json" }]
    }
    复制代码

     

    六.配置vue-router

    yarn add vue-router -S

    推荐一个很好的插件nprogress【进度条】

    yarn add @types/nprogress nprogress -D

    main.ts引入router

    复制代码
    // main.ts
    
    import { createApp } from 'vue'
    import './style.css'
    
    import App from './App.vue'
    import router from "./router";
    
    const app = createApp(App as any);
    app.use(router)
    
    app.mount('#app')
    复制代码

    src下创建router文件夹,项目往往需要模块化,所以代码尽量不要杂糅在一起

     /router/index.ts

    复制代码
    /router/index.ts
    
    import { createRouter, createWebHashHistory, RouteRecordRaw } from "vue-router";
    import NProgress from "nprogress";
    import "nprogress/nprogress.css";
    
    const modules: any = import.meta.glob("./modules/**/*.ts", { eager: true });
    
    const routes: Array = [];
    for (const key in modules) {
        routes.push(...modules[key].default);
    }
    
    const router = createRouter({
        history: createWebHashHistory(), // history 模式则使用 createWebHistory()
        routes,
    });
    
    router.beforeEach(async (_to, _from, next) => {
        NProgress.start();
        next();
    });
    
    router.afterEach((_to) => {
        NProgress.done();
    });
    
    export default router;
    复制代码

    /router/typings.d.ts 路由meta格式受控

    复制代码
    /router/typing.d.ts
    
    import "vue-router";
    
    declare module "vue-router" {
        interface RouteMeta {
            // options
              title?: string;
            // every route must declare
              show?: boolean; //
        }
    }
    复制代码

    然后就是test下随便创建一个路由,对应的,views下创建相应的vue文件,App.vue给上router-view

    test/index.ts

    app.vue

     

     test/index.vue

    查看页面

    页面正确显示,路由部署成功!

     

    七.配置css预处理:less

    yarn add less less-loader -D

    为了配置全局的less样式文件,同时引入fs模块

    yarn add fs -D

    进入项目根目录的配置文件 

    位置:vite.config.ts -- css

    复制代码
    // vite.config.ts
    
    import vue from "@vitejs/plugin-vue";
    import { resolve } from "path";
    import fs from 'fs'
    
    function pathResolve(dir: string) {
      return resolve(process.cwd(), ".", dir);
    }
    
    // https://vitejs.dev/config/
    export default () => {
      const lessResources: Array = []
      fs.readdirSync('src/assets/styles').map((dirname) => {
        if (fs.statSync(`src/assets/styles/${dirname}`).isFile()) {
          lessResources.push(`@import "src/assets/styles/${dirname}";`)
        }
      })
      return {
        ......,
      // css
        css: {
          preprocessorOptions: {
            less: {
              charset: false,
              additionalData: lessResources.join(''),
              modifyVars: {
                'primary-color': '#0080FF',
                'link-color': '#0080FF',
                'border-radius-base': '4px',
              },
              javascriptEnabled: true,
            },
          },
        },
      };
    };
    复制代码

     

    这里配置的公共less文件路径为src/assets/styles,创建styles文件夹和index.less文件

     进入index.less声明全局样式,测试less配置是否成功

     进入test/index.vue使用声明

     查看页面

    盒子背景颜色改变,less及全局less配置成功!

     

    八.配置svg

    yarn add vite-plugin-svg-icons -D
    yarn add fast-glob -D
    vite.config.ts引入插件
    复制代码
    // vite.config.ts
    
    import vue from "@vitejs/plugin-vue";
    import { createSvgIconsPlugin } from "vite-plugin-svg-icons";
    import path from "path";
    
    // https://vitejs.dev/config/
    export default () => {
      return {
        ......,
        plugins: [
          vue(),
          createSvgIconsPlugin({
            // 指定需要缓存的图标文件夹
              iconDirs: [path.resolve(process.cwd(), "src/assets/icons")],
            // 指定symbolId格式
              symbolId: "icon-[dir]-[name]",
          }),
        ],
      };
    };
    复制代码

    根据config配置创建存放svg的目录文件,并创建SvgIcon组件

     SvgIcon组件

    复制代码
    // SvgIcon/index.vue
    
    
    
    
    
    复制代码

    在main.ts中注册SvgIcon为全局组件

    复制代码
    // main.ts
    
    import { createApp } from 'vue'
    import './style.css'
    import "virtual:svg-icons-register";
    import SvgIcon from "@/components/SvgIcon/index.vue";
    
    import App from './App.vue'
    import router from "./router";
    
    const app = createApp(App as any);
    app.use(router)
    
    app.mount('#app')
    app.component("SvgIcon", SvgIcon);
    复制代码

    在test/index.vue中引入组件

    // test/index.vue
    
    

    查看页面,测试是否成功

     页面显示svg图标,svg组件配置成功!

     

    九.配置pinia

    pinia: 类似vuex的仓库
    pinia-use-persist: 持久加密缓存pinia数据
    yarn add pinia pinia-use-persist -S

    main.ts中引入pinia

    复制代码
    // main.ts
    
    import { createApp } from 'vue'
    import { createPinia } from 'pinia'
    import { usePersist } from 'pinia-use-persist'
    
    import App from './App.vue'
    
    const app = createApp(App as any);
    const pinia = createPinia()
    pinia.use(usePersist)
    app.use(pinia)
    复制代码

    src下创建store目录存放相关文件

     /store/modules下存放项目不同模块需要通过pinia通信的数据,假装项目有一个test模块,存放了一个数据number

    复制代码
    // store/modules/test/index.ts
    
    import { defineStore } from "pinia";
    
    interface stateType {
      number: number;
    }
    
    const useTestStore = defineStore("user", {
      state: (): stateType => ({
        number: 0,
      }),
    
      getters: {},
    
      actions: {
        setNumber(number: number): void {
          this.number = number;
        },
      },
    
      persist: {
        enabled: true,
        encryptionKey: "vueTest",
      },
    });
    
    export { useTestStore };
    复制代码

    store/index.ts引入各模块

    复制代码
    // store/index.ts
    
    import { createPinia } from "pinia";
    import { useTestStore } from "./modules/test";
    
    const pinia = createPinia();
    
    export { useTestStore };
    export default pinia;
    复制代码

    回到test/index.vue,测试pinia配置是否成功

    复制代码
    // test/index.vue
    
    
    
    
    复制代码

    点击按钮,刷新后查看页面是否变化

    页面数据没有初始化,pinia配置成功!

     

    十.配置vant ui

    vant ui:https://vant-contrib.gitee.io/vant/v4/#/zh-CN/home

    1
    yarn add vant

    这里再推荐一个插件,unplugin-vue-components【自动引入】,引入ui可以省去很多麻烦

    1
    yarn add unplugin-vue-components -D

    vite.config.ts中引入vant ui

    复制代码
    // vite.config.ts
    
    import vue from '@vitejs/plugin-vue';
    import Components from 'unplugin-vue-components/vite';
    import { VantResolver } from 'unplugin-vue-components/resolvers';
    
    export default {
      plugins: [
        vue(),
        Components({
          resolvers: [VantResolver()],
        }),
      ],
    };
    复制代码

    回到test/index.vue测试vant ui引入是否成功

    复制代码
    // test/index.vue
    
    
    
    vant button
    复制代码

    刷新页面查看

     

     

     按钮有样式,vant ui引入成功!

    但是官方描述:Vant 中有个别组件是以函数的形式提供的,包括 Toast,Dialog,Notify 和 ImagePreview 组件。在使用函数组件时,unplugin-vue-components 无法自动引入对应的样式,因此需要手动引入样式。

    所以,这几个组件需要使用的话需要在main.ts中引入样式

    复制代码
    // main.ts
    
    // Toast
    import 'vant/es/toast/style';
    // Dialog
    import 'vant/es/dialog/style';
    // Notify
    import 'vant/es/notify/style';
    // ImagePreview
    import 'vant/es/image-preview/style';
    复制代码

    回到test/index.vue测试,示例toast

    // test/index.vue
    
    import { Toast } from 'vant'
    
    Toast('使用vant')

    查看页面

     

     

     toast有样式,vant ui引入成功!

    但是,使用vant ui多是移动端,所以还要做移动端做以下适配

    参考: https://vant-contrib.gitee.io/vant/v4/#/zh-CN/advanced-usage

    1.适配安全距离

    根据vant ui提供,在根文件index.html修改

    复制代码
    // index.html
    
      
      
        content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, viewport-fit=cover" />
    
      
      
    
      
      
    复制代码

    2.Viewport 布局

    postcss-px-to-viewport-8-plugin:postcss-px-to-viewport-8-plugin 是一款 PostCSS 插件,用于将 px 单位转化为 vw/vh 单位。

    1
    yarn add postcss-px-to-viewport-8-plugin -D

    vite.config.ts中更改配置

    复制代码
    // vite.config.ts
    
    import pxtovw from 'postcss-px-to-viewport-8-plugin'
    const loder_pxtovw = pxtovw({
    //这里是设计稿宽度 自己修改
      viewportWidth: 375,
      viewportUnit: 'vw'
    })
    export default defineConfig({
      ......,
      css: {
        postcss: {
          plugins: [loder_pxtovw]
        }
      }
    })
    复制代码

    创建一个types/index.d.ts,用于处理包括postcss-px-to-viewport-8-plugin一类的没有声明文件的依赖

    // src/types/index.d.ts
    
    declare module "postcss-px-to-viewport-8-plugin"

    刷新页面,F12查看样式

     px已被转换,vant ui 及 移动端配置成功!

     

    十一.配置axios

    1
    yarn add axios

     tsconfig.json:types里加上"vite/client"

    复制代码
    // tsconfig.json
    
    {
      "compilerOptions": {
        ......,
        "types": ["vite/client", "vite-plugin-svg-icons/client"]
      },
      "include": [
        "src/**/*.ts",
        "src/**/*.d.ts",
        "src/**/*.tsx",
        "src/**/*.vue",
        "*.ts",
      ],
      "exclude": ["node_modules", "dist"],
      "references": [{ "path": "./tsconfig.node.json" }]
    }
    复制代码

    src下创建axios请求文件

     创建axios

    复制代码
    // utils/http/axios/index.ts
    
    import axios, {
      AxiosInstance,
      AxiosRequestConfig,
      AxiosResponse,
      AxiosError,
    } from "axios";
    import { IResponse } from "./type";
    
    // 如果请求超过 `timeout` 的时间,请求将被中断
    axios.defaults.timeout = 5000;
    
    const axiosInstance: AxiosInstance = axios.create({
      baseURL: import.meta.env.VITE_APP_API_BASEURL + "",
    });
    
    // axios实例拦截请求
    axiosInstance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        // 配置headers
        config.headers = {
          ...config.headers,
        };
        return config;
      },
      (error: any) => {
        return Promise.reject(error);
      }
    );
    
    // axios实例拦截响应
    axiosInstance.interceptors.response.use(
      // 请求成功
      (response: AxiosResponse) => {
        return response;
      },
      // 请求失败
      (error: AxiosError) => {
        const { response } = error;
        console.error(response, "response error");
        if (response) {
          return Promise.reject(response.data);
        }
      }
    );
    
    const request = (config: AxiosRequestConfig): Promise => {
      const conf = config;
      return new Promise((resolve) => {
        axiosInstance
          .request>(conf)
          .then((res: AxiosResponse) => {
            const {
              data: { result },
            } = res;
            resolve(result as T);
          });
      });
    };
    
    export function get(config: AxiosRequestConfig): Promise {
      return request({ ...config, method: "GET" });
    }
    
    export function post(config: AxiosRequestConfig): Promise {
      return request({ ...config, method: "POST" });
    }
    
    export default request;
    export type { AxiosInstance, AxiosResponse };
    复制代码
    复制代码
    // utils/http/axios/type.ts
    
    export interface RequestOptions {
        // Whether to process the request result
        isTransformResponse?: boolean;
    }
    
    // 返回res.data的interface
    export interface IResponse {
        code: number | string;
        result: T;
        data: T;
        message: string;
        status: string | number;
    }
    复制代码

    根目录创建.env.development配置开发请求地址

    复制代码
    // .env.development
    
    # 开发环境
    
    VITE_APP_API_BASEURL = 你的请求地址
    
    NODE_ENV = development
    复制代码

    vite.config.ts配置server

    复制代码
    // vite.config.ts
    
        server: {
          hmr: { overlay: false }, // 禁用或配置 HMR 连接 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层
                // 服务配置
                port: 3030, // 类型: number 指定服务器端口;
                open: false, // 类型: boolean | string在服务器启动时自动在浏览器中打开应用程序;
                cors: false, // 类型: boolean | CorsOptions 为开发服务器配置 CORS。默认启用并允许任何源
               host: "0.0.0.0", // IP配置,支持从IP启动
               ["/api"]: {
            target: process.env.VITE_APP_API_BASEURL,
            changeOrigin: true,
            rewrite: (path: string) => path.replace(new RegExp("^/api"), ""),
          },
        },
    复制代码

    创建api存放目录

      创建一个api

    复制代码
    // api/test/index.ts
    
    import { post } from "@/utils/http/axios";
    import { IResponse } from "@/utils/http/axios/type";
    
    export interface LoginData {
      username?: string;
      password?: string;
    }
    
    enum URL {
      login = "/api/user_center/testLogin",
    }
    
    /**
     * @description: 用户登录
     * @params {LoginData} params
     * @return {Promise}
     */
    
    const login = async (data: LoginData) =>
      post({ url: URL.login, data });
    
    export { login };
    复制代码

    回到test/index.vue调用api测试axios

    复制代码
    // test/index.vue
    
    
    复制代码

    回到页面,查看network

     接口请求成功,axios配置成功!

     最后,配置一下打包

    复制代码
    // vite.config.ts
    
    import { UserConfig, ConfigEnv, loadEnv } from "vite";
    
    // https://vitejs.dev/config/
    export default ({ command, mode }: ConfigEnv): UserConfig => {
      const env = loadEnv(mode, __dirname);
      return {
        base: env.NODE_ENV === "development" ? "/" : "./",
        build: {
          outDir: "dist",
          assetsDir: "assets", //指定静态资源存放路径
            sourcemap: false, //是否构建source map 文件
        },
      };
    };
    复制代码

    启动dist,没问题!

     

     

    结语:

    项目到此主体功能就已经配置完毕了,细节之处大家多多查看官网和众多网友的分享

    项目还有很多不完善甚至错误的地方,踩坑还会继续,后续有时间还会继续优化,实际使用中还有很多地方需要改进

     

    项目同步git:https://gitee.com/lixin_ajax/vue3-vite-ts-pinia-vant-less.git

  • 相关阅读:
    【iOS】UICollectionView的基本使用
    微服务架构的未来:跨边界的云原生整合
    keras训练的H5模型转tflite
    从零开始 Spring Boot 17:MyBatis Plus 续
    复习单片机:定时器/计数器部分(内含:1.51 单片机定时器原理 +2.51 单片机定时/计数器结构+3.定时器配置+4.代码部分+5.实验现象)
    百度地图API-初步使用(2)
    Layui自定义列表多选
    DSP2335的LED工程笔记
    力控软件与2台200Smart之间无线以太网通信
    网络间串扰降噪推荐掌握的经验法则
  • 原文地址:https://www.cnblogs.com/jing-zhe/p/16895284.html