服务器webpack构建性能,webpack4笔记(6)

  • Post author:
  • Post category:其他


webpack 的性能瓶颈webpack 的构建过程时间长

webpack 打包的结果体积大

常见优化方案

构建过程提速策略

1.减轻 loader 工作

比如 babel-loader 最常见的优化方式是,用 include 或 exclude 来帮我们避免不必要的转译,比如 webpack 官方在介绍 babel-loader 时给出的示例:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

module: {

rules: [

{

test: /.js$/,

exclude: /(node_modules|bower_components)/,

use: {

loader: ‘babel-loader’,

options: {

presets: [‘@babel/preset-env’]

}

}

}

]

}

这段代码帮我们规避了对庞大的 node_modules 文件夹或者 bower_components 文件夹的处理。但通过限定文件范围带来的性能提升是有限的。

除此之外,如果我们选择开启缓存将转译结果缓存至文件系统,则至少可以将 babel-loader 的工作效率提升两倍。要做到这点,我们只需要为 loader 增加相应的参数设定:

1

loader: ‘babel-loader?cacheDirectory=true’

2.注意第三方库

第三方库以 node_modules 为代表,它们庞大得可怕,却又不可或缺。DllPlugin 是基于 Windows 动态链接库(dll)的思想被创作出来的。这个插件会把第三方库单独打包到一个文件中,这个文件就是一个单纯的依赖库。这个依赖库不会跟着你的业务代码一起被重新打包,只有当依赖自身发生版本变化时才会重新打包。

3.Happypack——将 loader 由单进程转为多进程

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

const HappyPack = require(‘happypack’)

const happyThreadPool = HappyPack.ThreadPool({ size: os.cpus().length })

module.exports = {

module: {

rules: [

{

test: /.js$/,

// 问号后面的查询参数指定了处理这类文件的HappyPack实例的名字

loader: ‘happypack/loader?id=happyBabel’,

},

],

},

plugins: [

new HappyPack({

// 这个HappyPack的“名字”就叫做happyBabel,和楼上的查询参数遥相呼应

id: ‘happyBabel’,

// 指定进程池

threadPool: happyThreadPool,

loaders: [‘babel-loader?cacheDirectory’]

})

],

}

构建结果体积压缩

1.文件结构可视化,找出导致体积过大的原因

1

2

3

4

5

6

7

const BundleAnalyzerPlugin = require(‘webpack-bundle-analyzer’).BundleAnalyzerPlugin;

module.exports = {

plugins: [

new BundleAnalyzerPlugin()

]

}

2.拆分资源

代码分割

3.删除冗余代码(Tree-Shaking)

典型的应用,就是 Tree-Shaking。基于 import/export 语法,Tree-Shaking 可以在编译的过程中获悉哪些模块并没有真正被使用,这些没用的代码,在最后打包的时候会被去除。

4.按需加载

一次不加载完所有的文件内容,只加载此刻需要用到的那部分(会提前做拆分)

当需要更多内容时,再对用到的内容进行即时加载

首先 webpack 的配置文件:

1

2

3

4

5

6

output: {

path: path.join(__dirname, ‘/../dist’),

filename: ‘app.js’,

// 指定 chunkFilename

chunkFilename: ‘[name].[chunkhash:5].chunk.js’,

},

路由处的代码也要做一下配合:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

export default new Router({

mode: ‘history’,

routes: [

{

name: ‘Main’,

path: ‘/main’,

component: () => import(‘@/views/main/’)

},

{

path: ‘/demo’,

component: () => import(‘@/views/demo/’)

},

]

})

Gzip 压缩原理

压缩并不只是构建工具的工作,日常开发有个很方便的压缩操作:开启 Gzip。只需在 request headers 中加上这么一句:

1

accept-encoding:gzip

HTTP 压缩是一种内置到网页服务器和网页客户端中以改进传输速度和带宽利用率的方式。在使用 HTTP 压缩的情况下,HTTP 数据在从服务器发送前就已压缩:兼容的浏览器将在下载所需的格式前宣告支持何种方法给服务器;不支持压缩方法的浏览器将下载未经压缩的数据。最常见的压缩方案包括 Gzip 和 Deflate。

HTTP 压缩就是以缩小体积为目的,对 HTTP 内容进行重新编码的过程

Gzip 的内核就是 Deflate,目前我们压缩文件用得最多的就是 Gzip。可以说,Gzip 就是 HTTP 压缩的经典例题。

适用场景:

如果项目不是极端迷你的超小型文件,建议试试 Gzip。

疑问:压缩 Gzip,服务端要花时间;解压 Gzip,浏览器要花时间。中间节省出来的传输时间,真的那么可观吗?

答案是肯定的。如果你手上的项目是 1k、2k 的小文件,那确实有点高射炮打蚊子的意思,不值当。但更多的时候,我们处理的都是具备一定规模的项目文件。实践证明,这种情况下压缩和解压带来的时间开销相对于传输过程中节省下的时间开销来说,可以说是微不足道的。

webpack 的 Gzip 和服务端的 Gzip

一般来说,Gzip 压缩是服务器的活儿:服务器了解到我们这边有一个 Gzip 压缩的需求,它会启动自己的 CPU 去为我们完成这个任务。而压缩文件这个过程本身是需要耗费时间的,可以理解为我们以服务器压缩的时间开销和 CPU 开销(以及浏览器解析压缩文件的开销)为代价,省下了一些传输过程中的时间开销。

既然存在着这样的交换,那么就要求我们学会权衡。服务器的 CPU 性能不是无限的,如果存在大量的压缩需求,服务器也扛不住的。服务器一旦因此慢下来了,用户还是要等。Webpack 中 Gzip 压缩操作的存在,事实上就是为了在构建过程中去做一部分服务器的工作,为服务器分压。

因此,这两个地方的 Gzip 压缩,谁也不能替代谁。它们必须和平共处,好好合作。作为开发者,我们也应该结合业务压力的实际强度情况,去做好这其中的权衡。