资讯专栏INFORMATION COLUMN

vue源码学习(一)——从入口开始

ybak / 2037人阅读

摘要:学习源码时,我们首先需要看的是文件,该文件里配置了的依赖以及开发环境和生产环境的编译的启动脚本等其他信息。一个是完整版,一个是运行时。运行时用来创建实例渲染并处理虚拟等的代码。基本上就是除去编译器的其它一切。

学习vue源码时,我们首先需要看的是package.json文件,该文件里配置了vue的依赖以及开发环境和生产环境的编译的启动脚本等其他信息。首先我们需要关注的是script。我们这里先看第一个dev脚本:

"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"

我们可以看到vue是采用了rollup编译的脚本,然后对应的查看其配置文件config.js

const builds = {
...
// Runtime+compiler development build (Browser)
  "web-full-dev": {
    entry: resolve("web/entry-runtime-with-compiler.js"),
    dest: resolve("dist/vue.js"),
    format: "umd",
    env: "development",
    alias: { he: "./entity-decoder" },
    banner
  },
...
}

在该文件中我们可以找到web-full-dev的配置项,并且知道其编译的文件为"web/entry-runtime-with-compiler.js"
那么我们就需要去找到该文件了。
我们可以发现entry-runtime-with-compiler.js的其中有一行代码是:

import Vue from "./runtime/index"

然后继续跟着代码往上找,我们会发现还是嵌套了好几层,最后在"/instance/index"中找到我们vue的定义:最终其路劲如下:

/src/platforms/web/web-runtime-with-compiler.js   
=> /src/platforms/web/runtime/index.js 
=> /src/core/index.js 
=> /src/core/instance/index.js 

最终我们在instance/index.js上找到了vue的庐山真面目,他的构造函数及其简单:

function Vue (options) {
  if (process.env.NODE_ENV !== "production" &&
    !(this instanceof Vue)
  ) {
    warn("Vue is a constructor and should be called with the `new` keyword")
  }
  this._init(options)
}

我们可以发现它并没有使用class的,只是一个普通的构造函数,通过 !(this instanceof Vue) 来强制使用new来构建。
之所以不采用class,个人理解是为了更好的把代码拆分。原型上的方法只需要通过prototype来添加。如下

initMixin(Vue) // 这里主要注册了_init
stateMixin(Vue) // $set,$delete,$watch
eventsMixin(Vue) // $on, $once, $off, $emit
lifecycleMixin(Vue) //  _update, $forceUpdate,$destroy
renderMixin(Vue) // $nextTick, _render

这边都是基于在Vue上扩展方法,这样就把代码分离开发,方便维护。不需要全部写到Vue函数内部。
然后我们往回走,我们可以看到/src/core/index.js 中

initGlobalAPI(Vue)
Object.defineProperty(Vue.prototype, "$isServer", {
  get: isServerRendering
})
Object.defineProperty(Vue.prototype, "$ssrContext", {
  get () {
    /* istanbul ignore next */
    return this.$vnode && this.$vnode.ssrContext
  }
})

Object.defineProperty(Vue, "FunctionalRenderContext", {
  value: FunctionalRenderContext
})

Vue.version = "__VERSION__"

该文件中主要就是注册全局API,以供我们内部或外部使用
再往上/src/platforms/web/runtime/index.js,我们可以看到

// install platform specific utils
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement

// install platform runtime directives & components
extend(Vue.options.directives, platformDirectives)
extend(Vue.options.components, platformComponents)

// install platform patch function 
Vue.prototype.__patch__ = inBrowser ? patch : noop // 用于把vNode显示到dom上的方法,这边要区分是浏览器环境还是weex环境

// public mount method
Vue.prototype.$mount = function () {
.....
} // 把dom挂在到页面上

这边就是注册一些全局的工具,以及patch方法
那么再往上:src/platforms/web/web-runtime-with-compiler.js, 这个文件中主要就是重写$mount

const mount = Vue.prototype.$mount
Vue.prototype.$mount = function (
){
...
}

那么为什么要重写呢?原来在runtime里面的$mount方法是没有编译功能的,而最后一个重写就是增加了编译。
在vue脚手架我们会让我们选择哪个版本:如下图

这就是2个版本的区别,是否包含编译功能。一个是完整版,一个是运行时。
vue官方属于解释了:

完整版:同时包含编译器和运行时的版本。
编译器:用来将模板字符串编译成为 JavaScript 渲染函数的代码。
运行时:用来创建 Vue 实例、渲染并处理虚拟 DOM 等的代码。基本上就是除去编译器的其它一切。

如果你需要在客户端编译模板 (比如传入一个字符串给 template 选项,或挂载到一个元素上并以其 DOM 内部的 HTML 作为模板),就将需要加上编译器,即完整版:
// 需要编译器
new Vue({
  template: "
{{ hi }}
" }) // 不需要编译器 new Vue({ render (h) { return h("div", this.hi) } })

重写$mount方法就是对template就行了编译转换为render方法
好了这边就简要的介绍了vue的入口。

您的点赞是我继续努力的动力!

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

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

相关文章

  • Vue源码学习)——追根究底Vue

    摘要:其中执行命令是我们当前所关注的,对于项目的文件结构,我们需要去找到项目的启动的入口文件,接下来我们去一步一步的找到分析命令是一个模块打包器。 打算开始学习vue的源码开始,我开始 serach 关键词:vue 源码,可是发现很多都不是我想要看到的东西,所以打算记录下来,学习的记录和日后分享。我在想这个文章的名字时,手把手系列?十分钟系列?小白到大佬系列?都不是,只是单纯的学习笔记 文件...

    Harriet666 评论0 收藏0
  • 打前端博客压压惊

    前言 本文所有内容全部发布再个人博客主页 https://github.com/muwoo/blogs欢迎订阅。不过最近因为事情比较多,有一段时间没有更新了,后面打算继续不断学习更新,欢迎小伙伴一起沟通交流~ 最近更新 前端单测的那些事 基于virtual dom 的canvas渲染 js Event loop 机制简介 axios 核心源码实现原理 JS 数据类型、赋值、深拷贝和浅拷贝 j...

    wangbinke 评论0 收藏0
  • 打前端博客压压惊

    前言 本文所有内容全部发布再个人博客主页 https://github.com/muwoo/blogs欢迎订阅。不过最近因为事情比较多,有一段时间没有更新了,后面打算继续不断学习更新,欢迎小伙伴一起沟通交流~ 最近更新 前端单测的那些事 基于virtual dom 的canvas渲染 js Event loop 机制简介 axios 核心源码实现原理 JS 数据类型、赋值、深拷贝和浅拷贝 j...

    villainhr 评论0 收藏0
  • 打前端博客压压惊

    前言 本文所有内容全部发布再个人博客主页 https://github.com/muwoo/blogs欢迎订阅。不过最近因为事情比较多,有一段时间没有更新了,后面打算继续不断学习更新,欢迎小伙伴一起沟通交流~ 最近更新 前端单测的那些事 基于virtual dom 的canvas渲染 js Event loop 机制简介 axios 核心源码实现原理 JS 数据类型、赋值、深拷贝和浅拷贝 j...

    xiaoqibTn 评论0 收藏0

发表评论

0条评论

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