从vue-loader源码分析CSS Scoped的实现

本文同步在个人博客shymean.com上,欢迎关注

虽然写了很长一段时间的Vue了,对于CSS Scoped的原理也大致了解,但一直未曾关注过其实现细节。最近在重新学习webpack,因此查看了vue-loader源码,顺便从vue-loader的源码中整理CSS Scoped的实现。

本文展示了vue-loader中的一些源码片段,为了便于理解,稍作删减。参考

Vue CSS SCOPED实现原理
Vue loader官方文档
相关概念
CSS Scoped的实现原理
在Vue单文件组件中,我们只需要在style标签上加上scoped属性,就可以实现标签内的样式在当前模板输出的HTML标签上生效,其实现原理如下

每个Vue文件都将对应一个唯一的id,该id可以根据文件路径名和内容hash生成

编译template标签时时为每个标签添加了当前组件的id,如

会被编译成

编译style标签时,会根据当前组件的id通过属性选择器和组合选择器输出样式,如.demo{color: red;}会被编译成.demo[data-v-27e4e96e]{color: red;}

了解了大致原理,可以想到css scoped应该需要同时处理template和style的内容,现在归纳需要探寻的问题

渲染的HTML标签上的data-v-xxx属性是如何生成的
CSS代码中的添加的属性选择器是如何实现的
resourceQuery
在此之前,需要了解首一下webpack中Rules.resourceQuery的作用。在配置loader时,大部分时候我们只需要通过test匹配文件类型即可

{
test: /.vue$/,
loader: ‘vue-loader’
}
// 当引入vue后缀文件时,将文件内容传输给vue-loader进行处理
import Foo from ‘./source.vue’
复制代码
resourceQuery提供了根据引入文件路径参数的形式匹配路径

{
resourceQuery: /shymean=true/,
loader: path.resolve(__dirname, ‘./test-loader.js’)
}
// 当引入文件路径携带query参数匹配时,也将加载该loader
import ‘./test.js?shymean=true’
import Foo from ‘./source.vue?shymean=true’
复制代码
vue-loader中就是通过resourceQuery并拼接不同的query参数,将各个标签分配给对应的loader进行处理。

loader.pitch
参考

pitching-loader官方文档
webpack的pitching loader
webpack中loaders的执行顺序是从右到左执行的,如loaders:[a, b, c],loader的执行顺序是c->b->a,且下一个loader接收到的是上一个loader的返回值,这个过程跟"事件冒泡"很像。

但是在某些场景下,我们可能希望在"捕获"阶段就执行loader的一些方法,因此webpack提供了loader.pitch的接口。

一个文件被多个loader处理的真实执行流程,如下所示

a.pitch -> b.pitch -> c.pitch -> request module -> c -> b -> a
复制代码
loader和pitch的接口定义大概如下所示

// loader文件导出的真实接口,content是上一个loader或文件的原始内容
module.exports = function loader(content){
// 可以访问到在pitch挂载到data上的数据
console.log(this.data.value) // 100
}
// remainingRequest表示剩余的请求,precedingRequest表示之前的请求
// data是一个上下文对象,在上面的loader方法中可以通过this.data访问到,因此可以在pitch阶段提前挂载一些数据
module.exports.pitch = function pitch(remainingRequest, precedingRequest, data) {
data.value = 100
}}
复制代码
正常情况下,一个loader在execution阶段会返回经过处理后的文件文本内容。如果在pitch方法中直接返回了内容,则webpack会视为后面的loader已经执行完毕(包括pitch和execution阶段)。

在上面的例子中,如果b.pitch返回了result b,则不再执行c,则是直接将result b传给了a。

VueLoaderPlugin
接下来看看与vue-loader配套的插件:VueLoaderPlugin,该插件的作用是:

将在webpack.config定义过的其它规则复制并应用到 .vue 文件里相应语言的块中。

其大致工作流程如下所示

获取项目webpack配置的rules项,然后复制rules,为携带了?vue&lang=xx…query参数的文件依赖配置xx后缀文件同样的loader
为Vue文件配置一个公共的loader:pitcher
将[pitchLoder, …clonedRules, …rules]作为webapck新的rules
// vue-loader/lib/plugin.js
const rawRules =

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值