资讯专栏INFORMATION COLUMN

Webpack Loader 高手进阶(三)

ivydom / 1111人阅读

摘要:相关的内容为这样对于一个处理的第二阶段也就结束了,通过去拦截不同类型的,并返回新的,跳过后面的的执行,同时在内部会剔除掉,这样在进入到下一个处理阶段的时候,不在使用的范围之内,因此下一阶段便不会经由来处理。

文章首发于个人github blog: Biu-blog,欢迎大家关注~

Webpack 系列文章:

Webpack Loader 高手进阶(一)
Webpack Loader 高手进阶(二)
Webpack Loader 高手进阶(三)

Webpack Loader 详解

前2篇文章主要通过源码分析了 loader 的配置,匹配和加载,执行等内容,这篇文章会通过具体的实例来学习下如何去实现一个 loader。

这里我们来看下 vue-loader(v15) 内部的相关内容,这里会讲解下有关 vue-loader 的大致处理流程,不会深入特别细节的地方。

git clone git@github.com:vuejs/vue-loader.git

我们使用 vue-loader 官方仓库当中的 example 目录的内容作为整篇文章的示例。

首先我们都知道 vue-loader 配合 webpack 给我们开发 Vue 应用提供了非常大的便利性,允许我们在 SFC(single file component) 中去写我们的 template/script/style,同时 v15 版本的 vue-loader 还允许开发在 SFC 当中写 custom block。最终一个 Vue SFC 通过 vue-loader 的处理,会将 template/script/style/custom block 拆解为独立的 block,每个 block 还可以再交给对应的 loader 去做进一步的处理,例如你的 template 是使用 pug 来书写的,那么首先使用 vue-loader 获取一个 SFC 内部 pug 模板的内容,然后再交给 pug 相关的 loader 处理,可以说 vue-loader 对于 Vue SFC 来说是一个入口处理器。

在实际运用过程中,我们先来看下有关 Vue 的 webpack 配置:

const VueloaderPlugin = require("vue-loader/lib/plugin")

module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /.vue$/,
        loader: "vue-loader"
      }
    ]
  }

  plugins: [
    new VueloaderPlugin()
  ]
  ...
}

一个就是 module.rules 有关的配置,如果处理的 module 路径是以.vue形式结尾的,那么会交给 vue-loader 来处理,同时在 v15 版本必须要使用 vue-loader 内部提供的一个 plugin,它的职责是将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。例如,如果你有一条匹配 /.js$/ 的规则,那么它会应用到 .vue 文件里的

template block 会经过以下的流程处理:

source.vue?vue&type=template -> vue-loader(抽离 template block ) -> pug-plain-loader(将 pug 模块转化为 html 字符串) -> templateLoader(编译 html 模板字符串,生成 render/staticRenderFns 函数并暴露出去)

我们看到经过 vue-loader 处理时,会根据不同 module path 的类型(query 参数上的 type 字段)来抽离 SFC 当中不同类型的 block。这也是 vue-loader 内部定义的相关规则:

// vue-loader/lib/index.js

const qs = require("querystring")
const selectBlock = require("./select")
...

module.exports = function (source) {
  ...
  const rawQuery = resourceQuery.slice(1)
  const inheritQuery = `&${rawQuery}`
  const incomingQuery = qs.parse(rawQuery)

  ...
  const descriptor = parse({
    source,
    compiler: options.compiler || loadTemplateCompiler(),
    filename,
    sourceRoot,
    needMap: sourceMap
  })

  // if the query has a type field, this is a language block request
  // e.g. foo.vue?type=template&id=xxxxx
  // and we will return early
  if (incomingQuery.type) {
    return selectBlock(
      descriptor,
      loaderContext,
      incomingQuery,
      !!options.appendExtension
    )
  }
  ...
}

当 module path 上的 query 参数带有 type 字段,那么会直接调用 selectBlock 方法去获取 type 对应类型的 block 内容,跳过 vue-loader 后面的处理流程(这也是与 vue-loader 第一次处理这个 module时流程不一样的地方),并进入到下一个 loader 的处理流程中,selectBlock 方法内部主要就是根据不同的 type 类型(template/script/style/custom),来获取 descriptor 上对应类型的 content 内容并传入到下一个 loader 处理:

module.exports = function selectBlock (
  descriptor,
  loaderContext,
  query,
  appendExtension
) {
  // template
  if (query.type === `template`) {
    if (appendExtension) {
      loaderContext.resourcePath += "." + (descriptor.template.lang || "html")
    }
    loaderContext.callback(
      null,
      descriptor.template.content,
      descriptor.template.map
    )
    return
  }

  // script
  if (query.type === `script`) {
    if (appendExtension) {
      loaderContext.resourcePath += "." + (descriptor.script.lang || "js")
    }
    loaderContext.callback(
      null,
      descriptor.script.content,
      descriptor.script.map
    )
    return
  }

  // styles
  if (query.type === `style` && query.index != null) {
    const style = descriptor.styles[query.index]
    if (appendExtension) {
      loaderContext.resourcePath += "." + (style.lang || "css")
    }
    loaderContext.callback(
      null,
      style.content,
      style.map
    )
    return
  }

  // custom
  if (query.type === "custom" && query.index != null) {
    const block = descriptor.customBlocks[query.index]
    loaderContext.callback(
      null,
      block.content,
      block.map
    )
    return
  }
}
总结

通过 vue-loader 的源码我们看到一个 Vue SFC 在整个编译构建环节是怎么样一步一步处理的,这也是得益于 webpack 给开发这提供了这样一种 loader 的机制,使得开发者通过这样一种方式去对项目源码做对应的转换工作以满足相关的开发需求。结合之前的2篇有关 webpack loader 源码的分析,大家应该对 loader 有了更加深入的理解,也希望大家活学活用,利用 loader 机制去完成更多贴合实际需求的开发工作。

文章首发于个人github blog: Biu-blog,欢迎大家关注~

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/102787.html

相关文章

  • Webpack Loader 高手进阶(一)

    摘要:在一个构建过程中,首先根据的依赖类型例如调用对应的构造函数来创建对应的模块。 文章首发于个人github blog: Biu-blog,欢迎大家关注~ Webpack 系列文章: Webpack Loader 高手进阶(一)Webpack Loader 高手进阶(二)Webpack Loader 高手进阶(三) Webpack loader 详解 loader 的配置 Webpack...

    MAX_zuo 评论0 收藏0
  • webpack进阶loader

    webpack的loaders是一大特色,也是很重要的一部分。这遍博客我将分类讲解一些常用的laodershowImg(https://segmentfault.com/img/remote/1460000005742040); 一、loaders之 预处理 css-loader 处理css中路径引用等问题 style-loader 动态把样式写入css sass-loader scss编译器 ...

    qylost 评论0 收藏0
  • Webpack Loader 高手进阶(二)

    摘要:如果函数没有返回值的话,那么进入到下一个的函数的执行阶段。这也是异步化的一种方式如果执行后有返回值,执行开始下一个执行以上就是对于在构建过程中执行流程的源码分析。 文章首发于个人github blog: Biu-blog,欢迎大家关注~ Webpack 系列文章: Webpack Loader 高手进阶(一)Webpack Loader 高手进阶(二)Webpack Loader 高手...

    jackzou 评论0 收藏0
  • webpack进阶之插件篇

    摘要:基本环境搭建就不展开讲了一插件篇自动补全前缀官方是这样说的,也就是说它是一个自动检测兼容性给各个浏览器加个内核前缀的插件。 上一篇博客讲解了webpack环境的基本,这一篇讲解一些更深入的内容和开发技巧。基本环境搭建就不展开讲了showImg(http://static.xiaomo.info/images/webpack.png); 一、插件篇 1. 自动补全css3前缀 autop...

    Tonny 评论0 收藏0
  • [js高手之路]深入浅出webpack教程系列1-安装与基本打包用法和命令参数

    摘要:,我想大家应该都知道或者听过,是前端一个工具可以让各个模块进行加载预处理再进行打包。 webpack,我想大家应该都知道或者听过,Webpack是前端一个工具,可以让各个模块进行加载,预处理,再进行打包。现代的前端开发很多环境都依赖webpack构建,比如vue官方就推荐使用webpack.废话不多说,我们赶紧开始吧. 第一步、安装webpack 新建文件夹webpack->再在web...

    pubdreamcc 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<