Open youngwind opened 7 years ago
文中的depTree是从哪里生成的?@youngwind
请先看第一篇 #99 ,里面有提到。 @mosikoo
学习了
能别评论这么没有营养的东西吗,关注的也会收到邮件
在 2017年10月11日,下午2:52,aaawhz notifications@github.com 写道:
太难了, 看不太懂, 感觉前端也要变成算法了, 人工智能。 那得花多少时间掌握。。 麻烦。。 。。 还是炒股有意思啊。
— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/youngwind/blog/issues/101#issuecomment-335700418, or mute the thread https://github.com/notifications/unsubscribe-auth/ALHp93fOzvQapHbgREBQdXu8yioHM8Ffks5srGWkgaJpZM4MN2-e.
get
博主,loader的pitch过程没说呀。。。
大佬,你打包出来的文件为什么没有那么多的换行符之类的东西,看起来很干净?
你好!我已经收到你的邮件啦!谢谢!
前言
在上一篇 #100 中,我们实现了 webpack 的 code-splitting 功能。今天,我们来探索 loader 机制,最终实现的代码版本参考这里。(参考的 webpack 版本是这个)
问题
以加载 less 为例。
按照官方文档,想要加载 less 文件,我们需要配置三个 loader:style-loader!css-loader!less-loader。
该从什么地方着手研究呢? → 仔细观察最终生成的 output.js ,如下图所示。
由此我们进行以下思考:
style-loader 和 less-loader 的作用已经明了,但是,css-loader 发挥什么作用呢?虽然我一直按照官方文档配置三个 loader,但我从未真正理解为什么需要 css-loader。后来我在 css-loader 的文档中找到了答案。
来源:https://github.com/webpack-contrib/css-loader#options
既然如此,为了降低实现的难度,我们暂时不予考虑 import 和 url 的情况,也就无需实现 css-loader 了。
require(2)(require(3))
,很显然:”模块3的导出作为模块2的输入参数,执行模块2“,也就是说:“将模块3中的 css 代码插入到 head 标签中“。理解这个逻辑不难,难点在于:webpack 如何知道应该拼接成require(2)(require(3))
,而不是别的什么。也就说,如何控制拼接出require(2)(require(3))
?思路
思路进行到这儿,似乎走不下去了。看来只分析 output.js 还不足以理清,那么,让我们更进一步,观察 depTree,如下图所示。(图片较大,请点击放大查看)![image](https://cloud.githubusercontent.com/assets/8401872/23388226/ebcea460-fd9b-11e6-8cb8-cb2bb779ae62.png)
问题在于:为什么凭空多出来2个模块?到底是哪里起了作用呢?→ 我在 style-loader 的源码中找到了答案。
style-loader 的再 require
观察源码,我们发现:style-loader 返回的字符串里面又包含了2个 require,分别 require 了 addStyle 和 less-loader!style.less,由此,我们终于找到了突破口。→ loader 本质上是一个函数,输入参数是一个字符串,输出参数也是一个字符串。当然,输出的参数会被当成是 JS 代码,从而被 esprima 解析成 AST,触发进一步的依赖解析。 这就是多引入2个模块的原因。
loaders 的拆解与运行
loaders 就像首尾相接的管道那样,从右到左地被依次运行。对应的代码如下:
请注意:loader 也是分为同步和异步两种的,比如 style-loader 是同步的(看源码就知道,直接 return);而 less-loader 却是异步的,为什么呢?
异步的 less-loader
由代码我们可以看出:less-loader 本质上只是调用了 less 本身的 render 方法,由于 less.render 是异步的,less-loader 肯定也得异步,所以需要通过回调函数来获取其解析之后的 css 代码。
node-modules 的逐级查找
还差最后一点,我们就能完成 loader 机制了。 试想以下情景:webpack 检测到当前为 less 文件,需要找到 style-loader 和 less-loader 运行。但是,webpack 怎么知道这两个 loader 藏在哪个目录下面呢?他们可能藏在 example.js 所在目录的任意上层文件夹的 node-modules 中。 说到底,我们还是得实现之前提到过的 node-modules 的逐级查找功能。 核心代码如下:
举个例子,对于 style-loader 来说,生成的查找路径集合如下:
程序按照这个顺序依次查找,直到找到为止或者最终找不到抛出错误。
后话
至此,我们就完成了一个非常简单的 loader 机制,可以通过 style-loader 和 less-loader 处理加载 less 文件。当然,还有很多可以完善的地方,比如:
----------- EOF ------------