打通webpack任督二脉

打通webpack任督二脉

十二月 02, 2020

image

一、基础梳理(上帝视角de灵魂拷问)

1.1 webpack是什么?

  • webpack就是一个js的翻译器
    • 它只认识import 这样的语句,其他高级js语法,一概不认。

核心定义:模块打包工具 👏👏👏

  • 识别import,引入import模块,打包生成最终的模块。

image

1.2 什么是webpack模块

image

1.3 webpack.config.js的作用是什么?

扩展webpack的能力,提供给webpack使用,webpack会默认读取webpack.config.js的信息。

1.4 Loader是什么?

我的理解:它就是一个对于特定文件所提供给webpack打包的一种打包方案。

stackoverflow Reference https://stackoverflow.com/a/46176755/7552246

Loaders

Loaders work at the individual file level during or before the bundle is generated.
bundle生成期间或之前,loader在单个文件级别工作。

Plugins

Plugins work at bundle or chunk level and usually work at the end of the bundle generation process. Plugins can also modify how the bundles themselves are created. Plugins have more powerful control than loaders.
pluginbundlechunk级别工作,通常在bundle生成结束时工作。插件还可以修改bundle本身的创建方式。plugin具有比loader更强大的控制功能。

image

准备工作

  1. 什么是AST?

AST(Abstract Syntax Tree),

  1. AST在JS代码执行的那个阶段产生?

词法分析–>语法分析(生成AST)–>预编译–>解释执行

  1. AST语法树
1
2
3
4
5
6
7
8
9
10
11
type:         描述该语句的类型  --> 变量声明的语句
kind: 变量声明的关键字
declaration: 声明内容的数组,里面每一项也是一个对象
type: 描述该语句的类型
id: 描述变量名称的对象
type: 定义
name: 变量的名字
init: 初始化变量值的对象
type: 类型
value: 值
row: 值,判别是否 带引号

基础配置优化

  1. 利用好webpack.config.js配置中的resolve,主动告诉webpack,我们需要对于哪些文件进行一个打包查找:(这里优先介绍常用的)

    1> extensions,告诉webpack,我们需要优先查找哪些没有后缀名但是拥有前缀名的文件,列在数组首位的后缀名优先。

    2> alias设置别名路径,当路径过长的时候,可以使用alias设置短链接指向。

  2. 合适场景,利用好合适loader去处理合适文件,例如可以利用url-loader去处理图片文件,将图片适当的base64化。

  3. loader中配置exclude & include,缩小complier范围。

  4. 利用cache-loader & cache-plugin缓存大体量的loader OR plugin,实现提效。

分割打包策略

为什么要分包?分什么包?怎么分包?分包可以达到什么效果?

  • 为什么要分包?
    • 原始的打包会将node_modules需要打包的(src)文件打包进一个bundle,在client进行缓存的时候,重新打包请求,耗费时间,导致首页白屏时间较长,可以选择将需要稳定版本的node_modules持久缓存起来,经常变化的lib/src待编译文件打包进核心的bundle
  • 分什么包?
    • 可以将稳定版本的node_modules分包进一个stable vendor;可以将需要latest版本的node_modules分包进一个lazy vendor;可以将核心待编译文件分包进main bundle;可以将测试文件分包进test vendor,注意需要在main bundleexclude测试文件
  • 怎么分包?
    • webpack 4之前利用的是SplitChunksPlugin这个插件,但是4版本中已被废弃,可以直接在内部通过optimization进行配置。
      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
      28
      29
      30
      31
      module.exports = {
      optimization: {
      runtimeChunk: 'single',
      splitChunks: {
      chunks: 'all',
      maxInitialRequests: Infinity,
      minSize: 0,
      cacheGroups: {
      default: {
      name: 'common',
      chunks: 'initial',
      minChunks: 5, //模块被引用5次以上的才抽离
      // priority: -1 // 设置优先级
      },
      vendor: {
      test: /[\\/]node_modules[\\/]/,
      name(module) {
      const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
      // 部分模块是以 @ 开头的,直接在分包命名中过滤掉
      return `npm.vendor.${packageName.replace('@', '')}`;
      },
      },
      testModule: {
      chunks: 'all',
      test: /__test__\/*/,
      name: 'test.vendor' ,
      }
      },
      }
      },
      }
  • 分包可以达到什么效果?
    • image

缓存优化构建策略

  1. happypack,之前有提到这个工具,但是其作者已经不维护了,另外多进程打包考验cpu能力,核数越高,打包越快,所以一般可能很难见成效;

  2. cache-loadercache-plugin可以很好的缓存那些大体量的loader或者plugin编译的结果在disk内存中,下次编译的时候可以直接从disk中拿。如果在服务端也可以在放置在redis中。

  3. HardSourceWebpackPlugin可以实现持久缓存,第一次构建可能效果不明显,第一次之后,效果可以实现提升。

怎么理解chunkbundle

image

如上图,其实还是很好理解的:

module是打包前的引入文件,chunk是打包时的处理文件,bundlewebpack处理chunk的产物。

chunk的数目怎么计算?很好识别的:一个入口文件一个chunk,一个分包策略一个chunk

webpack的构建流程是怎样的呢?

  1. 合并shell参数与webpack.config.js中的配置。

  2. config配置文件中去确定entry入口。

  3. 开始执行run编译,对应文件使用对应file-loader,递归处理模块。

  4. 根据入口与代码分割方案生成chunk

  5. 处理chunk,生成最终的 bundle

  6. 输出完成。

参考资料