Vue面试系列之什么是vue-loader?有什么作用

414 阅读2分钟

vue-loader 是什么?它有什么作用?

分析

这是一道工具类的原理题目,相当有深度,具有不错的人才区分度。

体验

使用官方提供的 SFC playground 可以很好的体验 vue-loader。

有了 vue-loader 加持,我们才可以以 SFC 的方式快速编写代码。

sfc.vuejs.org

<template>
  <div class="example">{{ msg }}</div>
</template>

<script>
export default {
  data() {
    return {
      msg: 'Hello world!',
    }
  },
}
</script>

<style>
.example {
  color: red;
}
</style>

思路

  • vue-loader是什么东东
  • vue-loader是做什么用的
  • vue-loader何时生效
  • vue-loader如何工作

回答范例

  1. vue-loader是用于处理单文件组件(SFC,Single-File Component)的 webpack loader

  2. 因为有了vue-loader,我们就可以在项目中编写 SFC 格式的 Vue 组件,我们可以把代码分割为<template>、<script><style>,代码会异常清晰。结合其他 loader 我们还可以用 Pug 编写<template>,用 SASS 编写<style>,用 TS 编写<script>。我们的<style>还可以单独作用当前组件。

  3. webpack 打包时,会以 loader 的方式调用 vue-loader

  4. vue-loader 被执行时,它会对 SFC 中的每个语言块用单独的 loader 链处理。最后将这些单独的块装配成最终的组件模块。

知其所以然

  1. vue-loader会调用@vue/compiler-sfc模块解析 SFC 源码为一个描述符(Descriptor),然后为每个语言块生成 import 代码,返回的代码类似下面:
// source.vue被vue-loader处理之后返回的代码

// 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 script
  1. 我们想要 script 块中的内容被作为 js 处理(当然如果是<script lang="ts">被作为 ts 处理),这样我们想要 webpack 把配置中跟.js 匹配的规则都应用到形如source.vue?vue&type=script的这个请求上。例如我们对所有*.js 配置了 babel-loader,这个规则将被克隆并应用到所在 Vue SFC 的
import script from 'source.vue?vue&type=script'

将被展开为:

import script from 'babel-loader!vue-loader!source.vue?vue&type=script'

类似的,如果我们对.sass 文件配置了 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'
  1. 当处理展开请求时,vue-loader 将被再次调用。这次,loader 将会关注那些有查询串的请求,且仅针对特定块,它会选中特定块内部的内容并传递给后面匹配的 loader。
  2. 对于<script>块,处理到这就可以了,但是<template><style>还有一些额外任务要做,比如:
  • 需要用 Vue 模板编译器编译 template,从而得到 render 函数
  • 需要对<style scoped>中的 CSS 做后处理(post-process),该操作在 css-loader 之后但在 style-loader 之前

实现上这些附加的 loader 需要被注入到已经展开的 loader 链上,最终的请求会像下面这样:

// <template lang="pug">
import 'vue-loader/template-loader!pug-loader!source.vue?vue&type=template'

// <style scoped lang="scss">
import 'style-loader!vue-loader/style-post-loader!css-loader!sass-loader!vue-loader!source.vue?vue&type=style&index=1&scoped&lang=scss'