前端自动化加快vue项目的开发速度

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40639990/article/details/89960380

内部使用的管理平台这种项目大都时间比较仓促。实际上来说在使用了webpack + vue 这一套来开发的话已经大大了提高了效率。但是对于我们的开发层面。还是有很多地方可以再次提高我们的项目开发效率,让我们更加专注于业务,提高效率,毕竟时间就是生命。

production 环境自动删除console.log

使用编辑器进行全局搜索,发现有几十个页面有这个语句。
如果全部手动删除的话,又费时,又没效率。所以想到通过插件来删除。
安装需要的库
yarn add babel-plugin-transform-remove-console --save-dev
修改.babelrc 配置
“plugins”: [“transform-remove-console”]
在 npm run build 的时候,就会自动删除 console.log

按需引用element-ui

如果直接将 element-ui 全部引入将会导致项目体积过大,pc端还好,如果是移动端用户体验将会变差,因此首先考虑按需引入 element-ui。

解决方案

1.官方提供了一个按需引用的方法是使用 babel-plugin-component,可以参考:官方文档
2.element-ui也可以像lodash的cherry pick那样按需引入
首先去掉babel-plugin-component,lodash是一个一致性、模块化、高性能的 JavaScript 实用工具库。

import Button from 'element-ui/lib/button';
Vue.use(Button);

这里需要注意的一点是发现可以使用button组件,只是样式没了,因此需要导入样式文件

import 'element-ui/lib/theme-chalk/index.css';

当然样式文件也是可以按需加载的

/*icon字体路径变量*/
$--font-path: "~element-ui/lib/theme-chalk/fonts";

/*按需引入用到的组件的scss文件和基础scss文件*/
@import "~element-ui/packages/theme-chalk/src/base.scss";
@import "~element-ui/packages/theme-chalk/src/button.scss";

3.单独建立一个element-ui.js如下,将你需要的组件写进来

import Vue from 'vue'
import { Card, Button, Row, Col, Tag, Switch, Form, FormItem, Message, Input, Icon, Dropdown, DropdownMenu, DropdownItem, Popover, Tabs, TabPane } from 'element-ui'

Vue.component(Card.name, Card)
Vue.component(Button.name, Button)
Vue.component(Row.name, Row)
Vue.component(Col.name, Col)
Vue.component(Tag.name, Tag)
Vue.component(Switch.name, Switch)
Vue.component(Form.name, Form)
Vue.component(FormItem.name, FormItem)
Vue.component(Input.name, Input)
Vue.component(Icon.name, Icon)
Vue.component(Dropdown.name, Dropdown)
Vue.component(DropdownMenu.name, DropdownMenu)
Vue.component(DropdownItem.name, DropdownItem)
Vue.component(Popover.name, Popover)
Vue.component(Tabs.name, Tabs)
Vue.component(TabPane.name, TabPane)
Vue.prototype.$message = Message

巧用webpack实现自动化

Webpack是实现我们前端项目工程化的基础,但其实它的用处远不仅仅如此,我们可以通过Webpack来帮我们做一些自动化的事情。首先我们需要了解一下require.context()

require.context() ???

首先它是一个webpack的api,通过执行require.context() 来获取一个特定的上下文,这里的上下文,是指我们可以通过这个方法来筛选出我们需要的文件并且进行读取
使用 require.context 可以动态地引入文件。其实是Webpack通过解析 require() 的调用,提取出来如下这些信息:

Directory: ./template
Regular expression: /^.*\.ejs$/

想了解更多可以参考: 官方文档,但是文档中的表述非常官方。

什么时候需要用到require.context()

使用require.context()同时也可以减少我们的重复代码
情景1
更加合理地处理路由文件
随着项目越来越大,需要的模块越来越多,require.context()这个时候可以实现自动化导入模块,在前端工程中,如果遇到从一个文件夹引入很多模块的情况,可以使用这个api,它会遍历文件夹中的指定文件,然后自动导入,就不再需要每次显式的调用import导入模块。
举个栗子:在写vue多客服后台管理的项目中,把路由通过不同的功能划分成不同的模块,需要在index.js中一个个导入,需求模块越来越多,每次手动import会显得有些力不从心,这里就可以使用require.context()遍历来modules文件夹的所有文件然后一次性导入到index.js中。
在这里插入图片描述

在这里插入图片描述

生成一个这样的包含各种模块的modules目录,然后将每个功能的模块一次性地导入modules目录下的index.js。

modules文件夹中处理业务模块

modules文件夹中存放着我们所有的业务逻辑模块,至于业务逻辑模块怎么分,我相信大家自然有自己的一套标准。我们通过上面提到的require.context()接下来编写自动化的核心部分index.js。

/**
* @param directory 要搜索的文件夹目录不能是变量,否则在编译阶段无法定位目录
* @param useSubdirectories  是否搜索子目录
* @param regExp 匹配文件的正则表达式,匹配哪种文件
* @return function 返回一个具有 resolve, keys, id 三个属性的方法
          resolve() 它返回请求被解析后得到的模块 id,接受一个参数request,request为test文件夹下面匹配文件的相对路径,返回这个匹配文件相对于整个工程的相对路径
          keys() 它返回一个数组,由所有符合上下文模块处理的请求组成,返回匹配成功模块的名字组成的数组 
          id 是上下文模块里面所包含的模块 id. 它可能在你使用 module.hot.accept 的时候被用到
          这三个都是作为函数的属性(注意是作为函数的属性,函数也是对象,有对应的属性)
*/
// require.context('demo', useSubdirectories = false, regExp = /\.js$/)
// (创建了)一个包含了 demo 文件夹(不包含子目录)下面的、所有文件名以 `js` 结尾的、能被 require 请求到的文件的上下文。

const files = require.context('.', true, /\.js$/)
//console.log(files.keys()) // 返回一个数组['./components.js','./login.js']
let configRouters = []
files.keys().forEach(key => {
  if (key === './index.js') return
  // console.log(files(key).default)
  configRouters = configRouters.concat(files(key).default)  // 读取出文件中的default模块
})
export default configRouters      // 抛出一个Vue-router期待的结构的数组

自动化部分写完了,那业务组件部分怎么写?

export default [
  {
    path: '/richtext',
    noDropdown: true, // 是否有下级菜单
    name: 'Richtext',
    hidden: false, // 是否隐藏
    icon: '', // 图标
    redirect: "/richtext", // 如果要默认路由携带名称的话,就需要redirect
    component: () => import('@/views/frame/Frame'),
    children: [
      {
        path: '',
        component: () =>import('@/views/richtext/ReachText')
      }
    ]
  }
]

路由初始化 这是我们的最后一步了,用来初始化我们的项目路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import RouterConfig from './modules'
import ToppingRouter from './topping'
import CommonRouters from './common'
Vue.use(VueRouter)
export default new VueRouter({
  // mode: 'history', // 需要服务端支持
  // base: '/',
  scrollBehavior: () => ({ y: 0 }),
  // the real routers
  routes: [...ToppingRouter, ...RouterConfig, ...CommonRouters]
})

之前我们创建完一个模块要手动的把这个模块import到路由文件声明的地方去使用。但是有了上面的index.js,在使用的时候你只需要去创建并抛出一个符合VueRouter规范的数组,剩下的就不用管了。import RouterConfig from './modules’已经帮你处理完了。
情景2
全局注册组件
当项目中需要全局注册很多个组件那么就要在main.js里面手动很多个Vue.component()。
这种情况下也可以使用require.context()来帮忙,把所有的公共组件放在global目录下面。
在这里插入图片描述

import Vue from 'vue'

// 自动加载 global 目录下的 .js 结尾的文件
const componentsContext = require.context('./global', true, /\.js$/)
console.log(componentsContext.keys())
componentsContext.keys().forEach(component => {
  const componentConfig = componentsContext(component)
  console.log(componentConfig) // 返回Module
  /**
  * 兼容 import export 和 require module.export 两种规范
  */
  const ctrl = componentConfig.default || componentConfig
  console.log(ctrl)
  console.log('ctrl.name', ctrl.name)
  Vue.component(ctrl.name, ctrl)
})

通过node自动生成vue组件

每次新建组件的时候,都要创建一个目录,然后新增一个.vue文件,然后写template、script、style这些东西,然后新建一个index.js、导出vue组件。都是一些重复的操作,写相同的代码,既消耗体力,也浪费时间,就等于浪费美好的生命。
这个时候我们可以借助node,然后告诉node帮我生成的组件名称就行了。然后让node来帮我们写代码。
我实现这个功能主要要借助Node的fs和process。
1.安装一下chalk,这个插件能让我们的控制台输出语句有各种颜色区分。
chalk
主要注意一下它可以使用的一些颜色color。
在根目录中创建一个 scripts 文件夹,
新增一个generateComponent.js文件,放置使用node生成组件的代码
新增一个template.js文件,放置我们可自定义组件模板的代码。

在项目中优雅地使用svg

参考未来必热:SVG Sprite技术介绍
svg可缩放矢量图形(Scalable Vector Graphics),顾名思义就是任意改变其大小也不会变形,是基于可扩展标记语言(XML),他严格遵从XML语法,并用文本格式的描述性语言来描述图像内容,因此是一种和图像分辨率无关的矢量图形格式,应该更多的使用场景是手机端,因为手机分辩率差异化大。
svg的优点如下
1.任意缩放
用户可以任意缩放图像显示,而不会破坏图像的清晰度、细节等。
2.较小文件
总体来讲,SVG文件比那些GIF和JPEG格式的文件要小很多,因而下载也很快。
3.超强显示效果
SVG图像在屏幕上总是边缘清晰,它的清晰度适合任何屏幕分辨力和打印分辨力,更好地帮助视力低下的人
使用svg的步骤
1.首先建一个name为cc-svg-icon的全局组件

<template>
  <svg  class="cc-svg-icon" :class="svgClass" aria-hidden="true">
    <use :xlink:href="iconName"></use>
  </svg>
</template>
<script>
export default {
  name: 'cc-svg-icon',
  props: {
    iconClass: {
      type: String
    },
    className: {
      type: String
    }
  },
  computed: {
    iconName () {
      return `#icon-${this.iconClass}`
    },
    svgClass () {
      if (this.className) {
        return `svg-icon ${this.className}`
      }
      return `svg-icon`
    }
  }
}
</script>
<style lang="scss" scoped>
.cc-svg-icon {
  width: 16px;
  height: 16px;
  vertical-align: middle;
  fill: currentColor;
  overflow: hidden;
}
</style>

2.写自动化index.js

const requireAll = requireContext => requireContext.keys().map(requireContext)
const req = require.context('./svg', true, /\.svg$/)
requireAll(req)

3.修改webpack.config.js
使用svg-sprite-loader对项目中使用的svg进行处理:

const path = require('path')

function resolve(dir) {
  return path.join(__dirname, './', dir)
}

module.exports = {
  chainWebpack: config => {
    // svg loader
    const svgRule = config.module.rule('svg') // 找到svg-loader
    svgRule.uses.clear() // 清除已有的loader, 如果不这样做会添加在此loader之后
    svgRule.exclude.add(/node_modules/) // 正则匹配排除node_modules目录
    svgRule // 添加svg新的loader处理
      .test(/\.svg$/)
      .use('svg-sprite-loader')
      .loader('svg-sprite-loader')
      .options({
        symbolId: 'icon-[name]'
      })

    // 修改images loader 添加svg处理
    const imagesRule = config.module.rule('images')
    imagesRule.exclude.add(resolve('src/icons'))
    config.module
      .rule('images')
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
  }
}

最后,在main.js 中引入import '@/icons’即可
至于svg ,可以到阿里开源的图标库 iconFont
进行下载。

gizp压缩

安装compression-webpack-plugin插件

cnpm install compression-webpack-plugin --save-dev
// or
yarn add compression-webpack-plugin --dev
// vue.config.js
const CompressionPlugin = require('compression-webpack-plugin')
module.exports = {
  chainWebpack: config => {
    // 这里是对环境的配置,不同环境对应不同的BASE_URL,以便axios的请求地址不同
    config.plugin('define').tap(args => {
      args[0]['process.env'].BASE_URL = JSON.stringify(process.env.BASE_URL)
      return args
    })
    if (process.env.NODE_ENV === 'production') {
      // #region 启用GZip压缩
      config
        .plugin('compression')
        .use(CompressionPlugin, {
          asset: '[path].gz[query]',
          algorithm: 'gzip',
          test: new RegExp('\\.(' + ['js', 'css'].join('|') + ')$'),
          threshold: 10240,
          minRatio: 0.8,
          cache: true
        })
        .tap(args => { })

      // #endregion
    }
  }
}

猜你喜欢

转载自blog.csdn.net/qq_40639990/article/details/89960380