前端优化(webpack, js, html)

Posted SegmentFault

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端优化(webpack, js, html)相关的知识,希望对你有一定的参考价值。

作者:夏灬影
来源:SegmentFault 思否社区



HTTP优化


gzip压缩
资源的压缩与合并


HTTP协议上的gzip编码是一种用来改进web应用程序性能的技术,web服务器和客户端(浏览器)必须共同支持gzip。

浏览器请求url,并在request header中设置属性accept-encoding:gzip。表明浏览器支持gzip。

  • 该不该用 Gzip
  • 压缩 Gzip,服务端要花时间;解压 Gzip,浏览器要花时间。中间节省出来的传输时间,真的那么可观吗?建议较大文件进行gizp


  • webpack4中启动gzip压缩
  •    
         
         
       
    npm i -D compression-webpack-plugin

    plugins: [
      new CompressionPlugin({
        filename: "[path].gz[query]",
        algorithm: "gzip",
        test: /\.js$|\.html$|\.css/,
        threshold: 10240, // 只处理比这个值大的资源。按字节计算
        minRatio: 0.8 //     只有压缩率比这个值小的资源才会被处理
        deleteOriginalAssets: false, //是否删除原资源
      }),
    ];

详细配置 CompressionWebpackPlugin
https://www.webpackjs.com/plugins/compression-webpack-plugin/

CDN加速
现在大部分云服务商都是提供cdn服务



简单的来说: 原服务器上数据复制到其他服务器上,用户访问时,那台服务器近访问到的就是那台服务器上的数据。

CDN加速优点 是成本低,速度快。可以用CDN best的CDN进行加速,免费,可部署私有,公有CDN系统。可以实现宕机检测,自动切换ip,分线路,分组解析。也就是CDN加速的主要作用就是保证网站的正常访问,及加快网站访问速度和响应速度,防止网站因黑客攻击,DNS解析劫持故障等导致的网站服务器的宕机状况的出现。



图片(图标)方面


使用字体图标
推荐:Iconfont-阿里巴巴矢量图标库

雪碧图
将多个图标集成在一起


雪碧图制作起来麻烦,我还是推荐Iconfont的字体图标啦

图片使用Base64编码减少页面请求数(建议小图片)


  • Base64编码图片可以在浏览器自己显示出来

  • 采用Base64的编码方式将图片直接嵌入到网页中,而不是从外部载入,如<img src="data:image/gif;base64,/9j/2SDFG... >,这样下载HTML文档的时间就会增长了。在CSS背景图中也是可以这么做的


使用webpack处理图片成 base64


 
   
   
 
npm install --save-dev url-loader
// webpack.config.js
module.exports = {
  module: {
    rules: [{
      test: /\.(png|svg|jpg|gif|jpeg|ico|woff|woff2|eot|ttf|otf)$/,
      use: [{
          loader: "url-loader", // 根据图片大小,把图片优化成base64
          options: {
            limit: 10000, //小于10000字节的图片都进行base64操作
          }
        }
      ]
    }]
  }
};

webpack配置 JPG、PNG、GIF和SVG图像的压缩


 
   
   
 
// webpack.config.js
module.exports = {
  module: {
    rules: [
      {
        loader: "image-webpack-loader", // 先进行图片优化
        options: {
          mozjpeg: {
            progressive: true,
            quality: 65,
          },
          optipng: {
            enabled: false,
          },
          pngquant: {
            quality: "65-90",
            speed: 4,
          },
          gifsicle: {
            interlaced: false,
          },
          webp: {
            quality: 75,
          },
        },
      },
    ],
  },
};



html,css优化


<script>标签和<style>标签(看注释)


 
   
   
 
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  /**
  * 放头部:页面先解析<style>后得到css后解析html
  */
  <style>...<style>
  /**
  * 放头部:页面的解析在遇到js的时候需要运行完js之后才能继续
  * 缺点:js一旦加载或者运算很久,会导致用户白屏
  */
  <script>
    for (let i=0;i < 1000000000000000; i++) {
        console.log("年轻人不讲码德!你就慢慢等吧")
    }
  </script>
</head>
<body>
  <div id="container"></div>
  /**
  * 放尾部:页面的解析完毕开始加载js
  * 优点:用户无需等待js加载就可以看到界面
  */
   <script>
    var container = document.getElementById("container")
    console.log('container', container) // '<div id="container"></div>'
  </script>
</body>
  /**
  * 放尾部:页面先解析html后得到解析css
  * 缺点:导致html节点出来没样式后才有
  */
  <style>...<style>
</html>

回流和重绘
需要浏览器渲染机制,该文章就不展开讲了


  • 回流(重排)
  • 回流又名重排,指几何属性需改变的渲染。触发浏览器回流并重新生成渲染树。


  • 重绘
  • 重绘指更改外观属性而不影响几何属性的渲染。渲染树的节点发生改变,但是不影响该节点的几何属性。


  • 几何属性:包括布局、尺寸等可用数学几何衡量的属性
 
   
   
 
布局:display、float、position、list、table、flex、columns、grid
尺寸:margin、padding、border、width、height

  • 外观属性:包括界面、文字等可用状态向量描述的属性

 
   
   
 
界面:appearance、outline、background、mask、box-shadow、box-reflect、filter、opacity、clip
文字:text、font、word



js优化


减少 DOM 操作
  • 减少DOM 更改等操作

 
   
   
 
// bad
let box = document.getElementById('box')

box.innerHTML = '1'
box.innerHTML += '2'
box.innerHTML += '3'
...

// good
let content = ''
content = '1'
content += '2'
content += '3'

box.innerHTML = content // 一次性插入

  • DocumentFragment

不是真实 DOM 树,它的变化不会引起 DOM 树的重新渲染

 
   
   
 
let box = document.getElementById('box')

let content = document.createDocumentFragment()

let Fdiv = document.createElement('div')

Fdiv.innerHTML = '1'
Fdiv.innerHTML += '2'
Fdiv.innerHTML += '3'

content.appendChild(Fdiv)
// 只产生一次dom操作
box.appendChild(content)

图片懒加载


 
   
   
 
<li><img src="img/loading.gif" data-src="img/1.jpg"></li>

最开始每一个图片使用loading.gif,首屏加载的时候可以节省多张图片请求

原理 :滚动条设置到图片的时候加载data-src内的正常图片

防抖和节流


  • 防抖:在一定时间内,只能触发一次

 
   
   
 
/**
 * @param {Function} func 要执行的回调函数 
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行
 * @return null
 */
let timer, flag;
function throttle(func, wait = 500, immediate = true) {
    if (immediate) {
        if (!flag) {
            flag = true;
            // 如果是立即执行,则在wait毫秒内开始时执行
            typeof func === 'function' && func();
            timer = setTimeout(() => {
                flag = false;
            }, wait);
        }
    } else {
        if (!flag) {
            flag = true
            // 如果是非立即执行,则在wait毫秒内的结束处执行
            timer = setTimeout(() => {
                flag = false
                typeof func === 'function' && func();
            }, wait);
        }
        
    }
};
export default throttle

  • 节流: 一定时间内,只有最后一次操作,再过wait毫秒后才执行函数

 
   
   
 
let timeout = null;
/**
 * @param {Function} func 要执行的回调函数 
 * @param {Number} wait 延时的时间
 * @param {Boolean} immediate 是否立即执行 
 * @return null
 */
function debounce(func, wait = 500, immediate = false) {
    // 清除定时器
    if (timeout !== null) clearTimeout(timeout);
    // 立即执行,此类情况一般用不到
    if (immediate) {
        var callNow = !timeout;
        timeout = setTimeout(function() {
            timeout = null;
        }, wait);
        if (callNow) typeof func === 'function' && func();
    } else {
        // 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
        timeout = setTimeout(function() {
            typeof func === 'function' && func();
        }, wait);
    }
}

export default debounce



webpack4优化(打包过大等优化)


webpack 设置cdn优化
vuecli生成的项目进行配置


运行yarn build 发现vendors.js之中包含vue,vuex, vue-router
现在我们可以通过webpack的externals进行vue,vuex抽离掉使用cdn


 
   
   
 
# vue.config.js
module.exports = {
  configureWebpack:{
    externals: {
       'vue''Vue',
       'vuex''Vuex'
    }
  }
}

# store/index.js
import Vuex from "vuex";

// Vue.use(Vuex); 注释掉
// index.html
<body>
    <noscript>
      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without javascript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
    <!-- built files will be auto injected -->
    <script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.11/vue.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/vuex/3.1.3/vuex.min.js"></script>
  </body>

splitChunks(打包分割)


运行yarn build 发现vendors.js之中还有vue-router需要分离
可以利用webpack中的splitChunks分割出来
splitChunks的配置挺复杂的,需要大家自己学习,我只是提供一个方案


 
   
   
 
# vue.config.js
module.exports = {
  configureWebpack: {
    optimization: {
      splitChunks: {
        cacheGroups: {
          vendors: {
            test: /node_modules/,
            chunks: "initial",
            minChunks: 1,
            priority: -10,
          },
          router: {
            name: 'chunk-router',
            test: /[\\/]node_modules[\\/]vue-router[\\/]/,
            chunks: "all",
            minChunks: 1,
            priority: -5,
          }
        },
      },
    },
  },
};




点击左下角阅读原文,到  SegmentFault 思否社区  和文章作者展开更多互动和交流。

- END -

以上是关于前端优化(webpack, js, html)的主要内容,如果未能解决你的问题,请参考以下文章

WebPack实例与前端性能优化

前端构建WebPack实例与前端性能优化

前端性能优化总结(一)-js、css优化

非常全面的webpack之前端性能优化的实现分享

前端工程化之webpack打包知识总结

single-spa微前端简单实践与优化思路