本次构建的我的项目技术栈: Vite
+Vue3
+Volar
+Pinia
+Vue-Router
+TS
+JSX
+Scss
+Script setup
- Vite: 下一代前端开发与构建工具,极速的热更新开发体验★★★★★
- Vue3.2: 超多的黑魔法
- Volar: Vue3必备开发神器
- Pinia: 新一代的轻量状态管理器
- Vue-Router4: Vue3的官网路由
<Script setup>
语法糖,更简洁的语法、更好的开发体验Vue3 + TS + JSX
,一个重度React + TS + JSX
用户的Vue
我的项目解决方案应用vite创立vue3我的项目
# npm 6.xnpm create vite@latest my-vue-app --template vue-ts# npm 7+, extra double-dash is needed:npm create vite@latest my-vue-app -- --template vue-ts# yarnyarn create vite my-vue-app --template vue-ts# pnpmpnpm create vite my-vue-app -- --template vue-ts
配置VSCode开发环境
- 禁用
vetur
插件
// 通过门路 `Code -> Preferences -> Settings` 中关上vscode配置文件"vetur.validation.template": false
- 装置
Volar
相干插件Vue Language Features
和TypeScript Vue Plugin
- 装置
eslint
插件,并对VSCode进行配置
"editor.formatOnSave": true, "eslint.autoFixOnSave": true, "eslint.validate": [ "javascript", "javascriptreact", { "language": "html", "autoFix": true }, { "language": "vue", "autoFix": true }, { "language": "typescript", "autoFix": true }, { "language": "typescriptreact", "autoFix": true } ],
- 装置
prettier
插件,配置通用的prettier
规定
/* prettier的配置 */ "prettier.printWidth": 300, // 超过最大值换行 "prettier.tabWidth": 2, // 缩进字节数 "prettier.useTabs": false, // 缩进不应用tab,应用空格 "prettier.semi": true, // 句尾增加分号 "prettier.trailingComma": "none", // #在对象或数组最初一个元素前面不加逗号 "prettier.singleQuote": true, // 应用单引号代替双引号
工具配置
vscode里的ESlint插件和Prettier插件会优先以我的项目的配置文件(如.prettierrc.json)为准,所以咱们为我的项目创立适宜我的项目的自定义规定:
- 我的项目装置
prettier
npm install --save-dev --save-exact prettier
- 在我的项目根门路下创立我的项目的格式化配置文件
.prettierrc.json
,配置简略内容,更具体的配置规定阐明
// .prettierrc.json{ "singleQuote": true, "semi": true, "printWidth": 200}
- 我的项目装置
ESlint
npm install --save-dev eslint eslint-plugin-vue eslint-config-prettier
- 在我的项目根目录创立ESlint配置文件
.eslintrc.js
,应用vue3举荐的规定
// .eslintrc.jsmodule.exports = { env: { node: true, 'vue/setup-compiler-macros': true // 新增的配置 }, extends: ['eslint:recommended', 'plugin:vue/vue3-recommended', 'prettier'], rules: { 'vue/require-default-prop': 'off', // 敞开默认值 "@typescript-eslint/no-explicit-any": "off", // 敞开禁用any }, parser: 'vue-eslint-parser', parserOptions: { parser: '@typescript-eslint/parser', ecmaVersion: 2020, sourceType: 'module', },};
- 在
package.json
增加脚本命令
"scripts": { // ... "lint": "eslint --ext .js,.vue --ignore-path .gitignore --fix src", "format": "prettier . --write", },
- 我的项目装置
@typescript-eslint/parser
npm install @typescript-eslint/parser
- 如果心愿eslint谬误间接在浏览器上显示,能够装置插件
vite-plugin-eslint
npm i --save-dev vite-plugin-eslint
- 在
vite.config.ts
中配置vite-plugin-eslint
// vite.congfig.tsimport { defineConfig } from 'vite';import vue from '@vitejs/plugin-vue';import eslintPlugin from 'vite-plugin-eslint';export default defineConfig({ plugins: [vue(), eslintPlugin()],});
其它我的项目工具的配置
- 装置
vue-router
npm install vue-router@4
- 创立
router/index.ts
门路配置文件
import { createRouter,createWebHashHistory} from "vue-router";import Home from '../views/Home/index.vue'import Login from '../views/Login/index.vue'const routes = [ { path: "/", redirect: "/home" }, { path: "/home", name: "home", component: Home }, { path: "/login", name: "login", component: Login }]export const router = createRouter({ history: createWebHashHistory(), routes: routes})
- 在
main.ts
中启用router
import { createApp } from 'vue'import App from './App.vue'import {router} from './router'createApp(App).use(router).mount('#app')
- 在
App.vue
中应用
<script setup lang="ts"></script><template> <router-view /></template><style>#app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px;}</style>
- 装置
sass
npm install sass -Dnpm install node-sass -Dnpm install sass-loader -D
- 装置
@types/node
npm install @types/node -D
- 配置门路别名
在vite.config.ts
增加配置
// vite.congfig.tsimport { defineConfig } from 'vite';import vue from '@vitejs/plugin-vue';import eslintPlugin from 'vite-plugin-eslint';import {join} from "path";export default defineConfig({ plugins: [vue(), eslintPlugin()], resolve: { alias: { "@": join(__dirname, "src"), "~": join(__dirname, "node_modules") } }});
在 tsconfig.json
在配置
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["esnext", "dom"], "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }]}
- 装置
pinia
轻量状态管理器
npm install pinia
- 创立
stores/user.ts
全局状态store
import { defineStore } from 'pinia'import { ref } from 'vue'export const useUserStore = defineStore('counter', () => { const count = ref(0) function increment() { count.value++ } return { count, increment }})
- vue启用
pinia
,批改main.ts
代码
import { createApp } from 'vue'import App from './App.vue'import {router} from './router'import { createPinia } from 'pinia'createApp(App).use(router).use(createPinia()).mount('#app')
- 装置
@vitejs/plugin-vue-jsx
npm install @vitejs/plugin-vue-jsx -D
- 在
vite.config.ts
中启用jsx
// vite.congfig.tsimport { defineConfig } from 'vite';import vue from '@vitejs/plugin-vue';import eslintPlugin from 'vite-plugin-eslint';import {join} from "path";import vueJsx from "@vitejs/plugin-vue-jsx";export default defineConfig({ plugins: [vue(), eslintPlugin(), vueJsx()], resolve: { alias: { "@": join(__dirname, "src"), "~": join(__dirname, "node_modules") } }});
- 批改
tsconfig.json
规定,包含src
下所有的.tsx
文件
{ "compilerOptions": { "target": "esnext", "useDefineForClassFields": true, "module": "esnext", "moduleResolution": "node", "strict": true, "jsx": "preserve", "sourceMap": true, "resolveJsonModule": true, "isolatedModules": true, "esModuleInterop": true, "lib": ["esnext", "dom"], "baseUrl": ".", "paths": { "@/*": ["src/*"] } }, "include": ["src/**/*.ts", "src/*.tsx", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], "references": [{ "path": "./tsconfig.node.json" }]}
- 革新
App.vue
为App.tsx
,并在main.ts
引入
// App.tsximport { defineComponent } from 'vue';import {RouterLink, RouterView} from 'vue-router';import './style/app.scss'export default defineComponent({ name: 'App', setup() { return () => ( <> <div id="nav"> <RouterLink to="/home">Home</RouterLink> | <RouterLink to="/login">Login</RouterLink> </div> <RouterView/> </> ); }});
// main.tsimport { createApp } from 'vue'import App from './App'import {router} from './router'import { createPinia } from 'pinia'createApp(App).use(router).use(createPinia()).mount('#app')
- 我的项目装置
axios
npm install --save axios vue-axios
- 封装
axios
结构一个通用的request
办法
// src/request/base.tslet BASE_URL = ''const TIME_OUT = 30000if (process.env.NODE_ENV === 'dev') { BASE_URL = '开发环境IP'} else if (process.env.NODE_ENV === 'prod') { BASE_URL = '生产环境IP'} else { BASE_URL = '其它环境IP'}export { BASE_URL, TIME_OUT }
// src/request/type.tsimport type { AxiosRequestConfig, AxiosResponse } from 'axios'export interface LJRequestInterceptors<T = AxiosResponse> { requestInterceptor?: (config: AxiosRequestConfig) => AxiosRequestConfig requestInterceptorCatch?: (error: any) => any responseInterceptor?: (res: T) => T responseInterceptorCatch?: (error: any) => any}export interface LJRequestConfig<T = AxiosResponse> extends AxiosRequestConfig { showLoading?: boolean interceptors?: LJRequestInterceptors<T>}
// src/request/request.tsimport axios from 'axios'import type { AxiosInstance } from 'axios'import { LJRequestInterceptors, LJRequestConfig } from './type' class LJRequest { instance: AxiosInstance interceptors?: LJRequestInterceptors constructor(config: LJRequestConfig) { //创立axios实例 this.instance = axios.create(config) //保留根本信息 this.interceptors = config.interceptors //应用拦截器 //从config钟取出的拦截器是对应的实例的拦截器 this.instance.interceptors.request.use(this.interceptors?.requestInterceptor, this.interceptors?.requestInterceptorCatch) this.instance.interceptors.response.use(this.interceptors?.responseInterceptor, this.interceptors?.requestInterceptorCatch) //所有的实例都有的拦截器 this.instance.interceptors.request.use((config) => { console.log('所有的实例都有的拦截器: 申请拦挡胜利') console.log(config) return config }, (err) => { console.log('所有的实例都有的拦截器: 申请拦挡失败') return err }) this.instance.interceptors.response.use( (res) => { console.log('所有的实例都有的拦截器: 响应拦挡胜利') return res.data }, (err) => { console.log('所有的实例都有的拦截器: 响应拦挡失败') //例子:判断不同httpErrorCode显示不同错误信息 if (err.response.status === 404) { console.log('404谬误~') } return err } ) } request<T>(config: LJRequestConfig<T>): Promise<T> { return new Promise((resolve, reject) => { //单个申请对申请config的解决 if (config.interceptors?.requestInterceptor) { config = config.interceptors.requestInterceptor(config) } this.instance .request<any, T>(config) .then((res) => { //单个申请对数据的解决 if (config.interceptors?.responseInterceptor) { res = config.interceptors.responseInterceptor(res) } console.log(res) //将后果返回进来 resolve(res) }) .catch((err) => { reject(err) }) }) } get<T>(config: LJRequestConfig<T>): Promise<T> { return this.request<T>({ ...config, method: 'GET' }) } post<T>(config: LJRequestConfig<T>): Promise<T> { return this.request<T>({ ...config, method: 'POST' }) } delete<T>(config: LJRequestConfig<T>): Promise<T> { return this.request<T>({ ...config, method: 'DELETE' }) } patch<T>(config: LJRequestConfig<T>): Promise<T> { return this.request<T>({ ...config, method: 'PATCH' }) }}export default LJRequest
// src/request/index.tsimport LJRequest from './request'import { BASE_URL, TIME_OUT } from './base'const ljRequest = new LJRequest({ baseURL: BASE_URL, timeout: TIME_OUT, interceptors: { requestInterceptor: (config) => { let _config = { ...config, } _config.headers = { ...config.headers, token: sessionStorage.getItem("token") as any, app: 'visionary' } console.log('申请胜利拦挡') return _config }, requestInterceptorCatch: (err) => { console.log('申请失败拦挡') return err }, responseInterceptor: (config) => { console.log('响应胜利拦挡') return config }, responseInterceptorCatch: (err) => { console.log('响应失败拦挡') return err } }})export default ljRequest
// src/views/index.vue<script setup lang="ts">import ljRequest from "@/request/index"ljRequest.get({ url: '接口地址', showLoading: true,}) .then((res) => { console.log(res) }).catch((err) => { console.log(err) })</script>
配置脚本启动参数命令
--mode 环境变量值
"dev": "vite --host --mode development",
我的项目打包的相干问题
打包遇到对node_modules中的类型进行了查看,能够批改npm
build
命令, 减少--skipLibCheck
参数,如下:"build": "vue-tsc --noEmit --skipLibCheck && vite build",
- 执行打包命令时,
vue-tsc
语法查看报错时,请查看IDE
的Volar
插件版本和vue-tsc
版本是否兼容,如遇到新语法不兼容时可降级vue-tsc
或Volar
的版本,我这里呈现的是vue-tsc
无奈辨认自定义指令,然而Volar
是反对的(开发过程不报错),所以我将vue-tsc
降级到了0.33.9
版本。 - 有时候
vue-tsc
报打包谬误,查看node
版本是否为14.0.0+
,应用最新的构建工具倡议把node
版本升级到比拟新的版本。