公司我的项目应用react,然而作为vue2的一名coder,周末花了两天的工夫,整顿了一波vue3 + tsx + vite + axios 的开发模板,外面涵盖jest、tailwindcss、pinia、element-plus等一些日常工具包,以及退出了eslint、prettier保障日常开发代码品质工具,基本上可能保障大家可能开箱即用,上面附上模板代码地址,对于代码目录构造能够参考代码仓库的阐明文档,喜爱的敌人能够转评赞给一个,点个珍藏不失落,上面呢我介绍一下根本构建思路;

1、对于我的项目中应用tsx

  要想我的项目中运行tsx,咱们就得思考到tsx语法糖编译的问题,这里就得用到@vitejs/plugin-vue-jsx插件,具体用法参考github文档,装置后,在vite的plugin中间接调用即可;

import { defineConfig } from 'vite'import vue from '@vitejs/plugin-vue'import vueJsx from '@vitejs/plugin-vue-jsx'// https://vitejs.dev/config/export default defineConfig({  plugins: [vue(), vueJsx()]})

2、装置tailwindcss

  对于tailwindcss + vite计划,它的官网有了很敌对的计划,这块大家循序渐进的装置就够了,没有多少复杂度,参考地址,抉择tailwindcss次要是它提供了一些疾速款式,比方padding、margin、background等,如果咱们我的项目是后盾管理系统,tailwindcss会大大降低咱们写css款式的工作,大家能够去学习一波在我的项目中用起来,相熟了当前就感觉他是在是太不便了。

  这里不做用法的介绍,就举荐一个vscode插件Tailwind CSS IntelliSense,装置后,在我的项目中咱们就能够只能提醒,如下所示:

3、对于eslint + prettier 代码对立标准

  对于代码标准,个别小一点公司不太会做这方面的工程化配置,然而eslint等这些代码标准工具,会让咱们团队的代码更标准,格调更对立,团队合作更加不便,我简略说一下配置eslint及prettier的方法

(1)首先装置eslint工具库

pnpm add eslint -D

pnpm eslint --init

(2)装置内部的语法eslint标准及import校验标准

  抉择对应的我的项目内容,这里我的我的项目用到(vue, typescript,browser)这个,当然有这个还不够,咱们须要装置如下两个工具包

pnpm add eslint-plugin-import // 次要对于es与typescript import 门路的一个eslint校验

pnpm add eslint-config-airbnb-base // 这个是airbnb出的一套eslint语法标准的工具库,如果本人公司没有对应的代码标准,这个是很实用的一套

(3)编写vue3相干的标准

  我的项目中咱们用到的是eslint-plugin-vue这个vue代码校验标准工具,外面有很多内容及配置项性能,咱们这里举荐大家在配置代码标准,能够参考官网的阐明文档,链接放在这里;

(4)装置和配置prettier

  这个绝对来讲比较简单一些,咱们间接装置pnpm add eslint-plugin-prettier eslint-config-prettier prettier -D,这里咱们须要留神的是prettier与eslint抵触问题;

  下面是配置时候的根本流程,最终后果我将eslintrc文件及package.json文件放到这里,有须要的敌人,能够间接copy一份去配置,毕竟这个配置很臭很长,深刻学习感觉又没有太大必要(23333~)

{  "name": "vue-tsx-template",  "private": true,  "version": "0.0.0",  "scripts": {    "dev": "vite",    "build": "vue-tsc --noEmit && vite build",    "preview": "vite preview",    "fix": "eslint --fix --ext .js,.jsx,.tsx,.vue src && prettier "  },  "dependencies": {    "vue": "^3.2.25"  },  "devDependencies": {    "@typescript-eslint/eslint-plugin": "^5.23.0",    "@typescript-eslint/parser": "^5.23.0",    "@vitejs/plugin-vue": "^2.3.3",    "@vitejs/plugin-vue-jsx": "^1.3.10",    "autoprefixer": "^10.4.7",    "eslint": "^8.15.0",    "eslint-config-airbnb-base": "^15.0.0",    "eslint-config-prettier": "^8.5.0",    "eslint-plugin-import": "^2.26.0",    "eslint-plugin-prettier": "^4.0.0",    "eslint-plugin-vue": "^8.7.1",    "postcss": "^8.4.13",    "prettier": "^2.6.2",    "sass": "^1.51.0",    "tailwindcss": "^3.0.24",    "typescript": "^4.5.4",    "vite": "^2.9.9",    "vue-eslint-parser": "^9.0.1",    "vue-tsc": "^0.34.7"  }}

上面是.eslintrc.js文件

module.exports = {  env: {    browser: true,    es2021: true,    node: true,    // 解决 defineProps 报错    'vue/setup-compiler-macros': true,  },  extends: [    'eslint:recommended',    'airbnb-base',    'prettier',    'plugin:prettier/recommended',    'plugin:vue/vue3-recommended',    'plugin:@typescript-eslint/recommended',    'plugin:import/recommended',    'plugin:import/typescript',  ],  parser: 'vue-eslint-parser',  parserOptions: {    ecmaVersion: 'latest',    parser: '@typescript-eslint/parser',    sourceType: 'module',  },  plugins: ['vue', '@typescript-eslint'],  rules: {    // 避免prettier与eslint抵触    'prettier/prettier': 'error',    // eslint-plugin-import es module导入eslint规定配置,旨在躲避拼写错误问题    'import/no-unresolved': 0,    'import/extensions': [      'error',      {        js: 'never',        jsx: 'never',        ts: 'never',        tsx: 'never',        json: 'always',      },    ],    // 应用导出的名称作为默认属性(次要用作导出模块外部有 default, 和间接导出两种并存状况下,会呈现default.proptry 这种问题从在的状况)    'import/no-named-as-default-member': 0,    'import/order': ['error', { 'newlines-between': 'always' }],    // 导入确保是否在首位    'import/first': 0,    // 如果文件只有一个导出,是否开启强制默认导出    'import/prefer-default-export': 0,    'import/no-extraneous-dependencies': [      'error',      {        devDependencies: [],        optionalDependencies: false,      },    ],    /**     * 对于typescript语法校验     * 参考文档: https://www.npmjs.com/package/@typescript-eslint/eslint-plugin     */    '@typescript-eslint/no-extra-semi': 0,    // 是否禁止应用any类型    '@typescript-eslint/no-explicit-any': 0,    // 是否对于null状况做非空断言    '@typescript-eslint/no-non-null-assertion': 0,    // 是否对返回值类型进行定义校验    '@typescript-eslint/explicit-function-return-type': 0,    '@typescript-eslint/member-delimiter-style': ['error', { multiline: { delimiter: 'none' } }],    // 联合eslint 'no-use-before-define': 'off',不然会有报错,须要敞开eslint这个校验,次要是减少了对于type\interface\enum    'no-use-before-define': 'off',    '@typescript-eslint/no-use-before-define': ['error'],    '@typescript-eslint/explicit-module-boundary-types': 'off',    '@typescript-eslint/no-unused-vars': [      'error',      {        ignoreRestSiblings: true,        varsIgnorePattern: '^_',        argsIgnorePattern: '^_',      },    ],    '@typescript-eslint/explicit-member-accessibility': ['error', { overrides: { constructors: 'no-public' } }],    '@typescript-eslint/consistent-type-imports': 'error',    '@typescript-eslint/indent': 0,    '@typescript-eslint/naming-convention': [      'error',      {        selector: 'interface',        format: ['PascalCase'],      },    ],    // 不容许应用 var    'no-var': 'error',    // 如果没有批改值,有些用const定义    'prefer-const': [      'error',      {        destructuring: 'any',        ignoreReadBeforeAssign: false,      },    ],    // 对于vue3 的一些语法糖校验    // 超过 4 个属性换行展现    'vue/max-attributes-per-line': [      'error',      {        singleline: 4,      },    ],    // setup 语法糖校验    'vue/script-setup-uses-vars': 'error',    // 对于箭头函数    'vue/arrow-spacing': 'error',    'vue/html-indent': 'off',  },}

4、退出单元测试

  单元测试,依据本人我的项目体量及重要性而去思考是否要减少,当然单测能够反推一些组件 or 办法的设计是否正当,同样如果是一个稳固的性能在加上单元测试,这就是一个很nice的体验;
咱们单元测试是基于jest来去做的,具体装置单测的方法如下,跟着我的步骤一步步来;

  • 装置jest单测相干的依赖组件库

pnpm add @testing-library/vue @testing-library/user-event @testing-library/jest-dom @types/jest jest @vue/test-utils -D

  • 装置实现后,发现还须要装置前置依赖 @testing-library/dom @vue/compiler-sfc咱们持续补充
  • 装置babel相干工具,用ts写的单元测试须要本义,具体装置工具如下pnpm add @babel/core babel-jest @vue/babel-preset-app -D,最初咱们配置babel.config.js

    module.exports = {presets: ['@vue/app'],}
  • 配置jest.config.js

    module.exports = {roots: ['<rootDir>/test'],testMatch: [  // 这里咱们反对src目录外面减少一些单层,事实上我并不喜爱这样做  '<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',  '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}',  // 这里我习惯将单层文件对立放在test独自目录下,不在我的项目中应用,升高单测文件与业务组件模块混合在一起  '<rootDir>/test/**/*.{spec,test}.{js,jsx,ts,tsx}',],testEnvironment: 'jsdom',transform: {  // 此处咱们单测没有实用vue-jest形式,我的项目中咱们江永tsx形式来开发,所以咱们如果须要退出其它的内容  // '^.+\\.(vue)$': '<rootDir>/node_modules/vue-jest',  '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': '<rootDir>/node_modules/babel-jest',},transformIgnorePatterns: [  '<rootDir>/node_modules/',  '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',  '^.+\\.module\\.(css|sass|scss|less)$',],moduleFileExtensions: ['ts', 'tsx', 'vue', 'js', 'jsx', 'json', 'node'],resetMocks: true,}

      具体写单元测试的办法,能够参考我的项目模板中的组件单元测试写法,这里不做过多的阐明;

    5、封装axios申请库

      这里呢其实思路有很多种,如果有本人的习惯的封装形式,就依照本人的思路,上面附上我的封装代码,简短的说一下我的封装思路:

  • 1、根底的申请拦挡、相应拦挡封装,这个是对于一些申请参数格式化解决等,或者返回值状况解决
  • 2、申请异样、谬误、接口调用胜利返回后果谬误这些谬误的集中处理,代码中申请就不再做trycatch这些操作
  • 3、申请函数对立封装(代码中的 get、post、axiosHttp
  • 4、泛型形式定义申请返回参数,定义好类型,让咱们能够在不同中央应用有良好的提醒

    import type { AxiosRequestConfig, AxiosResponse } from 'axios'import axios from 'axios'import { ElNotification } from 'element-plus'import errorHandle from './errorHandle'// 定义数据返回构造体(此处我简略定义一个比拟常见的后端数据返回构造体,理论应用咱们须要依照本人所在的我的项目开发)interface ResponseData<T = null> {code: string | numberdata: Tsuccess: booleanmessage?: string[key: string]: any}const axiosInstance = axios.create()// 设定响应超时工夫axiosInstance.defaults.timeout = 30000// 能够后续依据本人http申请头非凡邀请设定申请头axiosInstance.interceptors.request.use((req: AxiosRequestConfig<any>) => {  // 非凡解决,后续如果我的项目中有全局通传参数,能够在这儿做一些解决  return req},error => Promise.reject(error),)// 响应拦挡axiosInstance.interceptors.response.use((res: AxiosResponse<any, any>) => {  // 数组解决  return res},error => Promise.reject(error),)// 通用的申请办法体const axiosHttp = async <T extends Record<string, any> | null>(config: AxiosRequestConfig,desc: string,): Promise<T> => {try {  const { data } = await axiosInstance.request<ResponseData<T>>(config)  if (data.success) {    return data.data  }  // 如果申请失败对立做提醒(此处我没有装置组件库,我简略写个mock例子)  ElNotification({    title: desc,    message: `${data.message || '申请失败,请查看'}`,  })} catch (e: any) {  // 对立的错误处理  if (e.response && e.response.status) {    errorHandle(e.response.status, desc)  } else {    ElNotification({      title: desc,      message: '接口异样,请查看',    })  }}return null as T}// get申请办法封装export const get = async <T = Record<string, any> | null>(url: string, params: Record<string, any>, desc: string) => {const config: AxiosRequestConfig = {  method: 'get',  url,  params,}const data = await axiosHttp<T>(config, desc)return data}// Post申请办法export const post = async <T = Record<string, any> | null>(url: string, data: Record<string, any>, desc: string) => {const config: AxiosRequestConfig = {  method: 'post',  url,  data,}const info = await axiosHttp<T>(config, desc)return info}

    申请谬误(状态码谬误相干提醒)

    import { ElNotification } from 'element-plus'function notificat(message: string, title: string) {ElNotification({  title,  message,})}/** * @description 获取接口定义 * @param status {number} 谬误状态码 * @param desc {string} 接口形容信息 */export default function errorHandle(status: number, desc: string) {switch (status) {  case 401:    notificat('用户登录失败', desc)    break  case 404:    notificat('申请不存在', desc)    break  case 500:    notificat('服务器谬误,请查看服务器', desc)    break  default:    notificat(`其余谬误${status}`, desc)    break}}

    6、对于vue-router 及 pinia

      这两个绝对来讲简略一些,会应用vuex状态治理,上手pinia也是很轻松的事儿,只是更简单化了、更不便了,能够参考模板我的项目外面的用法example,这里附上routerpinia配置办法,路由守卫,大家能够依据我的项目的要求再增加

    import type { RouteRecordRaw } from 'vue-router'import { createRouter, createWebHistory } from 'vue-router'// 配置路由const routes: Array<RouteRecordRaw> = [{  path: '/',  redirect: '/home',},{  name: 'home',  path: '/home',  component: () => import('page/Home'),},]const router = createRouter({routes,history: createWebHistory(),})export default router

    针对与pinia,参考如下:

    import { createPinia } from 'pinia'export default createPinia()

    在入口文件将router和store注入进去

    import { createApp } from 'vue'import App from './App'import store from './store/index'import './style/index.css'import './style/index.scss'import 'element-plus/dist/index.css'import router from './router'// 注入全局的storeconst app = createApp(App).use(store).use(router)app.mount('#app')

  说这些比拟干燥,倡议大家去github参考我的项目阐明文档,下载我的项目,本人过一遍,喜爱的敌人珍藏点赞一下,如果喜爱我构建好的我的项目给个star不失落,谢谢各位看官的反对。