BetaSu / fe-hunter

每天一道题,3个月后,你就是面试小能手,答题还能赚钱哦
1.67k stars 117 forks source link

Webpack的module、chunk、bundle的意义是? #59

Open BetaSu opened 2 years ago

BetaSu commented 2 years ago

发生问题的场景

小明初次接触Webpack,发现关于“打包”,存在三个概念:

需要解决的问题

你能从以下角度向他解释三者的关系么:

最佳答案评选标准

  1. 按以上角度答题
  2. 给出示例是加分项
  3. 能拓展其他打包工具的类似概念是极大的加分项

最佳答案

悬赏中,欢迎作答...

答题同学须知

围观同学须知

rumunanfeng commented 2 years ago

三者的定义

Module

对于 webpack 来说,项目源码中所有资源(包括 JS、CSS、Image、等等)都属于 module 模块。可以配置指定的 Loader 去处理这些文件。

Chunk

当使用 webpack 将我们编写的源代码进行打包时,webpack 会根据文件引用关系生成的文件叫chunk 。

Bundle

webpack 处理完 chunk 文件之后,最终会输出 bundle 文件,这个 bundle 文件包含了经过加载和编译的最终产物。

三者互相之间的关联

module、chunk 和 bundle 其实就是同一份代码在不同转换场景的三个名称。我们编写的代码在 webpack 处理前被 webpack 视为 module ,当 webpack 根据文件引用关系处理后变为 chunk ,最后编译/压缩打包等处理后输出的是 bundle 。

打个比方就是厨师(weback)要做一道小炒肉,所需的原料就是各种module,厨师炒之前需要对食材进行预处理,比如辣椒和猪肉需要切好,猪肉需要腌制,那么这个过程中辣椒需要依赖菜刀,猪肉需要依赖菜刀,盐,生抽,老抽,根据依赖关系得到的两个预处理好的食材就是 Chunk ,最后厨师再爆炒出锅的才是 Bundle。

humorHan commented 2 years ago

三者的定义及解释 Module 对于 webpack 来说,一切资源结是module(比如包括 JS、CSS、Image等),资源是有类型区别的,那么webpack要求大家根据不同类型使用不同loader去解析这个文件(类似说不同的工作类型需要不同的人员去处理,比如修车师傅用来修车,老板娘用来收钱哈哈)

Chunk 按照我们的入口文件,根据静态语法树分析后找到引用关系,将引用代码合并为一个文件,那这个时候就是我们的chunk。 ps:当然有例外情况,比如配置了webpack的单独打包这个时候就不会合并到一个文件,而且类似异步加载

Bundle webpack 处理完 chunk 文件之后,还会经过一系列的优化处理(比如将chunk代码转为es5再比如著名的webpack-bundle-analysis插件就是在最后输出前对依赖关系做的一个关系网用来协助优化构建,也是在这个阶段实现的),最终会输出 bundle 文件,这个 bundle 文件就是我们的最终产物。

ps:换句话说,这三个名词是构建期不同时间段的产物,建议结合webpack工作流一起理解哈

image
echoLC commented 2 years ago

如果要解释清楚这三个概念,还需要引入一个概念叫 Dependency,它与 ModuleChunkBundle 组成了 Webpack 构建流程中各个阶段的核心数据结构抽象。下面从源码角度分别解释各个概念。在此之前,我们将 Webpack 整个构建流程分成三个阶段:初始化阶段构建阶段生成阶段

Dependency

Webpack 源码中,Dependency 是初始化阶段最基本的数据结构,Webpack 初始化阶段就是从 entry 配置开始分析,将 entry 对应的文件以及所有 entry 引用的模块(文件)通过 addEntry 方法转换成 Dependency ,这个过程发生在 Webpack 初始化阶段。当然 Dependency 是最基础的数据结构,Webpack 真正在使用的时候是以 Dependency 作为基类创建 EntryDependencyModuleDependencyContainerEntryDependency(专门用于 mf 插件)等各种类。

Module

有了 Denpendency,表示初始化阶段完成了,接下来就进入构建阶段,那就是将 entry 对应生成的 Dependencies 创建生成 Module,在 Webpack 源码也有相对应的数据结构,ModuleWebpack 构建时处理的最小单位,这个阶段就会需要使用 loader 将各种文件转成标准的 JS 模块(正常是 es module),然后调用 acorn 这样的库将 JS 模块转成 AST,这也是为什么需要 loader 将一些非标准 JS 的文件转成标准 JS 模块的原因。有了 AST 就好办了,然后就可以分析 AST 生成各模块依赖关系,这个过程就生成了 Webapck 构建流程中非常核心的模块依赖图,所以在 Webpack 源码中也会有 ModuleGraph 这个数据结构,用来存储这个阶段生成的模块和各模块之间的关系。实际上 Webpack 构建阶段就是生成 Module 和构建依赖图的过程。

Chunk

Chunk 是生成文件之前最后一个数据结构的抽象,它是在最后生成阶段的时候”组装“出来的。很容易理解,实际上在编译阶段生成的所有 Module,在生成阶段就会根据模块之间的关系将一个或者多个 Module 组装起来生成一个个 Chunk。在 Webpack 默认的策略中,以下场景会默认生成 Chunk

如果对 Webpack 有理解的人可能会马上意识到上面生成 Chunk的 策略有很大的弊端,如果只有上述两种场景中生成 Chunk,那在单页面应用这种场景中,一般只有一个入口,这样生成的 Chunk 岂不是很大?怎么解决?

Webpack4 之前通过 CommonsChunkPlugin 插件解决,而 Webpack4 之后官方默认通过 SplitChunksPlugin 解决,这个插件允许用户自定义 Chunks 生成策略,当然官方也内置了默认策略,所以不会出现我们担忧的情况,在大型项目特别是单页面应用中单个 Chunk 体积过大的情况。想要了解更多这个插件的细节,可以看我之前写过的文章:精读 Webpack SplitChunksPlugin 插件源码

有了 Chunk 就简单了,在生成完所有的 Chunk 后,实际上 Webpack 会将构建控制权交回给 Compiler 对象,然后它根据用户的配置生成对应的文件,正常情况下,一个 Chunk 对应一个文件,这些文件也就是我们口中常说的 Bundle 了。

Bundle

实际上,我理解 Bundle 就是 Webpack 构建产物的一种更加书面的说法,通俗的讲,它表示的就是构建后生成的 js、css、image 等文件。

三者之间的关系

实际上,个人理解,它们代表的就是 Webpack 构建过程中不同阶段核心数据结构的抽象,这些名词不是随便造出来的概念,实际在 Webpack 源码中有相应的数据结构对应。从 Webpack 构建流程看,它们存在一个线性的关系: Dependency(初始化阶段) -> Module(构建阶段) -> Chunk(生成阶段) -> Bundle

specialbiscuit commented 1 year ago

https://juejin.cn/post/7005530386641977374 可参考