vue-loader
- vue-loader 是一个给 webpack 使用的 loader,让我们能以单页面应用(SFCs)的形式写 vue 组件
<template>
<div class="example">{{ msg }}</div>
</template>
<script>
export default {
data() {
return {
msg: "Hello world!",
};
},
};
</script>
<style>
.example {
color: red;
}
</style>
vue-loader提供了很多很酷的特性:
- 允许为一个 Vue 组件的每一部分使用其他的 webpack loaders,例如给`<style>`使用 Sass,给`<template>`使用 Pug;
- 允许在`.vue`文件中使用自定义块,并且有自定义的 loader 可以应用于自定义块
- 将`<style>` 和 `<template>`中的静态文件引用当做模块依赖对待,并且使用webpack loader处理这些静态资源引用;
- 对每个模块模拟实现局部CSS;
- 开发环境中实现热重载的状态保留;
概括来说,webpack 和 vue-loader 的结合会提供给你一个现代的,灵活的和非常强大的前端工作流用于实现 Vue.js 应用。
vue-loader 如何工作的
下面的部分是针对对于 vue-loader 内部实现细节感兴趣的维护者和贡献者,对于终端用户来说不是必备的知识。
- vue-loader 不是一个简单的源码转换 Loader。它使用专门的 loader 链(你可以认为每个模块都是一个虚拟模块)来处理 SFC 中的每个语言模块,并且把所有块组装到最终模块中。下面是一个关于整个过程如何实现的简短概述:
-
vue-loader 使用
@vue/component-compiler-utils把 SFC 源码解析为 SFC 描述符。然后生成一个每个语言块的 import,因此真正的返回模块代码看起来像这样:// code returned from the main loader for 'source.vue' // import the <template> block import render from 'source.vue?vue&type=template' // import the <script> block import script from 'source.vue?vue&type=script' export * from 'source.vue?vue&type=script' // import <style> blocks import 'source.vue?vue&type=style&index=1' script.render = render export default注意代码如何导入 source.vue 本身,每个块使用不同的请求参数
-
我们想要 script 块中的内容像
.js文件一样被处理,其他语言块也一样,所以我们想要 webpack 将任何已配置的匹配.js的模块规则也应用到像source.vue?vue&type=script的请求上。这是VueLoaderPlugin(src/plugins.ts)做的事情:对于在 webpack 配置中的每个模块规则,它创建了一个修改后的副本,指向了相应的 Vue 语言块请求。假设我们已经给所有
*.js文件配置了babel-loader。这个规则会被复制并且也应用到 Vue SFC 的<script>块。在 webpack 内部,像这样的请求import script from "source.vue?vue&type=script";将会扩展成:
import script from "babel-loader!vue-loader!source.vue?vue&type=script";注意
vue-loader也会匹配上,因为vue-loader应用于.vue文件相似的,如果你给
*.scss文件配置了style-loader+css-loader+sass-loader:<style scoped lang="scss">将会被
vue-loader转换为:import "source.vue?vue&type=style&index=1&scoped&lang=scss";然后 webpack 会把它扩展成:
import "style-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss"; -
当处理扩展后的请求时,
vue-loader将会再次包含进来。然而这次,vue-loader注意到请求有queries并且仅指向一个明确的块。所以它选择(src/select.ts)目标块的内容,然后把内容传递给匹配的 loader 进行处理 -
对于
<script>块,差不多就是这样了。对于<template>和<style>块,需要执行一些额外的任务:- 我们需要使用 Vue 模板编译器编译 template
- 我们需要在
css-loader处理之前,post-process(后处理,根据下文,应该是使用src/stylePostLoader.ts处理,即style-post-loader)<style scoped>块中的 CSS
技术上来说,这些是需要被注入到扩展后的 loader 链中的额外的 loaders(
src/templateLoader.tsandsrc/stylePostLoader.ts)。如果终端用户需要自己配置这些 loaders,那会非常复杂,所以VueLoaderPlugin也注入了一个全局的能够拦截 Vue<template>和<style>请求并且注入必要的 loaders 的Pitching loader (src/pitcher.ts)。最终的请求看起来像下面这样// <template lang="pug"> import "vue-loader/template-loader!pug-loader!vue-loader!source.vue?vue&type=template"; // <style scoped lang="scss"> import "style-loader!css-loader!vue-loader/style-post-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss";