话不多说,直接进入正题:
当webpack遇到.vue结尾的文件时,此时会去module的rules里面查找vue相关正则,如下图所示:
在此之前vue会使用vueLoaderPlugin给当前rules最前面加上pitch.js和templateLoader。
此时会从上到下执行loader的pitch方法,但是这个pitch方法的执行是有条件的:
也就是说要有query参数才会进入pitch方法,所以一开始并不会进入pitch方法。templateLoader也是如此:
此时所有的pitch方法执行完毕就开始从下到上执行loader,当执行到vue-loader,会把当前.vue里面的内容传给此loader,如图所示:
53行以前都是设置常量,看看53行做了些什么:
可以看到,将source分解成了三块,script、styles、template内容全部分离了出来。接下来直到102行,咱们直接看重点:
最终生成的代码如图所示:
这是vue-loader第一次解析得出的结果:
此时返回的值为normalizer函数的exports和一堆的import和export,很多人就蒙圈了,返回这么一段代码,那webpack会怎么处理呢?以第一行为例,webpack会返回.App.vue的内容并且再次通过vue-loader,这里和inline-loader不一样,inline-loader会以自己的loader为准,不会被module.rules里面设置的loader正则匹配,而是直接用inline-loader去处理
然后我们继续来分析normalizer干了些什么。直接看输出,内容如下:
可以看出render就是我们的模板渲染函数,scriptExports就是我们下图部分:
所以normalizer只是把我们的app.vue模版文件解析成一个普通的vue组件。用到的loader有:
第二次解析,用到的loader有:
此时多出一个picher函数,会先从上到下执行picher方法,再从下到上执行loader,如果当前的picher方法有返回值,则执行当前loader前面的loader 详情请看https://zhuanlan.zhihu.com/p/360421184。
此时可以看到又引入了App.vue,此时webpack又第二次使用vue-loader,在引用前会执行pitch.js loader的pitch方法,返回值如下:
看到这个返回值有的小伙伴可能又有点疑惑了,返回这个么老长一段代码,webpack又将怎么处理呢?这里可以看到返回的是inline-loader,此时还是以.App.vue结尾,但是此时不会再走vue-loader,而是从左到右加载cache-loader、babel-loader、。。。的pitch方法,如果pitch方法都没有返回值,那么将从右往左加载各个loader,同时每个loader的返回值将传递给下一个loader,直到执行完inline-loader上的所有loader。
返回刚刚的话题,经过pitch方法后新增的处理的loader,然后又加载了App.vue,此时由于有了incomingQuery.type,所以直接返回selectBlock的函数返回值:
此时进入selectBlock:
将我们的template的内容给了callback函数,loaderContext.callback是将vue-loader的处理结果交给下一个loader,下一个loader是templateLoader,如下图所示:
最终转换为render渲染函数。type为style和script转换过程类似。
总结:
- vueLoaderPlguin会给当前的的vue-loader前加上pitch.js方法和templateLoader方法。使用vue-loader将.vue结尾的文件解析为emplate,styles,script。并加上type再次导入到当前vue文件。
- 由于有type就会直接进入pitch方法,该方法会根据类型的不同加上不同的loader,比如type为template会被加上templateLoader,经过vue-loader的selectBlock获取到相关内容后交给templateLoader处理生成渲染函数render。type为styles会插入stylePostLoader。script还是原来的对象。