vue-loader解析

4,103 阅读2分钟

前言

最近在做一个玩具,其中用到了vue结构。

本文主要简单介绍下Webpack的loader具体做了些什么,然后简单解析一下vue-loader。

正文

webpack的loader

首先先介绍一下Webpack的loader究竟是什么,按照官网的说法,简单来说loader是让其他类型的文件转换成webpack能理解的js代码的一段代码(函数)。

Out of the box, webpack only understands JavaScript files. Loaders allow webpack to process other types of files and converting them into valid modules that can be consumed by your application and added to the dependency graph.

让我们从最简单的raw-loader出发,来看看loader究竟做了什么,raw-loader源码。可以看到一个loader就是一个函数,输入是文件内容,输出是一段commonJS模块代码。

raw-loader源码

然后我们在webpack中设置文件的loader就可以直接在js代码中通过import或者require直接引用这类非js文件了。

vue-loader

同理vue-loader也一样,vue-loader输入一个vue文件内容,然后输出一个js模块。如下图分别为vue文件内容以及经过vue-loader处理后的内容。

vue文件内容

vue-loader处理结果

其中beforeCreate、beforeDestory、render为vue-loader自己加的,在这个例子中其内容分别为

// beforeCreate(injectStyle)
function injectStyle (context) {
  if (disposed) return
  require("!!vue-loader/node_modules/vue-style-loader!css-loader?sourceMap!../node_modules/_vue-loader@14.2.2@vue-loader/lib/style-compiler/index?{\"optionsId\":\"0\",\"vue\":true,\"id\":\"data-v-6a905bfa\",\"scoped\":true,\"sourceMap\":true}!sass-loader!../node_modules/_vue-loader@14.2.2@vue-loader/lib/selector?type=styles&index=0!./index.vue")
}

// beforeCreate(anonymous)
function() {
  var record = map[id]
  if (!record.Ctor) {
    record.Ctor = this.constructor
  }
  record.instances.push(this)
}

// render
// Note: render函数基本上是template函数转换而成的,_c和_h不是本篇要讨论的内容,只需要知道render返回一个vnode
var render = function() {
  var _vm = this
  var _h = _vm.$createElement
  var _c = _vm._self._c || _h
  return _c(
    "div",
    [
      _c("p", [_vm._v("vue 测试")]),
      _vm._v(" "),
      _c("p", [_vm._v("访问了" + _vm._s(_vm.city))]),
      _vm._v(" "),
      _c("button", { on: { click: _vm.visit } }, [_vm._v("访问")]),
      _vm._v(" "),
      _c("component-test")
    ],
    1
  )
}

现在我们大致了解了vue-loader处理过后的模块其实是一个js对象,主要包括render、components以及其他自己写的内容以及一些自动生成的钩子函数。

其中template、script、style的解析通过vue-template-compiler实现,主要调用parseComponent