webpack的几个常见loader源码浅析,以及动手实现一个md2html-loader(二)

简介: webpack的几个常见loader源码浅析,以及动手实现一个md2html-loader

babel-loader源码简析

首先看下跳过loader的配置处理,看下babel-loader输出fb71f21b94b9fc23707ca6c9059e47b5_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png上图我们可以看到是输出transpile(source, options)的code和map 再来看下transpile方法做了啥ffd7232dc3e2bc9bed0190451f75b7be_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.pngbabel-loader是通过babel.transform来实现对代码的编译的, 这么看来,所以我们只需要几行代码就可以实现一个简单的babel-loader

const babel = require("babel-core")
module.exports = function (source) {
  const babelOptions = {
    presets: ['env']
  }
  return babel.transform(source, babelOptions).code
}
vue-loader源码简析

vue单文件组件(简称sfc)

<template>
  <div class="text">
    {{a}}
  </div>
</template>
<script>
export default {
  data () {
    return {
      a: "vue demo"
    };
  }
};
</script>
<style lang="scss" scope>
.text {
  color: red;
}
</style>

webpack配置

const VueloaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
  ...
  module: {
    rules: [
      ...
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  }
  plugins: [
    new VueloaderPlugin()
  ]
  ...
}

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

const vueLoaderUse = vueUse[vueLoaderUseIndex]
    vueLoaderUse.ident = 'vue-loader-options'
    vueLoaderUse.options = vueLoaderUse.options || {}
    // cloneRule会修改原始rule的resource和resourceQuery配置,
    // 携带特殊query的文件路径将被应用对应rule
    const clonedRules = rules
      .filter(r => r !== vueRule)
      .map(cloneRule)
    // global pitcher (responsible for injecting template compiler loader & CSS
    // post loader)
    const pitcher = {
      loader: require.resolve('./loaders/pitcher'),
      resourceQuery: query => {
        const parsed = qs.parse(query.slice(1))
        return parsed.vue != null
      },
      options: {
        cacheDirectory: vueLoaderUse.options.cacheDirectory,
        cacheIdentifier: vueLoaderUse.options.cacheIdentifier
      }
    }
    // 更新webpack的rules配置,这样vue单文件中的各个标签可以应用clonedRules相关的配置
    compiler.options.module.rules = [
      pitcher,
      ...clonedRules,
      ...rules
    ]

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

再看一下vue-loader结果的输出34d283a2c478dec72a052e45bf21d70d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png当引入一个vue文件后,vue-loader是将vue单文件组件进行parse,获取每个 block 的相关内容,将不同类型的 block 组件的 Vue SFC 转化成 js module 字符串。

// vue-loader使用`@vue/component-compiler-utils`将SFC源码解析成SFC描述符,,根据不同 module path 的类型(query 参数上的 type 字段)来抽离 SFC 当中不同类型的 block。
const { parse } = require('@vue/component-compiler-utils')
// 将单个*.vue文件内容解析成一个descriptor对象,也称为SFC(Single-File Components)对象
// descriptor包含template、script、style等标签的属性和内容,方便为每种标签做对应处理
const descriptor = parse({
  source,
  compiler: options.compiler || loadTemplateCompiler(loaderContext),
  filename,
  sourceRoot,
  needMap: sourceMap
})
// 为单文件组件生成唯一哈希id
const id = hash(
  isProduction
  ? (shortFilePath + '\n' + source)
  : shortFilePath
)
// 如果某个style标签包含scoped属性,则需要进行CSS Scoped处理
const hasScoped = descriptor.styles.some(s => s.scoped)

然后下一步将新生成的 js module 加入到 webpack 的编译环节,即对这个 js module 进行 AST 的解析以及相关依赖的收集过程。

来看下源码是怎么操作不同type类型(template/script/style)的,selectBlock 方法内部主要就是根据不同的 type 类型,来获取 descriptor 上对应类型的 content 内容并传入到下一个 loader 处理7a71f4a4d078cffafbb1872918221447_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png这三段代码可以把不同type解析成一个import的字符串

import { render, staticRenderFns } from "./App.vue?vue&type=template&id=7ba5bd90&"
import script from "./App.vue?vue&type=script&lang=js&"
export * from "./App.vue?vue&type=script&lang=js&"
import style0 from "./App.vue?vue&type=style&index=0&lang=scss&scope=true&"

总结一下vue-loader的工作流程

  1. 注册VueLoaderPlugin 在插件中,会复制当前项目webpack配置中的rules项,当资源路径包含query.lang时通过resourceQuery匹配相同的rules并执行对应loader时 插入一个公共的loader,并在pitch阶段根据query.type插入对应的自定义loader
  2. 加载*.vue时会调用vue-loader .vue文件被解析成一个descriptor对象,包含template、script、styles等属性对应各个标签, 对于每个标签,会根据标签属性拼接src?vue&query引用代码,其中src为单页面组件路径,query为一些特性的参数,比较重要的有lang、type和scoped 如果包含lang属性,会匹配与该后缀相同的rules并应用对应的loaders 根据type执行对应的自定义loader,template将执行templateLoader、style将执行stylePostLoader
  3. 在templateLoader中,会通过vue-template-compiler将template转换为render函数,在此过程中, 会将传入的scopeId追加到每个标签的segments上,最后作为vnode的配置属性传递给createElemenet方法, 在render函数调用并渲染页面时,会将scopeId属性作为原始属性渲染到页面上
  4. 在stylePostLoader中,通过PostCSS解析style标签内容


参考文献


  1. webpack官网loader api(https://www.webpackjs.com/api/loaders/)
  2. 手把手教你写webpack yaml-loader(https://mp.weixin.qq.com/s/gTAq5K5pziPT4tmiGqw5_w)
  3. 言川-webpack 源码解析系列(https://github.com/lihongxun945/diving-into-webpack)
  4. 从vue-loader源码分析CSS Scoped的实现(https://juejin.im/post/5d8627355188253f3a70c22c)

目录
相关文章
|
1月前
|
移动开发 前端开发 HTML5
HTML5实现酷炫个人产品推广、工具推广、信息推广、个人主页、个人介绍、酷炫官网、门户网站模板源码
HTML5实现酷炫个人产品推广、工具推广、信息推广、个人主页、个人介绍、酷炫官网、门户网站模板源码
|
19天前
404错误页面源码,简单实用的html错误页面模板
小编精心准备一款404错误页面源码,简单实用的html错误页面模板,简单大气的页面布局,可以使用到不同的网站中,相信大家一定会喜欢的
12 2
404错误页面源码,简单实用的html错误页面模板
|
13天前
|
JavaScript
欢乐打地鼠小游戏html源码
这是一款简单的js欢乐打地鼠游戏,挺好玩的,老鼠出来用鼠标点击锤它,击中老鼠获得一积分。
22 2
|
1月前
好看的html网站维护源码
好看的html网站维护源码,源码由HTML+CSS+JS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面,
40 3
好看的html网站维护源码
|
1月前
|
移动开发 前端开发 HTML5
HTML5 Canvas发光Loading源码
一款基于HTML5 Canvas的发光Loading加载HTML源码。Loading旋转图标是在canvas画布上绘制的,整个loading动画是发光3D的视觉效果
25 1
HTML5 Canvas发光Loading源码
|
25天前
|
人工智能
大字体学生出勤记录系统网页HTML源码
源码介绍 上课需要一个个点名记录出勤情况,就借助AI制作了一个网页版学生出勤记录系统, 大字体显示学生姓名和照片,让坐在最后排学生也能看清楚,显示姓名同时会语音播报姓名, 操作很简单,先导入学生姓名和照片,点击到课或未到课就能自动下一位, 并且记录出勤情况,点击导出记录就能导出文件。
28 0
大字体学生出勤记录系统网页HTML源码
|
29天前
|
移动开发 网络协议 安全
HTML5页面被运营商DNS问题及解决方案,app中h5页面源码的获取
HTML5页面被运营商DNS问题及解决方案,app中h5页面源码的获取
85 4
|
1月前
|
移动开发 HTML5
超级高大上HTML5引导页源码 动态效果更好看
超级高大上HTML5引导页源码 动态效果更好看
57 3
超级高大上HTML5引导页源码 动态效果更好看
|
8天前
切方块游戏 HTML5+jQuery【附源码】
切方块游戏 HTML5+jQuery【附源码】
9 0