# vite-vue3-ts-starter **Repository Path**: zsj265/vite-vue3-ts-starter ## Basic Information - **Project Name**: vite-vue3-ts-starter - **Description**: ✨一款基于Vite + Vue3 + TypeScript + Pinia + Element Plus + Sass + Axios的快速开发模版 - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2024-11-20 - **Last Updated**: 2025-09-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # vite-vue3-ts-starter ⭐一款基于Vite + Vue3 + TypeScript + Pinia + Element Plus + Sass + Axios的快速开发模版 ## 项目启动 ```bash npm install // 安装依赖 npm run dev // 开发 npm run build // 打包 npm run preview // 预览 ``` ![](https://github.com/zhang2657977442/MyPicGo/blob/master/vite-vue3-ts-starter/%E6%88%AA%E5%9B%BE1.png) ## 功能集成 - [√ 配置 ip 访问项目](#ip) - [√ 配置多环境变量](#env) - [√ 配置 alias 别名](#alias) - [√ Sass 全局样式](#sass) - [√ 识别 nodejs 内置模块](#node) - [√ Vue-router自动生成路由](#router) - [√ Pinia 状态管理](#pinia) - [√Axios 封装及接口管理](#axios) - [√ 配置 proxy 跨域](#proxy) - [√ Element Plus 自动按需引入](#element) - [√Markdown预览](#markdown) - [√ Eslint + Prettier 统一开发规范](#prettier) ## ✅ 配置 ip 访问项目 - vite 启动后出现 “ Network: use --host to expose ” ```js vite v2.3.7 dev server running at: > Local: http://localhost:3000/ > Network: use `--host` to expose ``` - 是因为 IP 没有做配置,所以不能从 IP 启动,需要在 vite.config.js 做相应配置: 在 vite.config.js 中添加 server.host 为 0.0.0.0 ```typescript export default defineConfig({ plugins: [vue()], // 在文件中添加以下内容 server: { host: '0.0.0.0' } }) ``` - 重新启动后显示 ```js vite v2.3.7 dev server running at: > Local: http://localhost:3000/ > Network: http://192.168.199.127:3000/ ``` ## ✅ 配置多环境变量 - 文档:https://cn.vitejs.dev/guide/env-and-mode.html * 在生产环境,会把 import.meta.env 的值转换成对应真正的值 1. 添加环境变量文件,每个文件写入配置,**定义 env 环境变量前面必须加 VITE\_** - `.env.development` ```js # must start with VITE_ VITE_ENV = 'development' VITE_OUTPUT_DIR = 'dev' ``` - `.env.production` ```js # must start with VITE_ VITE_ENV = 'production' VITE_OUTPUT_DIR = 'dist' ``` - `.env.test` ```js # must start with VITE_ VITE_ENV = 'test' VITE_OUTPUT_DIR = 'test' ``` 2. 修改 scripts 命令 - `--mode` 用来识别我们的环境 ```js "dev": "vite --mode development", "test": "vite --mode test", "prod": "vite --mode production", ``` 3. 在项目中访问 ```js console.log(import.meta.env) ``` 4. typescript 智能提示 - 修改 `src/env.d.ts` 文件,如果没有创建一个 ```js /// interface ImportMetaEnv extends Readonly> { readonly VITE_ENV: string; // 环境 readonly VITE_OUTPUT_DIR: string; // 打包目录 } interface ImportMeta { readonly env: ImportMetaEnv; } ``` ## ✅ 配置 alias 别名 - 文档:https://cn.vitejs.dev/config/#resolve-alias - 修改 vite.config.ts 配置 ```js resolve: { alias: { "@": "/src", }, }, ``` ## ✅ Sass 全局样式 - 文档:https://cn.vitejs.dev/guide/features.html#css-pre-processors 1. 安装依赖 使用`dart-sass`, 安装速度比较快,大概率不会出现安装不成功 ```js npm i -D sass ``` 2. 使用 每个页面自己对应的样式都写在自己的 .vue 文件之中 `scoped` 它顾名思义给 css 加了一个域的概念。 ```html ``` ### vite 识别 sass 全局变量 - 文档:https://cn.vitejs.dev/config/#css-preprocessoroptions * vite.config.js 添加配置 ```js css: { preprocessorOptions: { scss: { additionalData: ` @import "@/styles/mixin.scss"; @import "@/styles/variables.scss"; `, }, }, }, ``` ## ✅ 识别 nodejs 内置模块 - path 模块是 node.js 内置的功能,但是 node.js 本身并不支持 typescript,所以直接在 typescript 项目里使用是不行的 - 解决方法:安装@types/node ```js npn i -D @types/node ``` - 在 vite.config.js 中使用 ```js import { resolve } from 'path' ``` ## ✅ Vue-router自动生成路由 - 文档:https://next.router.vuejs.org/zh/installation.html ### 1. 安装依赖 ```ts npm install vue-router npm install vite-plugin-pages -D ``` ### 2. 配置自动生成路由 - 在 src 目录下,新建 router 文件夹,并在文件夹内创建 - index.ts 配置自动生成路由 ```ts import { createRouter, createWebHistory } from 'vue-router'; import routes from 'pages-generated'; const router = createRouter({ history: createWebHistory(), // HashHistory routes, }); export default router; ``` + vite.config.js 添加配置,自动根据src/views下的文件生成路由 ```ts export default defineConfig({ plugins: [ Pages({ pagesDir: [ { dir: 'src/views', baseRoute: '', }, ], exclude: ['**/components/*.vue'], }), ] }); ``` ### 3. mian 中引入 router ```ts import { createApp } from 'vue' import router from './router' import App from './App.vue' // 引入全局样式 import '@/styles/index.scss' const app = createApp(App) app.use(router) app.mount('#app') ``` ### 4. app.vue 和 layout 配置 router-view ```ts // app.vue ``` ## ✅ Pinia 状态管理 - 文档:https://pinia.vuejs.org/ - 参考资料:https://juejin.cn/post/7049196967770980389 - Pinia 的特点: - 完整的 typescript 的支持; - 足够轻量,压缩后的体积只有 1.6kb; - 去除 mutations,只有 state,getters,actions(这是我最喜欢的一个特点); - actions 支持同步和异步; - 没有模块嵌套,只有 store 的概念,store 之间可以自由使用,更好的代码分割; - 无需手动添加 store,store 一旦创建便会自动添加; ### 安装依赖 ```js npm i pinia ``` ### 创建 Store - 新建 src/store 目录并在其下面创建 index.ts,导出 store ```js // src/store/index.ts import { createPinia } from 'pinia' const store = createPinia() export default store ``` ### 在 main.ts 中引入并使用 ```ts // src/main.ts import { createApp } from 'vue' import App from './App.vue' import store from './store' const app = createApp(App) app.use(store) ``` ### 定义 State - 在 src/store 下面创建一个 user.ts ```ts //src/store/user.ts import { defineStore } from 'pinia' import { useAppStore } from './app' export const useUserStore = defineStore({ id: 'user', state: () => { return { name: '张三', age: 18 } }, getters: { fullName: (state) => { return state.name + '丰' } }, actions: { updateState(data: any) { this.$state = data this.updateAppConfig() }, updateAppConfig() { const appStore = useAppStore() appStore.setData('app-update') } } }) ``` ```ts //src/store/app.ts import { defineStore } from 'pinia' export const useAppStore = defineStore({ id: 'app', state: () => { return { config: 'app' } }, actions: { setData(data: any) { console.log(data) this.config = data } } }) ``` ### 获取/更新 State ```vue ``` ### 数据持久化 - 文档:https://github.com/prazdevs/pinia-plugin-persistedstate * 插件 pinia-plugin-persistedstate 可以辅助实现数据持久化功能。 * 数据默认存在 sessionStorage 里,并且会以 store 的 id 作为 key。 * 安装依赖 ```ts npm i pinia-plugin-persistedstate ``` - 引用插件 ```ts // src/store/index.ts import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' const store = createPinia() store.use(piniaPluginPersistedstate) export default store ``` - 在对应的 store 里开启 persist 即可 ```ts export const useUserStore = defineStore({ id: 'user', state: () => { return { name: '张三' } }, // 开启数据缓存 persist: { key: 'user', storage: sessionStorage, // 数据存储位置,默认为 localStorage paths: ['name'], // 用于部分持久化状态的点表示法路径数组,表示不会持久化任何状态(默认为并保留整个状态) overwrite: true } }) ``` ## ✅ Axios 封装及接口管理  ### 安装依赖 ```js npm i axios ``` ### 封装Axios 在src/service/下创建request.ts文件来封装axios ```typescript import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; class HttpRequest { getInsideConfig() { const config = { baseURL: import.meta.env.VITE_API_BASE_URL, // 所有的请求地址前缀部分(没有后端请求不用写) timeout: 80000, // 请求超时时间(毫秒) withCredentials: true, // 异步请求携带cookie // headers: { // 设置后端需要的传参类型 // 'Content-Type': 'application/json', // 'token': x-auth-token',//一开始就要token // 'X-Requested-With': 'XMLHttpRequest', // }, }; return config; } // 请求拦截 interceptors(instance: AxiosInstance, url: string | number | undefined) { instance.interceptors.request.use( (config) => { // 添加全局的loading.. // 请求头携带token return config; }, (error: any) => { return Promise.reject(error); } ); //响应拦截 instance.interceptors.response.use( (res) => { //返回数据 const { data } = res; console.log('返回数据处理', res); return data; }, (error: any) => { console.log('error==>', error); return Promise.reject(error); } ); } request(options: AxiosRequestConfig) { const instance = axios.create(); options = Object.assign(this.getInsideConfig(), options); this.interceptors(instance, options.url); return instance(options); } } const http = new HttpRequest(); export default http; ``` ### 接口管理 在src/apis/下创建user.ts文件用来管理用户相关的接口 ```typescript import http from '../service/request'; const PREFIX = 'user'; export const getTest = (params: any) => { return http.request({ url: `${PREFIX}/test`, method: 'post', params, }); }; ``` ## ✅ 配置 proxy 跨域 在vite.config.ts进行如下配置 ```typescript export default defineConfig({ plugins: [vue()], // 在文件中添加以下内容 server: { proxy: { '/api': { target: 'http://xxxxxxxxxxxxxxx', changeOrigin: true, rewrite: (path) => path.replace(/^\/api/, ''), }, }, } }) ``` ## ✅ Element Plus 自动按需引入 ### 安装依赖 ```bash npm i element-plus npm i -D @iconify-json/ep unplugin-auto-import unplugin-icons unplugin-vue-components ``` 在vite.config.ts进行如下配置 ```typescript import AutoImport from 'unplugin-auto-import/vite'; import Components from 'unplugin-vue-components/vite'; import Icons from 'unplugin-icons/vite'; import IconsResolver from 'unplugin-icons/resolver'; import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'; export default defineConfig({ plugins: [ AutoImport({ resolvers: [ ElementPlusResolver(), // 自动导入图标组件 IconsResolver({ prefix: 'Icon', }), ], dts: path.resolve(__dirname, 'types/auto-imports.d.ts'), }), Components({ resolvers: [ ElementPlusResolver(), // 自动注册图标组件 IconsResolver({ enabledCollections: ['ep'], }), ], dts: path.resolve(__dirname, 'types/components.d.ts'), }), Icons({ autoInstall: true, }), ], }) ``` ## ✅ Markdown预览 ### 安装依赖 ```bash npm i highlight.js npm i -D vite-plugin-md ``` 在vite.config.ts进行如下配置 ```typescript import Markdown from 'vite-plugin-md'; import hljs from 'highlight.js'; export default defineConfig({ plugins: [ Markdown({ markdownItOptions: { html: true, linkify: true, typographer: true, highlight: function (str, lang) { if (lang && hljs.getLanguage(lang)) { try { return ( '
' +
                hljs.highlight(str, { language: lang, ignoreIllegals: true })
                  .value +
                '
' ); } catch (__) {} } return ''; }, }, }), ], }) ``` 在vue组件中使用 ```vue ``` ## ✅ Eslint + Prettier 统一开发规范 ### 1. 安装依赖 ```js npm i -D eslint eslint-plugin-vue prettier @vue/eslint-config-prettier @vue/eslint-config-typescript @rushstack/eslint-patch ``` ### 2. 编写相关文件 - .eslintrc.js ```js /* eslint-env node */ require('@rushstack/eslint-patch/modern-module-resolution') module.exports = { root: true, extends: [ 'plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-typescript/recommended', '@vue/eslint-config-prettier' ], env: { 'vue/setup-compiler-macros': true }, parserOptions: { ecmaVersion: 12 }, rules: { 'prettier/prettier': 'warn', '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-unused-vars': 'off' } } ``` - .prettierc.js ```js module.exports = { // 定制格式化要求 overrides: [ { files: '.prettierrc', options: { parser: 'json' } } ], printWidth: 100, // 一行最多 100 字符 tabWidth: 2, // 使用 4 个空格缩进 semi: false, // 行尾需要有分号 singleQuote: true, // 使用单引号而不是双引号 useTabs: false, // 用制表符而不是空格缩进行 quoteProps: 'as-needed', // 仅在需要时在对象属性两边添加引号 jsxSingleQuote: false, // 在 JSX 中使用单引号而不是双引号 trailingComma: 'none', // 末尾不需要逗号 bracketSpacing: true, // 大括号内的首尾需要空格 bracketSameLine: false, // 将多行 HTML(HTML、JSX、Vue、Angular)元素反尖括号需要换行 arrowParens: 'always', // 箭头函数,只有一个参数的时候,也需要括号 avoid rangeStart: 0, // 每个文件格式化的范围是开头-结束 rangeEnd: Infinity, // 每个文件格式化的范围是文件的全部内容 requirePragma: false, // 不需要写文件开头的 @prettier insertPragma: false, // 不需要自动在文件开头插入 @prettier proseWrap: 'preserve', // 使用默认的折行标准 always htmlWhitespaceSensitivity: 'css', // 根据显示样式决定 html 要不要折行 vueIndentScriptAndStyle: false, //(默认值)对于 .vue 文件,不缩进