阅读 315

【分享】项目构建优化,提升团队开发效率

大家好,我是code_shu,以后争取都是原创有价值,尽量不水。下面开始我们的正题。我会聊下我最近在搭建项目时做了哪些点的优化?与原来的模式相比,又能带来哪些方面的效率提升?看完本篇文章,你将能收获以下几点:

  • 熟练使用 importexport 进行前端工程自动化
  • 熟练使用 webpackrequire.context api 进行前端工程自动化
  • 前端工程自动化方面有了更好的认识

我们先从普通项目基本操作开始,然后对比优化方案,下面开始我们的正题。

普通项目结构

.
├── src
    ├── assets     --------------------------------------------静态文件
    ├── api        --------------------------------------------接口文件
    ├── components --------------------------------------------组件文件
    ├── router     --------------------------------------------vue-router 项目路由
    ├── store      --------------------------------------------vuex 项目状态管理
    ├── directives --------------------------------------------全局指令文件
    ├── minxins    --------------------------------------------混入文件
    ├── utils      --------------------------------------------工具函数文件
    ├── views      --------------------------------------------页面文件
    ├── App.vue    --------------------------------------------vue项目根组件
    └── main.js    --------------------------------------------项目入口

复制代码

我们在创建一些文件用来演示

.
├── src  
    ├── api        
    │   ├──user.js --------------------------------------------用户相关接口
    │   └──cart.js --------------------------------------------购物车相关接口 
    ├── components
    │   ├──Cart.vue   -----------------------------------------购物车组件
    │   └──Banner.vue  ----------------------------------------轮播图组件
    ├── directives
    │   └──index.js   ---------------------------------------- 全局指令
    ├── views
    │   └──home.vue   ---------------------------------------- 主页
    └── utils  
         ├──dom.js --------------------------------------------DOM相关的工具函数
         └──array.js   ----------------------------------------数组相关的工具函数
复制代码

api/user.js 里写两个演示接口


// 获取用户信息
const getUserInfo = ()=>({})

// 获取用户使用权限是否过期
const getUserExpired = ()=>({})

export {
    getUserInfo,   // 获取用户信息
    getUserExpired // 获取用户使用权限是否过期
}
复制代码

api/cart.js 里写两个演示接口


// 获取购物车商品分类
const getCartProductCategory = ()=>({})

// 获取购物车商品数量
const getCartProductCount = ()=>({})

export {
    getCartProductCategory, // 获取购物车商品分类
    getCartProductCount     // 获取购物车商品数量
}
复制代码

components/Cart.vue

<template>
  <div>
    <h1>Cart 组件</h1>
  </div>
</template>

<script>
export default {
  name: 'Cart',
  data () {
    return {}
  }
}
</script>
复制代码

components/Banner.vue

<template>
  <div>
    <h1>Banner 组件</h1>
  </div>
</template>

<script>
export default {
  name: 'Banner',
  data () {
    return {}
  }
}
</script>
复制代码

directives/index.js


import Vue from "vue" 
const draggable = {
      inserted(el, binding,vnode,oldVnode){
        //...
      },
      bind(el, binding,vnode,oldVnode){
        //...
      },
      update(el, binding,vnode,oldVnode){
      //...
      },
      unbind(el, binding,vnode,oldVnode){
      //...
      },
      componentUpdated(el, binding,vnode,oldVnode){
      //...
      }
}

const fcous = {
      inserted(el, binding,vnode,oldVnode){
        //...
      },
      bind(el, binding,vnode,oldVnode){
        //...
      },
      update(el, binding,vnode,oldVnode){
      //...
      },
      unbind(el, binding,vnode,oldVnode){
      //...
      },
      componentUpdated(el, binding,vnode,oldVnode){
      //...
      }
}
Vue.directive('draggable', draggable)
Vue.directive('fcous', fcous)
</script>
复制代码

然后 在 main.js里面 直接 import '@/directives'

views/home.vue

<template>
  <div class="wrapper">
    
  </div>
</template>

<script>
export default {
  data() {
    return {
      
    }
  },
  watch: {},
  computed: {},
  methods: {},
  created() {},
  mounted() {}
}
</script>
<style lang="scss" scoped></style>
复制代码

utils/dom.js 里写两个演示函数


// 获取DOM元素的样式
const getStyle = ()=>({})

// 获取DOM元素的属性
const getAttr= ()=>({})

export {
    getStyle, // 获取DOM元素的样式
    getAttr   // 获取DOM元素的属性
}
复制代码

API 使用优化

一般用法

Ps:我们默认你项目配置 别名 alias @src

api 的使用

views/home.vue

<template>
  <div class="wrapper">
    
  </div>
</template>

<script>
// api 按需使用
import { getUserInfo, getUserExpired } from "@/api/user"
import { getCartProductCategory, getCartProductCount } from "@/api/cart"

export default {
  data() {
    return {
      
    }
  },
  watch: {},
  computed: {},
  methods: {},
  created() {},
  mounted() {}
}
</script>
<style lang="scss" scoped></style>
复制代码

我们知道如果项目的体量越来越大,团队人员各自创建的 功能api名称 如 user.jscart.js不一定很语义化,可能会 取一个看似语义化而看不懂的 api文件名字 如ResourceLibraryProjectManagement.js资源库项目管理 的相关 api, 或许有人说,我不怕麻烦,我cv大法很厉害的,就怕复制粘贴错。

企业微信截图_16246762498073.png

我们对api的使用方式 开始进行优化,首先说明优化方向:

  1. 第一种方案,同样 通过 import 按需导入,达到如下效果
// 只要一个 import 进行按需导入
import { 
    getUserInfo, 
    getUserExpired,
    getCartProductCategory, 
    getCartProductCount 
} from "@/api"
复制代码

此种优化目的:我们不需要关心 你api模块名字是什么,因为每个人取名字风格不一样,唯一关心的 写了什么 api接口仅此而已

我们开始对 api 文件进行优化改造,改造后的api目录结构如下:

├── api  
    ├── modules    --------------------------------------------api模块         
    │   ├──user.js --------------------------------------------用户相关接口
    │   └──cart.js --------------------------------------------购物车相关接口 
    └──index.js  ----------------------------------------------api入口文件
复制代码

api/mudules/user.js


// 获取用户信息
export const getUserInfo = ()=>({})

// 获取用户使用权限是否过期
export const getUserExpired = ()=>({})

// 拒绝重复劳动
//export {
//    getUserInfo,   // 获取用户信息
//    getUserExpired // 获取用户使用权限是否过期
//}
复制代码

api/mudules/cart.js


// 获取购物车商品分类
export const getCartProductCategory = ()=>({})

// 获取购物车商品数量
export const getCartProductCount = ()=>({})

// 拒绝重复劳动
//export {
//    getCartProductCategory, // 获取购物车商品分类
//    getCartProductCount     // 获取购物车商品数量
//}
复制代码

api/index.js api入口文件

export * from "./modules/user.js"
export * from "./modules/cart.js"
复制代码
  1. 小伙伴说,第一种方案对我们1000+路由项目来说,维护很难,至少有几百个 import 按需导入接口,代码量多了上去维护难度也增加了,第二种改造方案继续:

改造后的目录结构依然不变,核心思想是模块化管理和入口文件

├── api  
    ├── modules    --------------------------------------------api模块         
    │   ├──user.js --------------------------------------------用户相关接口
    │   └──cart.js --------------------------------------------购物车相关接口 
    └──index.js  ----------------------------------------------api入口文件
复制代码

api/mudules/user.js

// 获取用户信息
export const getUserInfo = ()=>({})

// 获取用户使用权限是否过期
export const getUserExpired = ()=>({})

复制代码

api/mudules/cart.js


// 获取购物车商品分类
export const getCartProductCategory = ()=>({})

// 获取购物车商品数量
export const getCartProductCount = ()=>({})

复制代码

第二种方案与第一种方案唯一不同的就是api入口文件改造

api/index.js 第二种改造方案 的api入口文件

import Vue from 'vue'
// 通过 webpack 的 require.context 获取指定路径下面的js文件,为了可以进一步深度遍历,
// 第二个参数传为true
const files = require.context('./modules', true, /\.js$/)
// 所有api集合对象
const api = files.keys().reduce((modules, path) => {
  const apis = Object.keys(files(path)).reduce((r, key) => {
    r[key] = files(path)[key]
    return r
  }, {})
  return Object.assign({}, modules, apis)
}, {})
Vue.prototype.$api = api
复制代码

关于 require.context是什么?

一个webpackapi,通过执行require.context函数获取一个特定的上下文,主要用来实现自动化导入模块,在前端工程中,如果遇到从一个文件夹引入很多模块的情况,可以使用这个api,它会遍历文件夹中的指定文件,然后自动导入,使得不需要每次显式的调用import导入模块

具体请看官网:webpack.docschina.org/guides/depe…

然后 在 main.js里 直接 import "@/api", 使用方式则是简单了很多,没有了 import,缺点是 没有了按需,因为api集合对象是直接挂载在Vue的原型上了

使用示例:

views/home.vue

<template>
  <div class="wrapper"></div>
</template>
<script>
export default {
  data() {
    return {}
  },
  mounted() {
      console.log(this.$api)
      console.log(this.$api.getUserInfo)
      console.log(this.$api.getUserExpired)
      console.log(this.$api.getCartProductCategory)
      console.log(this.$api.getCartProductCount)
  }
}
</script>
<style lang="scss" scoped></style>
复制代码

说完 api在项目中的优化后,我们接着来优化我们组件的使用

组件使用优化

请看优化最终效果

views/home.vue

<template>
  <div class="wrapper"></div>
</template>
<script>

// 我想这样
import {
    Cart,
    Banner
} from "@/components"

// 我不想这样
//import Cart from "@/components/Cart.vue"
//import Banner from "@/components/Banner.vue"

export default {
  data() {
    return {}
  },
  components:{
    Cart,
    Banner
  }
}
</script>
<style lang="scss" scoped></style>
复制代码

开始我们的改造,组件目录结构如下:

├── api  
    ├── modules    --------------------------------------------组件模块         
    │   ├──Banner ---------------------------------------------轮播图组件
    │   │  └──index.vue
    │   └──Cart   ---------------------------------------------购物车组件
    │      └──index.vue
    └──index.js  ----------------------------------------------组件入口文件
   
复制代码

之所以这样设计目录结构,是因为考虑到你的组件 可能依赖很多为你这个组件服务的其他组件增强独立维护性

我们来写我们的组件入口文件

components/index.js

export { default as Banner } from "./modules/Banner"
export { default as Cart } from "./modules/Cart"
复制代码

以上就完成了组件方面的优化了,下面接着优化我们的全局指令

全局指令优化

全局指令优化,核心思想依然是 模块化+ 入口化 思想,即 一个入口文件管理众多模块文件,由 入口文件对外分发,因此更多的精力关注自己模块的编写即可

指令文件目录结构:

├── directives  
    ├── modules    -------------------------------------------- 组件模块         
    │   ├──focus.js ------------------------------------------- 获取焦点指令
    │   └──draggable.js   ------------------------------------- 拖拽指令
    └──index.js  ---------------------------------------------- 指令入口文件   
复制代码

directives/modules/focus.js

export default {
      inserted(el, binding,vnode,oldVnode){
        //...
      },
      bind(el, binding,vnode,oldVnode){
        //...
      },
      update(el, binding,vnode,oldVnode){
        //...
      },
      unbind(el, binding,vnode,oldVnode){
        //...
      },
      componentUpdated(el, binding,vnode,oldVnode){
        //...
      }
}
复制代码

directives/modules/draggable.js

export default {
      inserted(el, binding,vnode,oldVnode){
        //...
      },
      bind(el, binding,vnode,oldVnode){
        //...
      },
      update(el, binding,vnode,oldVnode){
        //...
      },
      unbind(el, binding,vnode,oldVnode){
        //...
      },
      componentUpdated(el, binding,vnode,oldVnode){
        //...
      }
}
复制代码

directives/index.js

import Vue from 'vue'
const files = require.context('./module', false, /\.js$/)
files.keys().forEach(key => {
  const fileName = key.replace(/(\.\/|\.js)/g, '')
  Vue.directive(fileName, files(key).default)
})
复制代码

最后 在main.js 导入 该文件 import "@/directives"

views/home.vue

<template>
  <div class="wrapper">
      <input type="text" v-focus />
  </div>
</template>
<script>

export default {
  data() {
    return {}
  }
}
</script>
<style lang="scss" scoped></style>
复制代码

相信有了以上优化思路,你也可以优化你的项目,由于文字不一定描述的很清楚,所以我把相关优化放在这个项目了,项目地址,如果觉得对你有所帮助,请不要吝啬的 你的 star,其他utils等都是类似的优化,就不一一道出了。

结语

以上就是我最近在项目搭建和前端工程自动化方面做的一些事,目的是降低相关使用门槛,提升团队效率。

文章若有不准确或错误的地方,欢迎指出,如果你有更好的点子,欢迎留言。

文章分类
前端
文章标签