├── .husky ├── .gitignore └── pre-commit ├── src ├── assets │ ├── style │ │ └── main.scss │ └── logo.png ├── vite-env.d.ts ├── service │ ├── api │ │ └── login │ │ │ ├── types.ts │ │ │ └── login.ts │ └── http.ts ├── App.vue ├── shims-vue.d.ts ├── main.ts ├── router │ └── index.ts ├── store │ └── main.ts └── pages │ └── login │ └── Login.vue ├── .prettierignore ├── .eslintignore ├── .gitignore ├── public └── favicon.ico ├── .prettierrc.js ├── index.html ├── tsconfig.json ├── vite.config.ts ├── package.json ├── .eslintrc.js └── README.md /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /src/assets/style/main.scss: -------------------------------------------------------------------------------- 1 | $test-color: red; -------------------------------------------------------------------------------- /src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # 忽略格式化文件 (根据项目需要自行添加) 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # eslint 忽略检查 (根据项目需要自行添加) 2 | node_modules 3 | dist 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushanpei/vite_vue3_ts/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xushanpei/vite_vue3_ts/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | npx lint-staged 6 | -------------------------------------------------------------------------------- /src/service/api/login/types.ts: -------------------------------------------------------------------------------- 1 | export interface ILoginParams { 2 | userName: string 3 | passWord: string | number 4 | } 5 | export interface ILoginApi { 6 | login: (params: ILoginParams) => Promise 7 | } 8 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/service/api/login/login.ts: -------------------------------------------------------------------------------- 1 | //login.ts 2 | import http from '@/service/http' 3 | import * as T from './types' 4 | 5 | const loginApi: T.ILoginApi = { 6 | login(params) { 7 | return http.post('/login', params) 8 | }, 9 | } 10 | 11 | export default loginApi 12 | -------------------------------------------------------------------------------- /src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import { DefineComponent } from 'vue' 3 | // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/ban-types 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import router from './router/index' 4 | import { createPinia } from 'pinia' 5 | 6 | const app = createApp(App) 7 | 8 | app.use(router) 9 | 10 | app.use(createPinia()) 11 | 12 | app.mount('#app') 13 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | tabWidth: 2, 3 | jsxSingleQuote: true, 4 | jsxBracketSameLine: true, 5 | printWidth: 100, 6 | singleQuote: true, 7 | semi: false, 8 | overrides: [ 9 | { 10 | files: '*.json', 11 | options: { 12 | printWidth: 200, 13 | }, 14 | }, 15 | ], 16 | arrowParens: 'always', 17 | } 18 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite App 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router' 2 | 3 | const routes: RouteRecordRaw[] = [ 4 | { 5 | path: '/', 6 | name: 'Login', 7 | component: () => import('@/pages/login/Login.vue'), 8 | }, 9 | ] 10 | 11 | const router = createRouter({ 12 | history: createWebHistory(), 13 | routes, 14 | }) 15 | 16 | export default router 17 | -------------------------------------------------------------------------------- /src/store/main.ts: -------------------------------------------------------------------------------- 1 | import { defineStore } from 'pinia' 2 | 3 | export const useMainStore = defineStore({ 4 | id: 'main', 5 | state: () => ({ 6 | name: '超级管理员', 7 | }), 8 | getters: { 9 | nameLength: (state) => state.name.length, 10 | }, 11 | actions: { 12 | async insertPost(data: string) { 13 | // 可以做异步 14 | // await doAjaxRequest(data); 15 | this.name = data 16 | }, 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "moduleResolution": "node", 6 | "strict": true, 7 | "jsx": "preserve", 8 | "sourceMap": true, 9 | "resolveJsonModule": true, 10 | "esModuleInterop": true, 11 | "lib": ["esnext", "dom"], 12 | "baseUrl": ".", 13 | "paths": { 14 | "@/*":["src/*"] 15 | } 16 | }, 17 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"] 18 | } 19 | -------------------------------------------------------------------------------- /src/pages/login/Login.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 22 | 23 | 28 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | import path from 'path' 4 | //@ts-ignore 5 | import viteCompression from 'vite-plugin-compression' 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | base: './', //打包路径 10 | plugins: [ 11 | vue(), 12 | // gzip压缩 生产环境生成 .gz 文件 13 | viteCompression({ 14 | verbose: true, 15 | disable: false, 16 | threshold: 10240, 17 | algorithm: 'gzip', 18 | ext: '.gz', 19 | }), 20 | ], 21 | // 配置别名 22 | resolve: { 23 | alias: { 24 | '@': path.resolve(__dirname, 'src'), 25 | }, 26 | }, 27 | css: { 28 | preprocessorOptions: { 29 | scss: { 30 | additionalData: '@import "@/assets/style/main.scss";', 31 | }, 32 | }, 33 | }, 34 | //启动服务配置 35 | server: { 36 | host: '0.0.0.0', 37 | port: 8000, 38 | open: true, 39 | https: false, 40 | proxy: {}, 41 | }, 42 | // 生产环境打包配置 43 | //去除 console debugger 44 | build: { 45 | terserOptions: { 46 | compress: { 47 | drop_console: true, 48 | drop_debugger: true, 49 | }, 50 | }, 51 | }, 52 | }) 53 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.0.0", 3 | "license": "ISC", 4 | "scripts": { 5 | "dev": "vite", 6 | "build:dev": "vite build --mode development", 7 | "build:pro": "vite build --mode production", 8 | "serve": "vite preview", 9 | "lint": "eslint src --fix --ext .ts,.tsx,.vue,.js,.jsx", 10 | "prettier": "prettier --write .", 11 | "prepare": "husky install" 12 | }, 13 | "dependencies": { 14 | "axios": "^0.24.0", 15 | "naive-ui": "^2.21.2", 16 | "nprogress": "^0.2.0", 17 | "pinia": "^2.0.0-rc.10", 18 | "vfonts": "^0.1.0", 19 | "vue": "^3.2.2", 20 | "vue-router": "4" 21 | }, 22 | "devDependencies": { 23 | "@babel/types": "^7.16.0", 24 | "@types/node": "^16.11.10", 25 | "@types/nprogress": "^0.2.0", 26 | "@typescript-eslint/eslint-plugin": "^5.4.0", 27 | "@typescript-eslint/parser": "^5.4.0", 28 | "@vitejs/plugin-vue": "^1.2.5", 29 | "@vue/compiler-sfc": "^3.0.5", 30 | "autoprefixer": "^10.4.0", 31 | "dart-sass": "^1.25.0", 32 | "eslint": "^8.3.0", 33 | "eslint-config-prettier": "^8.3.0", 34 | "eslint-plugin-prettier": "^4.0.0", 35 | "eslint-plugin-vue": "^8.1.1", 36 | "husky": "^7.0.4", 37 | "lint-staged": "^12.1.2", 38 | "mrm": "^3.0.10", 39 | "postcss": "^8.4.4", 40 | "prettier": "^2.4.1", 41 | "sass": "^1.44.0", 42 | "typescript": "^4.5.2", 43 | "vite": "^2.4.2", 44 | "vite-plugin-compression": "^0.3.6", 45 | "vite-plugin-eslint": "^1.3.0", 46 | "vue-tsc": "^0.0.24" 47 | }, 48 | "husky": { 49 | "hooks": { 50 | "pre-commit": "lint-staged" 51 | } 52 | }, 53 | "lint-staged": { 54 | "*.{js,jsx,vue,ts,tsx}": [ 55 | "yarn lint", 56 | "prettier --write", 57 | "git add" 58 | ] 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/service/http.ts: -------------------------------------------------------------------------------- 1 | //http.ts 2 | import axios, { AxiosRequestConfig } from 'axios' 3 | import NProgress from 'nprogress' 4 | 5 | // 设置请求头和请求路径 6 | axios.defaults.baseURL = '/api' 7 | axios.defaults.timeout = 10000 8 | axios.defaults.headers.post['Content-Type'] = 'application/json;charset=UTF-8' 9 | axios.interceptors.request.use( 10 | (config): AxiosRequestConfig => { 11 | const token = window.sessionStorage.getItem('token') 12 | if (token) { 13 | //@ts-ignore 14 | config.headers.token = token 15 | } 16 | return config 17 | }, 18 | (error) => { 19 | return error 20 | } 21 | ) 22 | // 响应拦截 23 | axios.interceptors.response.use((res) => { 24 | if (res.data.code === 111) { 25 | sessionStorage.setItem('token', '') 26 | // token过期操作 27 | } 28 | return res 29 | }) 30 | 31 | interface ResType { 32 | code: number 33 | data?: T 34 | msg: string 35 | err?: string 36 | } 37 | interface Http { 38 | get(url: string, params?: unknown): Promise> 39 | post(url: string, params?: unknown): Promise> 40 | upload(url: string, params: unknown): Promise> 41 | download(url: string): void 42 | } 43 | 44 | const http: Http = { 45 | get(url, params) { 46 | return new Promise((resolve, reject) => { 47 | NProgress.start() 48 | axios 49 | .get(url, { params }) 50 | .then((res) => { 51 | NProgress.done() 52 | resolve(res.data) 53 | }) 54 | .catch((err) => { 55 | NProgress.done() 56 | reject(err.data) 57 | }) 58 | }) 59 | }, 60 | post(url, params) { 61 | return new Promise((resolve, reject) => { 62 | NProgress.start() 63 | axios 64 | .post(url, JSON.stringify(params)) 65 | .then((res) => { 66 | NProgress.done() 67 | resolve(res.data) 68 | }) 69 | .catch((err) => { 70 | NProgress.done() 71 | reject(err.data) 72 | }) 73 | }) 74 | }, 75 | upload(url, file) { 76 | return new Promise((resolve, reject) => { 77 | NProgress.start() 78 | axios 79 | .post(url, file, { 80 | headers: { 'Content-Type': 'multipart/form-data' }, 81 | }) 82 | .then((res) => { 83 | NProgress.done() 84 | resolve(res.data) 85 | }) 86 | .catch((err) => { 87 | NProgress.done() 88 | reject(err.data) 89 | }) 90 | }) 91 | }, 92 | download(url) { 93 | const iframe = document.createElement('iframe') 94 | iframe.style.display = 'none' 95 | iframe.src = url 96 | iframe.onload = function () { 97 | document.body.removeChild(iframe) 98 | } 99 | document.body.appendChild(iframe) 100 | }, 101 | } 102 | export default http 103 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | browser: true, 5 | node: true, 6 | es2021: true, 7 | }, 8 | parser: 'vue-eslint-parser', 9 | extends: [ 10 | 'eslint:recommended', 11 | 'plugin:vue/vue3-recommended', 12 | 'plugin:@typescript-eslint/recommended', 13 | 'plugin:prettier/recommended', 14 | // eslint-config-prettier 的缩写 15 | 'prettier', 16 | ], 17 | parserOptions: { 18 | ecmaVersion: 12, 19 | parser: '@typescript-eslint/parser', 20 | sourceType: 'module', 21 | ecmaFeatures: { 22 | jsx: true, 23 | }, 24 | }, 25 | // eslint-plugin-vue @typescript-eslint/eslint-plugin eslint-plugin-prettier的缩写 26 | plugins: ['vue', '@typescript-eslint', 'prettier'], 27 | rules: { 28 | '@typescript-eslint/ban-ts-ignore': 'off', 29 | '@typescript-eslint/no-unused-vars': 'off', 30 | '@typescript-eslint/explicit-function-return-type': 'off', 31 | '@typescript-eslint/no-explicit-any': 'off', 32 | '@typescript-eslint/no-var-requires': 'off', 33 | '@typescript-eslint/no-empty-function': 'off', 34 | '@typescript-eslint/no-use-before-define': 'off', 35 | '@typescript-eslint/ban-ts-comment': 'off', 36 | '@typescript-eslint/ban-types': 'off', 37 | '@typescript-eslint/no-non-null-assertion': 'off', 38 | '@typescript-eslint/explicit-module-boundary-types': 'off', 39 | 'no-var': 'error', 40 | 'prettier/prettier': 'error', 41 | // 禁止出现console 42 | 'no-console': 'warn', 43 | // 禁用debugger 44 | 'no-debugger': 'warn', 45 | // 禁止出现重复的 case 标签 46 | 'no-duplicate-case': 'warn', 47 | // 禁止出现空语句块 48 | 'no-empty': 'warn', 49 | // 禁止不必要的括号 50 | 'no-extra-parens': 'off', 51 | // 禁止对 function 声明重新赋值 52 | 'no-func-assign': 'warn', 53 | // 禁止在 return、throw、continue 和 break 语句之后出现不可达代码 54 | 'no-unreachable': 'warn', 55 | // 强制所有控制语句使用一致的括号风格 56 | curly: 'warn', 57 | // 要求 switch 语句中有 default 分支 58 | 'default-case': 'warn', 59 | // 强制尽可能地使用点号 60 | 'dot-notation': 'warn', 61 | // 要求使用 === 和 !== 62 | eqeqeq: 'warn', 63 | // 禁止 if 语句中 return 语句之后有 else 块 64 | 'no-else-return': 'warn', 65 | // 禁止出现空函数 66 | 'no-empty-function': 'warn', 67 | // 禁用不必要的嵌套块 68 | 'no-lone-blocks': 'warn', 69 | // 禁止使用多个空格 70 | 'no-multi-spaces': 'warn', 71 | // 禁止多次声明同一变量 72 | 'no-redeclare': 'warn', 73 | // 禁止在 return 语句中使用赋值语句 74 | 'no-return-assign': 'warn', 75 | // 禁用不必要的 return await 76 | 'no-return-await': 'warn', 77 | // 禁止自我赋值 78 | 'no-self-assign': 'warn', 79 | // 禁止自身比较 80 | 'no-self-compare': 'warn', 81 | // 禁止不必要的 catch 子句 82 | 'no-useless-catch': 'warn', 83 | // 禁止多余的 return 语句 84 | 'no-useless-return': 'warn', 85 | // 禁止变量声明与外层作用域的变量同名 86 | 'no-shadow': 'off', 87 | // 允许delete变量 88 | 'no-delete-var': 'off', 89 | // 强制数组方括号中使用一致的空格 90 | 'array-bracket-spacing': 'warn', 91 | // 强制在代码块中使用一致的大括号风格 92 | 'brace-style': 'warn', 93 | // 强制使用骆驼拼写法命名约定 94 | camelcase: 'warn', 95 | // 强制使用一致的缩进 96 | indent: 'off', 97 | // 强制在 JSX 属性中一致地使用双引号或单引号 98 | // 'jsx-quotes': 'warn', 99 | // 强制可嵌套的块的最大深度4 100 | 'max-depth': 'warn', 101 | // 强制最大行数 300 102 | // "max-lines": ["warn", { "max": 1200 }], 103 | // 强制函数最大代码行数 50 104 | // 'max-lines-per-function': ['warn', { max: 70 }], 105 | // 强制函数块最多允许的的语句数量20 106 | 'max-statements': ['warn', 100], 107 | // 强制回调函数最大嵌套深度 108 | 'max-nested-callbacks': ['warn', 3], 109 | // 强制函数定义中最多允许的参数数量 110 | 'max-params': ['warn', 3], 111 | // 强制每一行中所允许的最大语句数量 112 | 'max-statements-per-line': ['warn', { max: 1 }], 113 | // 要求方法链中每个调用都有一个换行符 114 | 'newline-per-chained-call': ['warn', { ignoreChainWithDepth: 3 }], 115 | // 禁止 if 作为唯一的语句出现在 else 语句中 116 | 'no-lonely-if': 'warn', 117 | // 禁止空格和 tab 的混合缩进 118 | 'no-mixed-spaces-and-tabs': 'warn', 119 | // 禁止出现多行空行 120 | 'no-multiple-empty-lines': 'warn', 121 | // 禁止出现; 122 | semi: ['warn', 'never'], 123 | // 强制在块之前使用一致的空格 124 | 'space-before-blocks': 'warn', 125 | // 强制在 function的左括号之前使用一致的空格 126 | // 'space-before-function-paren': ['warn', 'never'], 127 | // 强制在圆括号内使用一致的空格 128 | 'space-in-parens': 'warn', 129 | // 要求操作符周围有空格 130 | 'space-infix-ops': 'warn', 131 | // 强制在一元操作符前后使用一致的空格 132 | 'space-unary-ops': 'warn', 133 | // 强制在注释中 // 或 /* 使用一致的空格 134 | // "spaced-comment": "warn", 135 | // 强制在 switch 的冒号左右有空格 136 | 'switch-colon-spacing': 'warn', 137 | // 强制箭头函数的箭头前后使用一致的空格 138 | 'arrow-spacing': 'warn', 139 | 'prefer-const': 'warn', 140 | 'prefer-rest-params': 'warn', 141 | 'no-useless-escape': 'warn', 142 | 'no-irregular-whitespace': 'warn', 143 | 'no-prototype-builtins': 'warn', 144 | 'no-fallthrough': 'warn', 145 | 'no-extra-boolean-cast': 'warn', 146 | 'no-case-declarations': 'warn', 147 | 'no-async-promise-executor': 'warn', 148 | }, 149 | globals: { 150 | defineProps: 'readonly', 151 | defineEmits: 'readonly', 152 | defineExpose: 'readonly', 153 | withDefaults: 'readonly', 154 | }, 155 | } 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > 哈喽,大家好 我是`xy`👨🏻‍💻。 从我最初接触`vue3`版本到现在已经有一年的时间。由于 vue3.2 版本的发布,` 820 | ``` 821 | 822 | ### getters 用法介绍 823 | 824 | > Pinia 中的 getter 与 Vuex 中的 getter 、组件中的计算属性具有相同的功能 825 | 826 | `store` => `main.ts` 827 | 828 | ```js 829 | import { defineStore } from 'pinia' 830 | 831 | export const useMainStore = defineStore({ 832 | id: 'main', 833 | state: () => ({ 834 | name: '超级管理员', 835 | }), 836 | // getters 837 | getters: { 838 | nameLength: (state) => state.name.length, 839 | } 840 | }) 841 | ``` 842 | 843 | 组件中使用: 844 | 845 | ```js 846 | 851 | 852 | 864 | ``` 865 | 866 | ![](https://files.mdnice.com/user/16854/ab70ded8-aa34-456a-9044-ac560ff5d2d4.gif) 867 | 868 | ### actions 869 | 870 | > 这里与 `Vuex` 有极大的不同,`Pinia` 仅提供了一种方法来定义如何更改状态的规则,放弃 `mutations` 只依靠 `Actions`,这是一项重大的改变。 871 | 872 | `Pinia` 让 `Actions` 更加的灵活: 873 | 874 | - 可以通过组件或其他 `action` 调用 875 | - 可以从其他 `store` 的 `action` 中调用 876 | - 直接在 `store` 实例上调用 877 | - 支持`同步`或`异步` 878 | - 有任意数量的参数 879 | - 可以包含有关如何更改状态的逻辑(也就是 vuex 的 mutations 的作用) 880 | - 可以 `$patch` 方法直接更改状态属性 881 | 882 | ```ts 883 | import { defineStore } from 'pinia' 884 | 885 | export const useMainStore = defineStore({ 886 | id: 'main', 887 | state: () => ({ 888 | name: '超级管理员', 889 | }), 890 | getters: { 891 | nameLength: (state) => state.name.length, 892 | }, 893 | actions: { 894 | async insertPost(data:string){ 895 | // 可以做异步 896 | // await doAjaxRequest(data); 897 | this.name = data; 898 | } 899 | }, 900 | }) 901 | 902 | ``` 903 | 904 | ## 环境变量配置 905 | 906 | > `vite` 提供了两种模式:具有开发服务器的`开发模式`(development)和`生产模式`(production) 907 | 908 | 项目根目录新建:`.env.development` : 909 | 910 | ```env 911 | NODE_ENV=development 912 | 913 | VITE_APP_WEB_URL= 'YOUR WEB URL' 914 | ``` 915 | 916 | 项目根目录新建:`.env.production` : 917 | 918 | ```env 919 | NODE_ENV=production 920 | 921 | VITE_APP_WEB_URL= 'YOUR WEB URL' 922 | ``` 923 | 924 | 组件中使用: 925 | 926 | ```js 927 | console.log(import.meta.env.VITE_APP_WEB_URL) 928 | ``` 929 | 930 | 配置 `package.json`: 931 | 932 | > 打包区分开发环境和生产环境 933 | 934 | ```json 935 | "build:dev": "vue-tsc --noEmit && vite build --mode development", 936 | "build:pro": "vue-tsc --noEmit && vite build --mode production", 937 | ``` 938 | 939 | ## 使用组件库 Naive UI 940 | 941 | > 组件库选择,这里我们选择 `Naive UI` 至于为什么选择它?我可以直接说`尤大大`推荐的吗? 942 | 943 | - 官方介绍: 944 | - 一个 `Vue 3` 组件库 945 | - 比较完整,`主题可调`,使用 `TypeScript`,不算太慢 946 | - 有点意思 947 | 948 | 介绍还是比较谦虚的,既然`尤大`推荐,肯定有它的优势了!!! 949 | 950 | ### 安装 Naive UI 951 | 952 | ```bash 953 | # 安装 组件库 954 | yarn add naive-ui 955 | # 安装 字体 956 | yarn add vfonts 957 | ``` 958 | 959 | ### 如何使用 960 | 961 | ```js 962 | import { NButton } from "naive-ui" 963 | naive-ui 964 | ``` 965 | 966 | ### 全局配置 Config Provider 967 | 968 | > 全局化配置设置内部组件的`主题`、`语言`和组件卸载于其他位置的 `DOM` 的类名。 969 | 970 | ```html 971 | 972 | 973 | 974 | ``` 975 | 976 | 尤其是主题配置这个功能,我真的很喜欢 ❤️ 977 | 978 | > 组件库选择上不做任何强制,根据自己的项目需要选择合适的组件库即可 979 | 980 | ## Vite 常用基础配置 981 | 982 | ### 基础配置 983 | 984 | `运行` `代理` 和 `打包` 配置 985 | 986 | ```js 987 | server: { 988 | host: '0.0.0.0', 989 | port: 3000, 990 | open: true, 991 | https: false, 992 | proxy: {} 993 | }, 994 | ``` 995 | 996 | 生产环境去除 `console` `debugger` 997 | 998 | ```js 999 | build:{ 1000 | ... 1001 | terserOptions: { 1002 | compress: { 1003 | drop_console: true, 1004 | drop_debugger: true 1005 | } 1006 | } 1007 | } 1008 | ``` 1009 | 1010 | ### 生产环境生成 .gz 文件 1011 | 1012 | > 开启 `gzip` 可以极大的压缩静态资源,对页面加载的速度起到了显著的作用。 1013 | 1014 | 使用 `vite-plugin-compression` 可以 `gzip` 或 `brotli` 的方式来压缩资源,这一步需要服务器端的配合,`vite` 只能帮你打包出 `.gz` 文件。此插件使用简单,你甚至无需配置参数,引入即可。 1015 | 1016 | ```bash 1017 | # 安装 1018 | yarn add --dev vite-plugin-compression 1019 | ``` 1020 | 1021 | plugins 中添加: 1022 | 1023 | ```js 1024 | import viteCompression from 'vite-plugin-compression' 1025 | 1026 | // gzip压缩 生产环境生成 .gz 文件 1027 | viteCompression({ 1028 | verbose: true, 1029 | disable: false, 1030 | threshold: 10240, 1031 | algorithm: 'gzip', 1032 | ext: '.gz', 1033 | }), 1034 | ``` 1035 | 1036 | ### 最终 vite.config.ts 1037 | 1038 | ```js 1039 | import { defineConfig } from 'vite' 1040 | import vue from '@vitejs/plugin-vue' 1041 | import path from 'path' 1042 | //@ts-ignore 1043 | import viteCompression from 'vite-plugin-compression' 1044 | 1045 | // https://vitejs.dev/config/ 1046 | export default defineConfig({ 1047 | base: './', //打包路径 1048 | plugins: [ 1049 | vue(), 1050 | // gzip压缩 生产环境生成 .gz 文件 1051 | viteCompression({ 1052 | verbose: true, 1053 | disable: false, 1054 | threshold: 10240, 1055 | algorithm: 'gzip', 1056 | ext: '.gz', 1057 | }), 1058 | ], 1059 | // 配置别名 1060 | resolve: { 1061 | alias: { 1062 | '@': path.resolve(__dirname, 'src'), 1063 | }, 1064 | }, 1065 | css:{ 1066 | preprocessorOptions:{ 1067 | scss:{ 1068 | additionalData:'@import "@/assets/style/main.scss";' 1069 | } 1070 | } 1071 | }, 1072 | //启动服务配置 1073 | server: { 1074 | host: '0.0.0.0', 1075 | port: 8000, 1076 | open: true, 1077 | https: false, 1078 | proxy: {} 1079 | }, 1080 | // 生产环境打包配置 1081 | //去除 console debugger 1082 | build: { 1083 | terserOptions: { 1084 | compress: { 1085 | drop_console: true, 1086 | drop_debugger: true, 1087 | }, 1088 | }, 1089 | }, 1090 | }) 1091 | 1092 | ``` 1093 | 1094 | ## 常用插件 1095 | 1096 | > 可以查看官方文档:https://vitejs.cn/plugins/ 1097 | 1098 | - `@vitejs/plugin-vue` 提供 `Vue 3` 单文件组件支持 1099 | - `@vitejs/plugin-vue-jsx` 提供 Vue 3 `JSX` 支持(通过 专用的 Babel 转换插件) 1100 | - `@vitejs/plugin-legacy` 为打包后的文件提供传统浏览器`兼容性`支持 1101 | - `unplugin-vue-components` 组件的按需自动导入 1102 | - `vite-plugin-compression` 使用 gzip 或者 brotli 来压缩资源 1103 | - ..... 1104 | 1105 | ## 非常推荐使用的 hooks 库 1106 | 1107 | > 因为`vue3.x`和`react hooks`真的很像,所以就称为 `hooks` 1108 | 1109 | `VueUse`:https://vueuse.org/ 1110 | 1111 | ![](https://files.mdnice.com/user/16854/cbf73b46-d22b-44e7-bca1-c33764e41784.png) 1112 | 1113 | 看到这个库的第一眼,让我立马想到了 react 的 `ahooks` 1114 | 1115 | `VueUse` 是一个基于 `Composition API` 的实用函数集合。通俗的来说,这就是一个`工具函数`包,它可以帮助你快速实现一些常见的功能,免得你自己去写,解决重复的工作内容。以及进行了基于 Composition API 的封装。让你在 vue3 中更加得心应手。 1116 | 1117 | 💡想要入手 vue3 的小伙伴,赶快学习起来吧!!! 1118 | 1119 | 💡最后给大家奉上仓库地址吧:https://github.com/xushanpei/vite_vue3_ts 1120 | 1121 | ## 写在最后 1122 | 1123 | > `公众号`:`前端开发爱好者` 专注分享 `web` 前端相关`技术文章`、`视频教程`资源、热点资讯等,如果喜欢我的分享,给 🐟🐟 点一个`赞` 👍 或者 ➕`关注` 都是对我最大的支持。 1124 | 1125 | 欢迎`长按图片加好友`,我会第一时间和你分享`前端行业趋势`,`面试资源`,`学习途径`等等。 1126 | 1127 | ![](https://files.mdnice.com/user/16854/b382cc29-13f4-4cd7-86ae-c669cb7ae117.jpg) 1128 | 1129 | 关注公众号后,在首页: 1130 | 1131 | - 回复`面试题`,获取最新大厂面试资料。 1132 | - 回复`简历`,获取 3200 套 简历模板。 1133 | - 回复`React实战`,获取 React 最新实战教程。 1134 | - 回复`Vue实战`,获取 Vue 最新实战教程。 1135 | - 回复`ts`,获取 TypeAcript 精讲课程。 1136 | - 回复`vite`,获取 精讲课程。 1137 | - 回复`uniapp`,获取 uniapp 精讲课程。 1138 | - 回复`js书籍`,获取 js 进阶 必看书籍。 1139 | - 回复`Node`,获取 Nodejs+koa2 实战教程。 1140 | - 回复`数据结构算法`,获取 数据结构算法 教程。 1141 | - 回复`架构师`,获取 架构师学习资源教程。 1142 | - 更多教程资源应用尽有,欢迎`关注获取` 1143 | --------------------------------------------------------------------------------