# vue3-ts-vite-template **Repository Path**: LHD86/vue3-ts-vite-template ## Basic Information - **Project Name**: vue3-ts-vite-template - **Description**: vue3+ts+vite的前端框架模板 - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-08-19 - **Last Updated**: 2024-01-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: Vue, TypeScript ## README # Vue 3 + TypeScript + Vite 框架模板 ## 一、技术栈 - 请求:axios - 路由:pinia - 开发语言:TypeScript - 构建工具:Vite - 包管理命令:yarn ## 二、目录文件配置 ### 1. 目录结构 ```apl 项目文件根目录 - build: - plugins: 插件目录 - public: 公共资源 - src: 资源目录 - assets: 静态名 - components: 非路由组件组件 - hooks: hook函数文件列表 - router: 路由文件 - store: - modules: - styles: 样式文件 - untils: 工具 - views: 路由组件 - types: 公共类型声明 - auto-imports.d.ts: 自动导入配置 - components.d.ts: 组件导入 - vite-env.d.ts: 自定义组件导入 - ``` ### 2. vite.config.ts基本配置 ```ts import { UserConfig, ConfigEnv } from 'vite'; import { createVitePlugins } from './build/vite/plugins'; import { resolve } from 'path'; import proxy from './build/vite/proxy'; import { VITE_PORT } from './build/constant'; function pathResolve(dir: string) { return resolve(process.cwd(), '.', dir); } // https://vitejs.dev/config/ export default ({ command }: ConfigEnv): UserConfig => { const isBuild = command === 'build'; let base: string; if (command === 'build') { base = '/fast-vue3/'; } else { base = '/'; } return { base, resolve: { alias: [ { find: 'vue-i18n', replacement: 'vue-i18n/dist/vue-i18n.cjs.js', }, // /@/xxxx => src/xxxx { find: /\/@\//, replacement: pathResolve('src') + '/', }, // /#/xxxx => types/xxxx { find: /\/#\//, replacement: pathResolve('types') + '/', }, ], }, // plugins plugins: createVitePlugins(isBuild), // css css: {}, // server server: { hmr: { overlay: false }, // 禁用或配置 HMR 连接 设置 server.hmr.overlay 为 false 可以禁用服务器错误遮罩层 // 服务配置 port: VITE_PORT, // 类型: number 指定服务器端口; open: false, // 类型: boolean | string在服务器启动时自动在浏览器中打开应用程序; cors: false, // 类型: boolean | CorsOptions 为开发服务器配置 CORS。默认启用并允许任何源 host: '0.0.0.0', // IP配置,支持从IP启动 proxy, }, }; }; ``` ## 三、封装plugins数组 ### 1. 封装插件流程 > 下面是导入插件的流程 - 创建目录,与src目录同级 ![image-20230721204626534](https://raw.githubusercontent.com/Keep-Fight/learn-notes/main/imgs/202307251209153.png) - 创建插件ts文件 ![image-20230721205349146](https://raw.githubusercontent.com/Keep-Fight/learn-notes/main/imgs/202307251209863.png) - 在plugins的index.ts文件目录下导入cha'dchad插件ts文件, > **这个地方是导入插件的地方,创建插件ts文件以后需要在这里导入** ```ts /** * @name createVitePlugins * @description 封装plugins数组统一调用 */ import { PluginOption } from 'vite'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; import VitePluginCertificate from 'vite-plugin-mkcert'; import vueSetupExtend from 'vite-plugin-vue-setup-extend'; import { ConfigSvgIconsPlugin } from './svgIcons'; import { AutoRegistryComponents } from './component'; import { AutoImportDeps } from './autoImport'; import { ConfigMockPlugin } from './mock'; import { ConfigVisualizerConfig } from './visualizer'; import { ConfigCompressPlugin } from './compress'; import { ConfigPagesPlugin } from './pages'; import { ConfigRestartPlugin } from './restart'; import { ConfigProgressPlugin } from './progress'; import { ConfigImageminPlugin } from './imagemin'; import { ConfigUnocssPlugin } from './unocss'; export function createVitePlugins(isBuild: boolean) { const vitePlugins: (PluginOption | PluginOption[])[] = [ // vue支持 vue(), // JSX支持 vueJsx(), // setup语法糖组件名支持 vueSetupExtend(), // 提供https证书 VitePluginCertificate({ source: 'coding', }) as PluginOption, ]; // 自动按需引入组件 vitePlugins.push(AutoRegistryComponents()); // 自动按需引入依赖 vitePlugins.push(AutoImportDeps()); // 自动生成路由 vitePlugins.push(ConfigPagesPlugin()); // 开启.gz压缩 rollup-plugin-gzip vitePlugins.push(ConfigCompressPlugin()); // 监听配置文件改动重启 vitePlugins.push(ConfigRestartPlugin()); // 构建时显示进度条 vitePlugins.push(ConfigProgressPlugin()); // unocss vitePlugins.push(ConfigUnocssPlugin()); // vite-plugin-svg-icons vitePlugins.push(ConfigSvgIconsPlugin(isBuild)); // vite-plugin-mock vitePlugins.push(ConfigMockPlugin(isBuild)); // rollup-plugin-visualizer vitePlugins.push(ConfigVisualizerConfig()); vitePlugins.push(ConfigImageminPlugin()); return vitePlugins; } ``` - 在vite.config.ts中导入插件(只操作一次) ```ts import { UserConfig, ConfigEnv } from 'vite'; import { createVitePlugins } from './build/vite/plugins'; import { resolve } from 'path'; import proxy from './build/vite/proxy'; import { VITE_PORT } from './build/constant'; function pathResolve(dir: string) { return resolve(process.cwd(), '.', dir); } // https://vitejs.dev/config/ export default ({ command }: ConfigEnv): UserConfig => { const isBuild = command === 'build'; let base: string; if (command === 'build') { base = '/fast-vue3/'; } else { base = '/'; } return { base, // plugins plugins: createVitePlugins(isBuild), // css css: {}, }; }; ``` ### 2. 常用的插件 #### (1)按需自动导入API > 在此导入以后会自动导入使用的组件比如**ref**,组件中不用在声明 - 安装插件 ```shell npm i -D unplugin-auto-import yarn add -D unplugin-auto-import ``` - 创建autoImport.ts ```ts /** * @name AutoImportDeps * @description 按需加载,自动引入 */ import AutoImport from 'unplugin-auto-import/vite'; export const AutoImportDeps = () => { return AutoImport({ dts: 'types/auto-imports.d.ts', imports: [ 'vue', 'pinia', 'vue-router', { '@vueuse/core': [], }, ], }); }; ``` - 导入插件 ```ts /** * @name createVitePlugins * @description 封装plugins数组统一调用 */ import { PluginOption } from 'vite'; import vue from '@vitejs/plugin-vue'; import vueJsx from '@vitejs/plugin-vue-jsx'; import VitePluginCertificate from 'vite-plugin-mkcert'; import vueSetupExtend from 'vite-plugin-vue-setup-extend'; import { AutoRegistryComponents } from './component'; export function createVitePlugins(isBuild: boolean) { const vitePlugins: (PluginOption | PluginOption[])[] = [ // vue支持 vue(), // JSX支持 vueJsx(), // setup语法糖组件名支持 vueSetupExtend(), // 提供https证书 VitePluginCertificate({ source: 'coding', }) as PluginOption, ]; // 自动按需引入组件 vitePlugins.push(AutoRegistryComponents()); return vitePlugins; } ``` - 使用示例 > 以下是自动生成的文件, ```ts // Generated by 'unplugin-auto-import' export {}; declare global { const reactive: typeof import('vue')['reactive']; const ref: typeof import('vue')['ref']; ..... } ``` > 组件中使用 ```vue ``` #### (2)按需自动导入组件 - 安装插件 ```shell npm install unplugin-vue-components -D yarn add unplugin-vue-components -D ``` - 创建component.ts ```ts /** * @name AutoRegistryComponents * @description 按需加载,自动引入组件 */ import Components from 'unplugin-vue-components/vite'; import { ElementPlusResolver, VueUseComponentsResolver } from 'unplugin-vue-components/resolvers'; export const AutoRegistryComponents = () => { return Components({ dirs: ['src/components'], extensions: ['vue'], deep: true, // 需要创建相应的文件夹 dts: 'types/components.d.ts', directoryAsNamespace: false, globalNamespaces: [], directives: true, importPathTransform: (v) => v, allowOverrides: false, include: [/\.vue$/, /\.vue\?vue/], exclude: [/[\\/]node_modules[\\/]/, /[\\/]\.git[\\/]/, /[\\/]\.nuxt[\\/]/], resolvers: [ElementPlusResolver(), VueUseComponentsResolver()], }); }; ``` - 在上面导入插件 #### (3)按需导入svg - 安装插件 ```shell yarn add -D vite-plugin-svg-icons ``` - 创建src/assets/icons文件夹 - 在src\components\SvgIcon文件夹下创建index.ts,内容如下 ```ts ``` - 在main.ts配置信息 ```ts import { createApp } from 'vue'; import App from './App.vue'; // 支持SVG import 'virtual:svg-icons-register'; createApp(App).mount('#app'); ``` - svg的使用 ```vue ``` #### (4)其他插件 > 安装都是 > > ```shell > yarn add -D vite-plugin-compression > x yarn add -D 插件名 > > ``` - **compress.ts** ```ts /** * @name ConfigCompressPlugin * @description 开启.gz压缩 */ import viteCompression from 'vite-plugin-compression'; import { COMPRESSION } from '../../constant'; export const ConfigCompressPlugin = () => { if (COMPRESSION) { return viteCompression({ verbose: true, // 默认即可 disable: false, //开启压缩(不禁用),默认即可 deleteOriginFile: false, //删除源文件 threshold: 10240, //压缩前最小文件大小 algorithm: 'gzip', //压缩算法 ext: '.gz', //文件类型 }); } return []; }; ``` - **imagemin.ts** ```ts import viteImagemin from 'vite-plugin-imagemin'; export function ConfigImageminPlugin() { const plugin = viteImagemin({ gifsicle: { optimizationLevel: 7, interlaced: false, }, mozjpeg: { quality: 20, }, optipng: { optimizationLevel: 7, }, pngquant: { quality: [0.8, 0.9], speed: 4, }, svgo: { plugins: [ { name: 'removeViewBox', }, { name: 'removeEmptyAttrs', active: false, }, ], }, }); return plugin; } ``` - **mock.ts** ```ts /** * @name ConfigMockPlugin * @description 引入mockjs,本地模拟接口 */ import { viteMockServe } from 'vite-plugin-mock'; export const ConfigMockPlugin = (isBuild: boolean) => { return viteMockServe({ ignore: /^\_/, mockPath: 'mock', localEnabled: !isBuild, prodEnabled: false, //实际开发请关闭,会影响打包体积 // https://github.com/anncwb/vite-plugin-mock/issues/9 injectCode: ` import { setupProdMockServer } from '../mock/_createProdMockServer'; setupProdMockServer(); `, }); }; ``` - pages.ts ```ts /** * @name ConfigPagesPlugin * @description 动态生成路由 */ import Pages from 'vite-plugin-pages'; export const ConfigPagesPlugin = () => { return Pages({ pagesDir: [{ dir: 'src/views', baseRoute: '' }], extensions: ['vue', 'md'], exclude: ['**/components/*.vue'], nuxtStyle: true, }); }; ``` - **progress.ts** ```ts /** * @name ConfigProgressPlugin * @description 构建显示进度条 */ import progress from 'vite-plugin-progress'; export const ConfigProgressPlugin = () => { return progress(); }; ``` - **restart.ts** ```ts /** * @name ConfigRestartPlugin * @description 监听配置文件修改自动重启Vite */ import ViteRestart from 'vite-plugin-restart'; export const ConfigRestartPlugin = () => { return ViteRestart({ restart: ['*.config.[jt]s', '**/config/*.[jt]s'], }); }; ``` - visualizer.ts ```ts /** * @name ConfigUnocssPlugin * @description 监听配置文件修改自动重启Vite */ // Unocss import Unocss from 'unocss/vite'; export const ConfigUnocssPlugin = () => { return Unocss(); }; ``` ### 3. 手动导入模块 - vite-env.d.ts文件 > 经常会有导入其他模块 ```ts /// // 导入自定义组件 declare module '*.vue' { import { DefineComponent } from 'vue'; const component: DefineComponent<{}, {}, any>; export default component; } declare module 'virtual:*' { const result: any; export default result; } // 样式库模块 declare module 'element-plus'; ``` ## 四、配置代码检查 (eslint) ### 1. eslint安装 - 安装插件 ```shell npm i eslint -D yarn add eslint -D pnpm add eslint -D # 安装eslint npm install eslint --save-dev # window如果无法运行上述命令,可尝试 "node_modules/.bin/eslint" --init ``` - 初始化eslint配置文件 > 配置文件不是一步生成的,这里是要在终端进行进一步的选择,比如你使用的框架,使用的语言,代码模块化的风格等等 ```shell # 初始化配置,eslint同时可作为命令行工具使用 ./node_modules/.bin/eslint --init # window如果无法运行上述命令,可尝试 "node_modules/.bin/eslint" --init # 初始化配置 npx eslint --init ``` - **vite集成eslint** > 安装一个插件ts > > ```shell > yarn add vite-plugin-eslint -D > ``` ```json import { defineConfig } from 'vite' import eslint from 'vite-plugin-eslint' export default defineConfig({ plugins: [ eslint({ include: ['src/**/*.ts', 'src/**/*.tsx', 'src/**/*.vue'], exclude: ['node_modules'], cache:false }) ] }) ``` ### 2. eslint配置 #### (1)配置.eslintrc.cjs - 在配置文件中添加规则 > eslint的规则往往是公司项目领导来决定,**下面是一个简单的模板** ```json rules: { // eslint(https://eslint.bootcss.com/docs/rules/) 'no-var': 'error', // 要求使用 let 或 const 而不是 var 'no-multiple-empty-lines': ['warn', { max: 1 }], // 不允许多个空行 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', 'no-unexpected-multiline': 'error', // 禁止空余的多行 'no-useless-escape': 'off', // 禁止不必要的转义字符 // typeScript (https://typescript-eslint.io/rules) '@typescript-eslint/no-unused-vars': 'error', // 禁止定义未使用的变量 '@typescript-eslint/prefer-ts-expect-error': 'error', // 禁止使用 @ts-ignore '@typescript-eslint/no-explicit-any': 'off', // 禁止使用 any 类型 '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-namespace': 'off', // 禁止使用自定义 TypeScript 模块和命名空间。 '@typescript-eslint/semi': 'off', // eslint-plugin-vue (https://eslint.vuejs.org/rules/) 'vue/multi-word-component-names': 'off', // 要求组件名称始终为 “-” 链接的单词 'vue/script-setup-uses-vars': 'error', // 防止