深入 Webpack5 等构建工具系列二(3) - webpack 的依赖关系图

551 阅读4分钟

这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战

上一篇文章,下面我们再来讲一个理论上的东西。

首先,上图:

image-20210123103759910.png

这是当前项目的目录结构,以及 src 目录下 main.js 文件(目前已被设置为了 webpack 的入口文件)中的内容。可以看到,src 目录下一共有 3 个文件,其中,入口文件 main.js 中引入了另外两个 js 文件。

现在,我们再在 src 目录下的 js 目录下新增一个 test.js 文件,里面添加一行代码:console.log("Hello world!");,那么请问到时候在用 webpack 对项目进行打包的时候,这个 test.js 文件会被打包吗?答案是不会。

先上图:

image-20210123111710816.png

然后我们可以这样进行验证:

  1. 确认一下 index.htmlscriptsrc 的内容是否和配置文件 wk.config.js 中的出口配置内容相一致,比如这里就需要将 src 的值改为 ./build/bundle.js
  2. 执行 npm run build 命令;
  3. 在谷歌浏览器中打开 index.html 页面,按 Ctrl + Shift + J 快捷键打开 Console 控制台,如图:

image-20210123111211461.png

可见,并没有看到“Hello world!”的输出,这意味着 test.js 中的代码没有执行,也就是说 test.js 中的代码没有被打包进”出口“文件。那为什么这个 test.js 文件没有被打包进去呢?原因非常的简单,因为项目打包时,从入口文件开始,一步步去寻找其它引入的文件,找到最后发现没有任何地方有引入 test.js 文件,也就是说和 test.js 没有任何关系(也就是不在 webpack 的依赖关系图中),所以自然就不会把它打包进去了。

这就引出了一个概念:webpack依赖关系图

  • webpack 到底是如何对我们的项目进行打包的呢?
    1. 事实上 webpack 在处理应用程序时,会根据命令或配置文件找到入口文件;
    2. 接着从入口开始,去查找所有的依赖文件,最终会生成一个依赖关系图(是一个图结构,一种数据结构),这个依赖关系图会包含应用程序中所需的所有模块(比如 .js 文件、css 文件、图片、字体等);
    3. 然后遍历图结构,打包一个个模块(根据文件的不同使用不同的 loader 来解析);

image-20210116073911320.png

总之,webpack 会先形成这个依赖关系图,然后根据这个依赖关系图进行打包。

因此,我们也可以得出一个结论:如果我们在项目中使用 node 安装了一个库(比如通过 npm install axios 安装了 axios 库),而没有在项目的任何地方引入这个库,那么最后打包出来的内容就和这个库没有任何关系,不会对这个库进行打包,也不会增加最终打包出来的静态资源包的大小。所以呢,如果你安装了一个包,但是没有用它,最后是不会增加打包出来的包的大小的。

好,那下面我们修改一下 main.js 中的代码,在引入 format.js 文件的这行代码下面再添加一行代码:import './js/test.js';,如图:

image-20210123125516973.png

这就意味着已经引入了 test.js 文件,那么依赖关系图中就会有这个文件了,所以现在再进行打包,这个文件就会被打包了。我们再来执行 npm run build,就能在浏览器的控制台中看到 test.js 文件中的输出了:

image-20210123130115767.png

下面,还有个东西要提一下,后面在讲性能优化时还会讲到,这里先简单讲一下。

如果一个最终会被打包的文件中定义有一个函数,但是这个函数从未被使用过,那么请问这个函数需要被打包吗?不需要哈~因为你压根都没用过这个函数,那就不用给它打包了,如果你给它打包了,还会增加最终的包的大小。那我们怎么才能做到这个函数不被打包呢?这就需要另外一个技术,叫做 tree shaking。那我们后面讲性能优化时再细讲。

这里最重要的是要知道依赖关系图这一概念哈~

这样以后如果遇到类似问题:明明写了某个文件,但这个文件就是没有被打包。就有可能是因为这个文件不在依赖关系图中,从入口文件开始,并没有对这个文件有任何相关的依赖。