zoukankan      html  css  js  c++  java
  • 前端优化总结

      最近项目打包的时候发现打包后的文件夹占用内层巨大,项目的加载速度也是有可见的延迟,于是想尽办法优化包,最终从几十M压到了几M,趁此机会总结一波优化方法,仅供参考。

    # 前端优化
    
    ## 优化打包速度、加载速度、首屏体验,降低包size
    
    1. 图片压缩
        - 大尺寸图片大小尽量控制在 250kb 以下 小尺寸图片尽量控制在 50kb 以下
        - 在线压缩工具:http://www.bejson.com/ui/compress_img/
    
    2. 字体包压缩
        - 字体包通常很大 但是项目文件中使用该字体的往往就几个字
        - 安装 font-spider 可以把需要的字符抽取出来生成字体文件
            + `npm install font-spider -g`
            + 新建一个文件夹用于生成新的字体文件
            + 将需要使用字体的字符写入html任意标签中 并且引用原字体文件
            + `font-spider ./demo/*.html` 使用命令解析这个html文件 就会生成新的字体包
    
    3. 防止编译文件中出现map文件
        - 打包后产生后缀名为.map的文件是由于配置了sourcemap选项生成的,打包后的文件不容易找到出bug对应的源代码的位置,sourcemap就是来帮我们解决这个问题的,有了map就可以像未压缩的代码一样,准确的输出是哪一行哪一列有错。
        - 去config/index.js中改一个参数就行 `productionSourceMap: false`
    
    4. 使用CDN
        - 在 webpack.base.conf.js 配置 需要避免打包的依赖
        - 在 index.html 引入相应的cdn路径
        - 解决 打包时间长、打包后的体积过大、服务器网络不稳定或者宽带不高
    ```javascript
    externals: {
        'vue': 'Vue',
        'vue-router': 'VueRouter',
        'element-ui': 'ELEMENT',
        'echarts': 'echarts',
        'vuex': 'Vuex'
    },
    ```
    
    5. 使用gzip压缩
        - 去config/index.js中改一个参数 `productionGzip: true`
        - 安装 `npm install --save-dev compression-webpack-plugin@1.1.11`
        - 再打包就会生成 .gz 的压缩包文件(需服务器配合使用)
    
    6. 清扫代码
        - 使用Webpack的UglifyJsPlugin插件,压缩代码、删除console.log等调试语句、删除单行/多行/文档注释、删除sourceMap、copyright等
        - 再 webpack.prod.conf.js 中设置
    ```javascript
    new UglifyJsPlugin({
        uglifyOptions: {
            comments: false,
            show_copyright: false,
            compress: {
                warnings: false,
                drop_debugger: true,
                drop_console: true
            }
        },
        sourceMap: false,
        parallel: true
    }),
    ```
    
    7. 路由使用懒加载
        - 当定位到相应路由时才加载组件页面
        - 极大优化了 __首屏加载__ 过慢的问题
        - 在路由配置中使用`component: (resolve) => require(['./XXX.vue'], resolve)`
    
    8. momentJS
        - moment带有很多的语言包 将中文包过滤出来 在 webpack.prod.conf.js 的 plugins中加入 `new webpack.ContextReplacementPlugin(/moment[/\]locale$/, /zh-cn/),` 大约会减少200kb
        - 如果只用了moment的极少功能 如 format() 可以自己实现简易版的函数代替
    ```javascript
    // 简易版moment代替moment.js
    class Moment {
        date
      constructor(arg = new Date().getTime()) {
        this.date = new Date(arg);
      }
      padStart(num) {
        num = String(num);
        if (num.length < 2) {
          return '0' + num;
        } else {
          return num;
        }
      }
      unix() {
        return Math.round(this.date.getTime() / 1000);
      }
      static unix(timestamp) {
        return new Moment(timestamp * 1000);
      }
      format(formatStr) {
        const date = this.date;
        const year = date.getFullYear();
        const month = date.getMonth() + 1;
        const day = date.getDate();
        const week = date.getDay();
        const hour = date.getHours();
        const minute = date.getMinutes();
        const second = date.getSeconds();
        const weeks = ['一', '二', '三', '四', '五', '六', '日'];
    
        return formatStr.replace(/Y{2,4}|M{1,2}|D{1,2}|d{1,4}|h{1,2}|m{1,2}|s{1,2}/g, (match) => {
          switch (match) {
            case 'YY':
              return String(year).slice(-2);
            case 'YYY':
            case 'YYYY':
              return String(year);
            case 'M':
              return String(month);
            case 'MM':
              return this.padStart(month);
            case 'D':
              return String(day);
            case 'DD':
              return this.padStart(day);
            case 'd':
              return String(week);
            case 'dd':
              return weeks[week];
            case 'ddd':
              return '周' + weeks[week];
            case 'dddd':
              return '星期' + weeks[week];
            case 'h':
              return String(hour);
            case 'hh':
              return this.padStart(hour);
            case 'm':
              return String(minute);
            case 'mm':
              return this.padStart(minute);
            case 's':
              return String(second);
            case 'ss':
              return this.padStart(second);
            default:
              return match;
          }
        });
      }
    }
    
    export const moment = (arg) => {
      return new Moment(arg);
    };
    ```
    
    9. UI框架
        - 必须按需加载 无法按需加载的采用所需功能的替代方案
    
    10. 首屏加载视觉优化
        - 在入口 index.html 中加入骨架屏或者loading动画或者可跳转的导航栏
        - 可以消除白屏 争取更多加载时间
    
    ## 主流框架性能优化
    1. 使用 immutable.js 优化深层树渲染 避免不必要的渲染
        + React
            - 关键是对 shouldComponentUpdate 的控制
            - diff是比较虚拟节点树 对不同的节点进行更新再整体覆盖真实节点执行render函数 虽然避免了大量的DOM操作但是要渲染整个节点树 而immutable对象因为是不可变的 当顶层render执行时 那些没有改变的节点就不会触发他们自身的render函数 从而大幅提升性能
            - React.PureComponent 在只有一层 state 和 props 时 会自动进行浅比较 从而控制shouldComponentUpdate
            - 深层 state 和 props 就要用到 immutable.js 如果对象树中一个节点发生变化 只修改这个节点和受它影响的父节点,其它节点则进行共享
            - 参考文章 https://github.com/camsong/blog/issues/3
    ```javascript
    import { is } from 'immutable';
    
    shouldComponentUpdate: (nextProps = {}, nextState = {}) => {
      const thisProps = this.props || {}, thisState = this.state || {};
    
      if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
          Object.keys(thisState).length !== Object.keys(nextState).length) {
        return true;
      }
    
      for (const key in nextProps) {
        if (!is(thisProps[key], nextProps[key])) {
          return true;
        }
      }
    
      for (const key in nextState) {
        if (thisState[key] !== nextState[key] && !is(thisState[key], nextState[key])) {
          return true;
        }
      }
      return false;
    }
    ```
    
    ## 其他建议
    
    1. 使用 webpack 模块打包器 从多方面进行优化
    2. 尽可能减少请求次数 避免不必要的重复的请求
    3. 预加载即将呈现的内容 推迟加载当前不需要的内容
    4. 减少 DOM元素数量 `document.getElementsByTagName('*').length` 可获取页面元素数量
    5. CSS 避免使用 @import
    6. 移动端 避免空的图像来源
  • 相关阅读:
    实验0 了解和熟悉操作系统一、目的和要求
    读后感
    有穷自动机自动转化
    文法分析
    词法分析随笔
    git操作笔记
    面试题汇总
    MYSQL数据库设计
    Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用
    invalid comparison:java.util.Date and java.lang.String
  • 原文地址:https://www.cnblogs.com/eightFlying/p/optimization.html
Copyright © 2011-2022 走看看