Webpack学习笔记——性能优化(2)

7.代码压缩

代码压缩可以减少代码体积;破坏代码的可读性,提升破解成本;通常只是用于生产环境

目前最流行的代码压缩工具主要有两个:UglifyJsTerser

UglifyJs是一个传统的代码压缩工具,已存在多年,曾经是前端应用的必备工具,但由于它不支持ES6语法,所以目前的流行度已有所下降。

Terser是一个新起的代码压缩工具,支持ES6+语法,因此被很多构建工具内置使用。webpack安装后会内置Terser,当启用生产环境后即可用其进行代码压缩。

因此,我们选择Terser ,它的官网:https://terser.org/

关于副作用 side effect

副作用:函数运行过程中,可能会对外部环境造成影响的功能

如果函数中包含以下代码,该函数叫做副作用函数:

  • 异步代码
  • localStorage
  • 对外部数据的修改

如果一个函数没有副作用,同时,函数的返回结果仅依赖参数,则该函数叫做纯函数(pure function)


webpack+Terser

webpack自动集成了Terser

如果你想更改、添加压缩工具,又或者是想对Terser进行配置,使用下面的webpack配置即可

const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
module.exports = {
  optimization: {
    // 是否要启用压缩,默认情况下,生产环境会自动开启
    minimize: true, 
    minimizer: [ // 压缩时使用的插件,可以有多个
      new TerserPlugin(),             // 压缩js代码
      new OptimizeCSSAssetsPlugin()   // 压缩css代码
    ],
  },
};

8. tree shaking

代码压缩可以移除模块内部的无效代码,而tree shaking可以移除模块之间的无效代码,例如下面这个例子:

// myMath.js
export function add(a, b){
  console.log("add")
  return a+b;
}
export function sub(a, b){
  console.log("sub")
  return a-b;
}
// index.js    
import {add} from "./myMath"
console.log(add(1,2));

myMath.js这个工具模块有两个导出方法,但是我们的项目只使用了add方法,如果在打包的时候两个方法都打包的话无疑会增加无效代码量,tree shaking的作用就是移除无效的代码块,只针对我们使用的部分进行打包处理。

(在例如我们常用的lodash这个库,我们通常只是用它里边的部分方法,并没有全部使用,打包的话也无疑是增加了很多无效的代码,这时候tree shaking就很有必要。)

其实webpack2就开始支持了tree shaking。只要是生产环境,tree shaking就会自动开启。

原理

webpack会从入口模块出发寻找依赖关系,当解析一个模块时,webpack会根据ES6的模块导入语句来判断,该模块依赖了另一个模块的哪个导出。

webpack之所以选择ES6的模块导入语句,是因为ES6模块有以下特点:

  1. 导入导出语句只能是顶层语句
  2. import的模块名只能是字符串常量
  3. import绑定的变量是不可变的

这些特征都非常有利于分析出稳定的依赖

在具体分析依赖时,webpack坚持的原则是:保证代码正常运行,然后再尽量tree shaking

所以,如果你依赖的是一个导出的对象,由于JS语言的动态特性,以及webpack还不够智能,为了保证代码正常运行,它不会移除对象中的任何信息

因此,我们在编写代码的时候,尽量

  • 使用export xxx导出,而不使用export default {xxx}导出
  • 使用import {xxx} from "xxx"导入,而不使用import xxx from "xxx"导入

依赖分析完毕后,webpack会根据每个模块每个导出是否被使用,标记其他导出为dead code,然后交给代码压缩工具处理,代码压缩工具最终移除掉那些dead code代码。

使用第三方库

某些(很多)第三方库可能使用的是commonjs的方式导出,比如lodash,又或者没有提供普通的ES6方式导出,对于这些库,tree shaking是无法发挥作用的。

因此要寻找这些库的es6版本,好在很多流行但没有使用的ES6的第三方库,都发布了它的ES6版本,比如lodash-es

作用域分析(深度分析)

tree shaking本身并没有完善的作用域分析,可能导致在一些dead code函数中的依赖仍然会被视为依赖

插件webpack-deep-scope-plugin提供了作用域分析,可解决这些问题(这个库慎用,它的个人开发的,维护难免不及时,)

副作用问题

webpack在tree shaking的使用,有一个原则:一定要保证代码正确运行

在满足该原则的基础上,再来决定如何tree shaking

因此,当webpack无法确定某个模块是否有副作用时,它往往将其视为有副作用

因此,某些情况可能并不是我们所想要的

//common.js
var n  = Math.random();

//index.js
import "./common.js"

虽然我们根本没用有common.js的导出,但webpack担心common.js有副作用,如果去掉会影响某些功能

如果要解决该问题,就需要标记该文件是没有副作用的

package.json中加入sideEffects

// package.json 文件设置
{
    "sideEffects": false
}

有两种配置方式:

  • false:当前工程中,所有模块都没有副作用。注意,这种写法会影响到某些css文件的导入
  • 数组:设置哪些文件拥有副作用,例如:["!src/common.js"],表示只要不是src/common.js的文件,都有副作用

这种方式我们一般不处理,通常是一些第三方库在它们自己的package.json中标注

css tree shaking

webpack无法对css完成tree shaking,因为csses6没有半毛钱关系

因此对csstree shaking需要其他插件完成,例如:purgecss-webpack-plugin

注意:purgecss-webpack-plugincss module无能为力


9. 懒加载

懒加载就是动态加载,按需加载,当我们需要的时候再加载。使用的是 import() 语法,它会返回一个promise

实现思路:最开始会有一个webpackJsonp数组,等我们加载完需要的模块后,它会把加载的模块放进webpackJsonp数组中。

// index.js
const btn = document.querySelector("button"); 
btn.onclick = async function() {    // 当按钮被点击后才会去读取 util这个文件
  //动态加载
  //import 是ES6的草案
  //浏览器会使用JSOP的方式远程去读取一个js模块
  //import()会返回一个promise   (* as obj)
  // const { chunk } = await import(/* webpackChunkName:"lodash" */"lodash-es");
  const { chunk } = await import("./util");
  const result = chunk([3, 5, 6, 7, 87], 2);
  console.log(result);
};
//util.js 
export { chunk } from "lodash-es";   // 静态的方式,从 lodash-es中导出chunk方法

util.js会等到执行时才会引入,当我们执行到import时才会到服务端请求该模块的js文件,而不是在页面加载的时候就去请求,这样可以减少页面刚开始加载时东西过多而导致时间很长的问题。


10. gzip

gzip是一种压缩文件的算法

B/S结构中的压缩传输

Webpack学习笔记——性能优化(2)_第1张图片

优点:传输效率可能得到大幅提升

缺点:服务器的压缩需要时间,客户端的解压需要时间

使用webpack进行预压缩

使用compression-webpack-plugin插件对打包结果进行预压缩,可以移除服务器的压缩时间

Webpack学习笔记——性能优化(2)_第2张图片
下载安装:npm i -D compression-webpack-plugin

https://www.npmjs.com/package/compression-webpack-plugin
https://www.webpackjs.com/plugins/compression-webpack-plugin/

//webpack.config.js配置
const CompressionPlugin = require('compression-webpack-plugin');
 
module.exports = {
 plugins: [
    new CmpressionWebpackPlugin({
      test: /\.js/,   //只针对匹配到的文件进行压缩
      minRatio: 0.8 //压缩后是原来体积的0.8,才会进行压缩(只有压缩率比这个值小的资源才会被处理)
    })
  ]
};

11. ESlint(代码风格检查)

ESLint是一个针对JS的代码风格检查工具,当不满足其要求的风格时,会给予警告或错误

官网:https://eslint.org/

民间中文网:https://eslint.bootcss.com/

eslint规则集 rules https://eslint.bootcss.com/docs/rules/

具体使用查看课件。


12. bundle analyzer

webpack-bundle-analyzer

https://www.npmjs.com/package/webpack-bundle-analyzer

使用交互式可缩放树图可视化webpack输出文件的大小。便于直观地比较各个bundle文件的大小,以达到优化性能的目的。

//webpack.config.js 配置
const WebpackBundleAnalyzer = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;

module.exports = {
  mode: "production",
  plugins: [new WebpackBundleAnalyzer()]
};

优化部分就此完结,具体还要情况具体分析,不明白的地方还需查看课件与官方文档。

你可能感兴趣的:(笔记)