-
Notifications
You must be signed in to change notification settings - Fork 383
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
webpack源码学习系列之二:code-splitting(代码切割) #100
Comments
本来 chunk1 应该是包含模块 c、b 和 d 的,但是由于 c 已经被其 parent-chunk(也就是 chunk1)包含,所以,必须将 c 从 chunk1 中移除,这样方能避免代码的冗余。 require.ensure(['e'], function (require) { |
@huangzhiyang166 抱歉,此处是我笔误了,多谢指正。需要移除的是模块 b,而非模块 c,2是模块 b 的 id,如文中示意图所示。 |
也就是说 t0 是其他t的父亲, 呵呵 。。呵呵 t0有的 其他t就不能有了, t0 t1 t10, t10 |
我也分不清module和chunk的区别,以后读源码还有一个方法就是像作者一样将功能最小化。写一个简单的例子再结合分析的重点就大致看出源码的走向。 |
mark |
前言
继上一篇 #99 之后,我们今天来看看如何实现 webpack 的代码切割(code-splitting)功能,最后实现的代码版本请参考这里。至于什么是 code-splitting ,为什么要使用它,请直接参考官方文档。
目标
一般说来,code-splitting 有两种含义:
换句话说,我们的目标是:将原先集中到一个 output.js 中的代码,切割成若干个 js 文件,然后分别进行加载。 也就是说:原先只加载 output.js ,现在把代码分割到3个文件中,先加载 output.js ,然后 output.js 又会自动加载 1.output.js 和 2.output.js 。
切割点的选择
既然要将一份代码切割成若干份代码,总得有个切割点的标志吧,从哪儿开始切呢?
答案:webpack 使用
require.ensure
作为切割点。然而,我用 nodeJS 也挺长时间了,怎么不知道还有
require.ensure
这种用法?而事实上 nodeJS 也是不支持的,这个问题我在CommonJS 的标准中找到了答案:虽然 CommonJS 通俗地讲是一个同步模块加载规范,但是其中是包含异步加载相关内容的。只不过这条内容只停留在 PROPOSAL (建议)阶段,并未最终进入标准,所以 nodeJS 没有实现它也就不奇怪了。只不过 webpack 恰好利用了这个作为代码的切割点。ok,现在我们已经明白了为什么要选择
require.ensure
作为切割点了。接下来的问题是:如何根据切割点对代码进行切割? 下面举个例子。例子
假设这个 example.js 就是项目的主入口文件,模块 a ~ f 是简简单单的模块(既没有进一步的依赖,也不包含
require.ensure
)。那么,这里一共有2个切割点,这份代码将被切割为3部分。也就说,到时候会产生3个文件:output.js ,1.output.js ,2.output.js识别与处理切割点
程序如何识别
require.ensure
呢?答案自然是继续使用强大的 esprima 。关键代码如下:观察上面的代码可以看出,识别出
require.ensure
之后,会将其存储到 asyncs 数组中,且继续遍历其中所包含的其他依赖。举个例子,example.js 模块最终解析出来的数据结构如下图所示:module 与 chunk
我在刚刚使用 webpack 的时候,是分不清这两个概念的。现在我可以说:“在上面的例子中,有3个 chunk,分别对应 output.js、1.output.js 、2.output.js;有7个 module,分别是 example 和 a ~ f。
所以,module 和 chunk 之间的关系是:1个 chunk 可以包含若干个 module。
观察上面的例子,得出以下结论:
好了,下面进入重头戏。
构建 chunks
在对各个模块进行解析之后,我们能大概得到以下这样结构的 depTree。
下面我们要做的就是:如何从8个 module 中构建出3个 chunk 出来。 这里的代码较长,我就不贴出来了,想看的到这里的 buildDep.js 。
其中要重点注意是:前文说到,为了避免代码的冗余,需要将模块 b 从 chunk1 中移除,具体发挥作用的就是函数
removeParentsModules
,本质上无非就是改变一下标志位。最终生成的chunks的结构如下:拼接 output.js
经历重重难关,我们终于来到了最后一步:如何根据构建出来的 chunks 拼接出若干个 output.js 呢?
此处的拼接与上一篇最后提到的拼接大同小异,主要不同点有以下2个:
后话
其实关于 webpack 的代码切割还有很多值得研究的地方。比如本文我们实现的例子仅仅是将1个文件切割成3个,并未就其加载时机进行控制。比如说,如何支持在单页面应用切换 router 的时候再加载特定的 x.output.js?
-------- EOF -----------
The text was updated successfully, but these errors were encountered: