美文网首页
企业级前端工程化配置指南:vite4 + vue3 + ts +

企业级前端工程化配置指南:vite4 + vue3 + ts +

作者: 习惯水文的前端苏 | 来源:发表于2023-06-20 17:39 被阅读0次

    大家好,我是苏先生,一名热爱钻研、乐于分享的前端工程师,跟大家分享一句我很喜欢的话:人活着,其实就是一种心态,你若觉得快乐,幸福便无处不在

    你可以学到什么?

    • 如何使用 vite 搭建项目
    • 如何集成与使用 web-localstorage-plus
    • 如何集成与使用 vue-router4
    • 如何集成与使用 pinia
    • 如何集成与使用 element-plus
    • 如何封装axios
    • 如何借力 eslint 和 prettier 保证代码质量
    • 如何借力 commitlint 规范git提交信息

    源码地址

    传送门

    1.创建项目

    按提示选择:

    1.运行vite

    yarn create vite
    

    2.输入自定义的项目名称

    name: › your-project-name
    

    3.选择你想要的技术框架

    ? Select a framework: › - Use arrow-keys. Return to submit.
    ❯   Vanilla
        Vue
        React
        Preact
        Lit
        Svelte
        Others
    

    4.选择ts模板

    ? Select a variant: › - Use arrow-keys. Return to submit.
    ❯   TypeScript
        JavaScript
        Customize with create-vue ↗
        Nuxt ↗
    

    5.按提示安装并运行项目

    Done. Now run:
    
      cd vite-project
      yarn
      yarn dev
    

    一键初始化

    除了上述问答形式创建外,vite官方也提供了快捷语法:通过命令行参数创建

    # npm 6.x
    npm create vite@latest my-vue-app --template vue
    
    # npm 7+, extra double-dash is needed:
    npm create vite@latest my-vue-app -- --template vue
    
    # yarn
    yarn create vite my-vue-app --template vue
    
    # pnpm
    pnpm create vite my-vue-app --template vue
    

    2.优化项目结构

    修剪vite默认生成的项目结构

    1.保留public文件夹,删除vite.svg文件,同时删除index.html中对该文件的引入

    image.png

    2.删除HelloWorld.vue文件,同时从App.vue中删除引入

    image.png

    3.删除App.vue中的默认代码,只保留默认的三个根元素

    我个人习惯将template放到最前边

    <template>
    </template>
    
    <script setup lang="ts">
    </script>
    
    <style scoped>
    </style>
    

    4.清空assets文件夹

    定制化目录

    1.创建store文件夹

    放置关于pinia的数据状态

    2.创建directive文件夹

    放置我们的自定义指令,如:v-auth

    3.创建utils文件夹

    项目中的公共方法或常量

    4.创建styles文件夹

    管理公共css样式文件,如:reset.css

    5.创建http文件夹

    处理axios的封装和调用

    6.创建router文件夹

    管理vue-router的路由模块

    7.创建pages文件夹

    管理业务代码

    3.配置vite.config.ts

    配置别名

    项目中,不同模块之间往往需要互相引入,使用别名能够帮助我们省去一级一级查找的繁琐

    ...
    import { resolve } from 'node:path'
    
    export default defineConfig({
      plugins: [vue()],
      resolve:{
        alias:{
          '@':resolve(__dirname,'src')
        }
      }
    })
    

    此时,node:path__dirname会报错,我们还需要安装下对应的ts类型包

    yarn add @types/node --D
    

    设置代理

    我们本地开发完跟后端联调阶段,经常会遇到跨域的问题,需要我们暂时的在前端进行下处理

    export default defineConfig({
      ...
      server: {
        proxy: {
          "/api": {
            target: "http url",
            changeOrigin: true,
            rewrite: (path: string) => path.replace(/^\/api/, ""),
          },
        },
      },
    });
    

    其中"/api"是我们要代理的接口标识,target是我们实际要访问的接口地址

    设置自动导入

    每次都手动导入依赖项是一件很麻烦的事情,幸运的是,我们可以借助第三方库来帮我们实现,它内置了常见的库,比如vue

    1.安装

    yarn add unplugin-auto-import -D
    

    2.在vite.config.ts中导入并作为plugin使用

    ...
    import AutoImport from 'unplugin-auto-import/vite'
    
    export default defineConfig({
      plugins: [...,AutoImport()],
      ...
    });
    

    4.集成web-storage-plus

    对于需要使用到持久缓存的地方,localstorage是优选的方案,不过原生接口比较难用,而该npm包对其进行了二次封装,使其支持了命名空间、过期时间、监听变化、批量操作等特性,且其为我们提供了发布订阅模式来弥补vue3中对bus的缺失,文档看这里:传送门

    1.安装

    yarn add web-localstorage-plus
    

    2.在main.ts中引入并初始化根存储

    ...
    import createStorage from 'web-localstorage-plus'
    createStorage({
        rootName:'spp-storage'
    })
    ...
    

    3.在.vue文件中引入并使用

    <script lang="ts" setup>
    import { useStorage } from 'web-localstorage-plus'
    
    const storage = useStorage()
    storage.setItem('user',{
        name:'spp',
        age:28
    })
    </script>
    

    5.集成pinia

    对于非持久化数据,我们选择使用pinia来进行管理,它帮我们托管了全局状态并且提供了响应式能力,文档看这里:传送门

    1.安装pinia

    yarn add pinia
    

    2.在store文件夹下新建index.ts文件作为pinia的根仓库文件

    import { createPinia } from "pinia"; 
    const pinia = createPinia()
    export default pinia
    

    3.在main.ts中导入并将 pinia 作为 plugin 注册给 vue

    import { createApp } from 'vue'
    ...
    import pinia from '@/store'
    ...
    const app = createApp(App)
    app.use(pinia)
    ...
    

    4.在store文件夹下新建xxx.ts文件作为子存储模块

    import { defineStore } from 'pinia'
    
    export default defineStore('spp', {
      state() {
          return {
            spp:''
          }
      },
      actions:{
        updateSpp(spp:string){
            this.spp = spp
        }
      }
    })
    

    5.在.vue文件中使用或修改pinia的状态

    <script lang="ts" setup>
    ...
    import useLoginStore from '@/store/login.ts'
    // 获取状态
    const store = useLoginStore()
    // 修改状态
    store.updateSpp('spp')
    ...
    </script>
    

    6.集成vue-router4

    作为spa项目,路由是我们进行页面切换的必备工具,文档看这里:传送门

    1.使用yarn安装

    yarn add vue-router@4
    

    2.在router文件夹下新建index.ts文件作为根路由

    import { createRouter, createWebHistory, RouteRecordRaw } from "vue-router";
    
    const routes: Array<RouteRecordRaw> = [
      {
        path: "/login",
        name: "Login",
        component: () => import("@/pages/login/index.vue")
      },
    ];
    
    const router = createRouter({
      history: createWebHistory(),
      routes,
    });
    
    export default router;
    

    3.在main.ts中导入并作为plugin注册给vue

    import { createApp } from 'vue'
    import router from '@/router';
    ...
    const app = createApp(App)
    app.use(router)
    ...
    

    4.将根App.vue作为路由出口

    <template>
      <RouterView/>
    </template>
    

    7.集成less

    1.安装

    yarn add less -D
    

    2.使用

    <style lang="less" scoped>
    .root-app {
      .spp {
        // 自定义样式
      }
    }
    </style>
    

    8.集成element-plus

    element-plus是vue侧比较流行的pc端ui框架之一,文档看这里:传送门

    1.安装

    yarn add element-plus
    

    2.按需自动导入

    • 安装依赖包
    yarn add unplugin-vue-components unplugin-auto-import -D
    
    • 修改vite.config.ts
    import { defineConfig } from "vite";
    ...
    import AutoImport from "unplugin-auto-import/vite";
    import Components from "unplugin-vue-components/vite";
    import { ElementPlusResolver } from "unplugin-vue-components/resolvers";
    
    export default defineConfig({
      plugins: [
        ...
        AutoImport({
          resolvers: [ElementPlusResolver()],
        }),
        Components({
          resolvers: [ElementPlusResolver()],
        }),
      ],
      ...
    });
    
    

    3.在.vue文件夹下直接使用即可

    9.集成axios(仅提供封装思路,可选)

    axios是目前最流行的前端发起ajax请求的库,其基于promise实现,同时支持在浏览器和nodejs中使用,文档看这里:传送门

    1.安装

    yarn add axios
    

    2.在http文件夹下新建index.ts文件

    该文件对我们业务中的请求进行基类封装

    import request from "./request";
    import getPrefix from "./urlPrefix";
    import { TgroupType } from '@/utils/types'
    import { warn } from '@/utils/function'
    
    class Http{
      protected prefix:string=getPrefix(undefined);
      protected config:any={}
      constructor(group?:TgroupType){
        this.prefix = getPrefix(group)
      }
      private combineUrl(url:string){
        return this.prefix + url
      }
      setExtraConfig(config:any){
        this.config = config
      }
      get<T>(url: string, arg?: T,message?:string){
        return new Promise((resolve, reject) => {
          request
            .get(this.combineUrl(url), {
              params: arg,
              ...this.config
            })
            .then((res:any)=>{
              // 根据与后端的约定format数据,并做resolve或reject
              ...
            })
            .catch(reject)
            .finally(()=>{
              this.config={}
            })
        });
      }
      post<T>(url: string, message?: string | T, arg?: T) {
        const isFull = arguments.length === 3
        if (!isFull) {
          arg = message as T;
        }
        const errMessage = '你的自定义错误'
        return new Promise((resolve, reject) => {
          request
            .post(this.combineUrl(url), arg,{
              ...this.config,
            })
            .then((res: any) => {
              // 根据与后端的约定format数据,并做resolve或reject
              ...
            })
            .catch(()=>{
              warn(errMessage)
              reject(errMessage);
            })
            .finally(()=>{
              this.config={}
            })
        });
      }
    }
    
    export const http = new Http()
    export const httpRequest = Http
    export const usePrefix = getPrefix
    

    3.在http文件夹下新建request.ts文件

    该文件用于配置axios,并通过拦截器对接口状态进行检测和错误的统一处理

    import axios from "axios";
    
    axios.defaults.timeout = 10000000;
    
    axios.defaults.withCredentials = true;
    
    axios.interceptors.request.use(
      (config) => {
        config.headers = Object.assign(config.headers,{
          // 配置header
        })
        return config;
      },
      (error) => {
        // 处理错误
        return Promise.reject(error);
      }
    );
    
    axios.interceptors.response.use(
      (response) => {
        // 统一拦截验证
        return response;
      },
      (error) => {
        // 处理错误
        return Promise.reject(error);
      }
    );
    
    export default axios;
    

    4.在http文件夹下新建urlPrefix.ts文件

    该文件用于统一管理不同域名对应的不同环境下的url

    import { IurlConfig,TgroupType} from '@/utils/types'
    const mode = import.meta.env.MODE;
    const urlConfig:IurlConfig = {
      // 前缀-{dev:'',pro:''}
    }
    
    const getPrefix = (key:TgroupType)=>{
      if(key === undefined){
        key = ''
        urlConfig[key][mode]
      }
      return urlConfig[key][mode]
    }
    
    export default getPrefix;
    

    5.在业务中引入并使用

    import { http } from "@/http";
    http
        .post<传递与当前接口参数匹配的类型>(url, "添加成功", params)
        .then(() => {
          // 请求成功的业务处理
        });
    

    10.常用工具推荐

    • 时间处理:moment

    文档地址

    • 万能工具库:lodash-es

    文档地址

    11.代码质量与提交规范

    eslint

    因为eslint无法识别.vue文件,因此我们还需要一个定制化插件:eslint-plugin-vue,文档看这里:传送门

    1.安装依赖

    yarn add eslint eslint-plugin-vue -D
    

    2.创建.eslintignore忽略文件

    node_modules
    dist
    yarn.lock
    index.html
    

    3.添加ts支持

    eslint-plugin-vue只针对.vue文件或者.js文件中的vue写法,我们还需要对ts进行兼容

    文档传送门:@typescript-eslint/parser@typescript-eslint/eslint-plugin

    yarn add @typescript-eslint/parser @typescript-eslint/eslint-plugin -D
    

    4.在根目录下创建.eslintrc.cjs配置文件

    module.exports = {
      parser: 'vue-eslint-parser',
      parserOptions: {
          parser: '@typescript-eslint/parser',
          ecmaVersion: 2020,
          sourceType: 'module',
          ecmaFeatures: {
              jsx: true
          }
      },
    
      extends: [
          'plugin:vue/vue3-recommended',
          'plugin:@typescript-eslint/recommended',
      ],
    
      rules: {
          "no-console": "error",
      }
    };
    

    5.按环境区分

    实际项目中,我们一般会根据不同的开发环境来区分规则,比如console应在开发阶段可用,生产时禁用

    1-安装依赖

    文档看这里:cross-env@rollup/plugin-eslint

    yarn add cross-env @rollup/plugin-eslint -D
    

    2-修改命令行

    在打包阶段配置环境变量,我这里以production为例子

    "scripts": {
        ...
        "build": "cross-env NODE_ENV=production && vue-tsc --noEmit && vite build"
      },
    

    3-将rollup插件加入vite的plugin

    ...
    import eslint from '@rollup/plugin-eslint';
    
    export default defineConfig({
      plugins: [
        ...
        eslint({
          include:['src/**']
        })
      ],
      ...
    });
    
    

    4-修改.eslintrc.cjs

    cross-env会将定义的环境变量暴露在env上,我们获取并做三元判断即可

    const mode = process.env.NODE_ENV
    module.exports = {
      ...
      rules: {
          "no-console": mode === 'production' ? "error" : "off",
          ...
      }
    };
    

    prettier

    相关文档看这里:prettiereslint-config-prettiereslint-plugin-prettier

    1.安装依赖

    yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
    

    2.创建配置文件:.prettierrc.js

    以我司的某个项目为例

    module.exports = {
      // 一行最多 150 个字符
      printWidth: 150,
      // 使用 4 个空格缩进
      tabWidth: 4,
      // 不使用 tab 缩进,而使用空格
      useTabs: false,
      // 行尾需要有分号
      semi: true,
      // 使用单引号代替双引号
      singleQuote: true,
      // 末尾使用逗号
      trailingComma: 'es5',
      // 箭头函数,只有一个参数的时候,也需要括号
      arrowParens: 'always',
    }
    

    3.修改 .eslintrc.js 配置

    强制当和eslint冲突时,以prettier为准

    module.exports = {
        ...
    
        extends: [
            ...
            'prettier',
            'plugin:prettier/recommended'
        ],
        ...
    };
    

    提交规范

    我们需要在提交代码前对代码质量、代码格式和commit信息进行约束,为此,我们需要先注册commit提交前钩子

    1-安装husky

    文档看这里:传送门

    yarn add husky -D
    

    2-初始化husky

    在package.json文件夹下新增prepare脚本,并立即运行一次

    "scripts": {
        ...
        "prepare": "husky install"
      },
    

    3-注册hook

    我们使用pre-commit钩子来拦截提交行为,

    npx husky add .husky/pre-commit "npm run check"
    git add .husky/pre-commit
    

    此时,当git commit发生时,将会调用check脚本,但这默认事针对全部文件的,因此我们需要借助另一个npm包帮我们把当前更改的文件提取出来单独校验

    1-安装lint-staged

    文档看这里:传送门

    yarn add lint-staged -D
    

    2-修改package.json配置

    "lint-staged": {
        "*.{js,ts,vue}": [
          "npm run eslint",
          "prettier --parser=typescript --write"
        ]
    }
    

    3-与husky关联

    将lint-staged作为check的指向脚本

    "scripts": {
        ...
        "check": "lint-staged"
      },
    

    最后我们来对commit提交格式进行约束,这可以通过commitlint来帮我们完成,文档看这里:传送门

    1-安装

    yarn add @commitlint/config-conventional @commitlint/cli -D
    

    2-将其校验位置放在check脚本执行前

    npx husky add .husky/commit-msg  'npx --no -- commitlint --edit ${1}'
    

    3-创建配置文件commitlint.config.cjs

    module.exports = {
        extends: ['@commitlint/config-conventional'],
        rules: {
            'type-enum': [
                2,
                'always',
                [
                    'feature', // 迭代功能
                    'conf', // 修改构建配置
                    'fixbug', // 修复bug
                    'refactor', // 代码重构
                    'optimize', // 代码优化
                    'style', // 仅修改样式文件
                    'docs', // 文档补充说明
                ],
            ],
            'header-max-length': [0, 'always', 72], //限制最长72
        },
    };
    

    4-测试使用

    image.png

    如果本文对您有用,希望能得到您的点赞和收藏


    相关文章

      网友评论

          本文标题:企业级前端工程化配置指南:vite4 + vue3 + ts +

          本文链接:https://www.haomeiwen.com/subject/yiayydtx.html