精华内容
下载资源
问答
  • vue源码
  • Vue源码分析带注解
  • vueSourceCodeInterpretation:用于学习vue源码的项目(来源吗慕课网vue源码解读视频)
  • VUE_KKB:vue源码实现
  • Vue源码分析.xmind

    2020-03-31 19:55:46
    Vue源码分析Vue源码分析Vue源码分析Vue源码分析Vue源码分析Vue源码分析Vue源码分析Vue源码分析
  • vue 1.0.28源码注释和Vue源码详细解析,主要包括vue整体入口,编译,指令,watcher,缓存等;并在后续持续完善; Vue原始注解版 注释原始码地址: src/vue/src/... 演示运行 # install dependencies npm install # ...
  • 瑞典人 手写vue源码
  • vue原理 vue源码分析

    2019-05-27 10:54:53
    vue源码分析 自己在淘宝花钱买得全集视频 vue原理
  • vue2.6.10-阅读 vue源码阅读
  • vue-src-learn vue源码学习
  • vue源码地址:https://github.com/vuejs/vue 知识点 获取vue 项目地址:https://github.com/vuejs/vue 迁出项目: git clone https://github.com/vuejs/vue.git 当前版本号:2.6.11 文件结构 源码目录: 调试环境...

    目标

    • 环境搭建
    • 掌握源码学习方法
    • vue初始化过程剖析
    • 深入理解数据响应式

    资源
    vue源码地址:https://github.com/vuejs/vue

    知识点

    获取vue
    项目地址:https://github.com/vuejs/vue
    迁出项目: git clone https://github.com/vuejs/vue.git
    当前版本号:2.6.11

    文件结构

    在这里插入图片描述

    源码目录:
    在这里插入图片描述

    调试环境搭建

    • 安装依赖: npm i
    • 安装rollup: npm i -g rollup
    • 修改dev脚本,添加sourcemap,package.json
    "dev": "rollup -w -c scripts/config.js --sourcemap --environment TARGET:web- full-dev",
    
    • 运行开发命令: npm run dev
    • 引入前面创建的vue.js,examples/commits/index.html
    <script src="../../dist/vue.js"></script>
    

    术语解释:

    • runtime:仅包含运行时,不包含编译器, 体积较小,适合webpack环境,所有模板都是预编译,执行的时候不需要编译器
    • common:cjs 规 范 , 用 于 webpack1
    • esm:ES模块,用于webpack2+打包,规范遵从ES6模块化规范,
    • umd: universal module definition,兼容cjs和amd,用于浏览器,兼容前后端两种模式,可用script直接引用,适合浏览器异步加载模块

    入口
    两种方式找入口文件:
    1、通过堆栈方式:
    2、通过对打包工具的了解:
    rollup也是打包工具,与webpack很相似,特别流行于js库打包,不涉及素材的东西

    dev脚本中-c scripts/config.js 指明配置文件所在
    参数TARGET:web-full-dev 指明输出文件配置项,line:123

    如何找到源码入口文件:
    1、找到package.json的dev配置
    在这里插入图片描述
    2、找到config.js, 搜索web-full-dev的配置
    在这里插入图片描述
    3、找到resolve方法
    在这里插入图片描述
    4、可以看一下alias文件内容,方便理解
    在这里插入图片描述
    alias里的web属性,就是resolve里面获取的文件名 web

    最后可以找到源码的入口文件是: /src/platforms/web/entry-runtime-with-compiler.js
    在这里插入图片描述

    初始化流程

    整体流程

    • new Vue()
      • _init()
    • $mount()
      • mountComponent()
        • updateComponent()
          • render()
          • update()
        • new Watcher()

    初始化文件:
    1、src\platforms\web\entry-runtime-with-compiler.js
    主要代码:

    import Vue from './runtime/index'
    
    // 扩展$mount方法
    const mount = Vue.prototype.$mount
    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
    	 // 用户配置选项
    	  const options = this.$options
    	  // resolve template/el and convert to render function
    	  // 获取渲染函数
    	  // el < template < render   优先级
    	  if (!options.render) {
    	  	if (template) {
    			...
    		} else if (el) {
          		template = getOuterHTML(el)
       		 }
       		 // 获取模板之后,编译它
    	    if (template) {
    			// 编译:获取渲染函数
    	      const { render, staticRenderFns } = compileToFunctions(template, {
    	        outputSourceRange: process.env.NODE_ENV !== 'production',
    	        shouldDecodeNewlines,
    	        shouldDecodeNewlinesForHref,
    	        delimiters: options.delimiters,
    	        comments: options.comments
    	      }, this)
    		}
    		// 执行默认挂载功能
    		return mount.call(this, el, hydrating)
    	  }
    

    源着上一个文件的vue导入,找到这个文件:
    2、src\platforms\web\runtime\index.js

    import Vue from 'core/index'
    // install platform patch function
    // 1.声明一个补丁函数
    Vue.prototype.__patch__ = inBrowser ? patch : noop
    
    // public mount method
    // 2.声明$mount方法:
    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
      el = el && inBrowser ? query(el) : undefined
      // 挂载执行
      return mountComponent(this, el, hydrating)
    }
    
    // devtools global hook
    /* istanbul ignore next */
    //控制台提示使用vue-devtools  和  vue版本提示
    if (inBrowser) {
    	if(!config.devtools){
    		console[console.info ? 'info' : 'log'](
              'Download the Vue Devtools extension for a better development experience:\n' +
              'https://github.com/vuejs/vue-devtools'
            )
    	}
    	console[console.info ? 'info' : 'log'](
            `You are running Vue in development mode.\n` +
            `Make sure to turn on production mode when deploying for production.\n` +
            `See more tips at https://vuejs.org/guide/deployment.html`
          )
    }
    

    关于vue-tools 和 vue版本提示表现在浏览器的console,如图
    在这里插入图片描述
    源着上一个文件导入的vue路径,找到如下文件
    3、\src\core\index.js

    import Vue from './instance/index'
    
    // 初始化全局api
    // 包括defineReactive、set、delete、nextTick、Use、Mixin、Extend、AssetRegisters等
    initGlobalAPI(Vue)
    
    // 判断是否是服务端渲染
    Object.defineProperty(Vue.prototype, '$isServer', {
      get: isServerRendering
    })
    Object.defineProperty(Vue.prototype, '$ssrContext', {
      get () {
        /* istanbul ignore next */
        return this.$vnode && this.$vnode.ssrContext
      }
    })
    // expose FunctionalRenderContext for ssr runtime helper installation
    Object.defineProperty(Vue, 'FunctionalRenderContext', {
      value: FunctionalRenderContext
    })
    

    源着上面文件导入的vue文件路径,找到下面的文件:
    4、src\core\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)
    }
    
    // 实例方法的初始化
    initMixin(Vue) // 混入_init()
    stateMixin(Vue) // $set/$delete/$watch
    eventsMixin(Vue) // $emit/$on/$off/$once
    lifecycleMixin(Vue) // $_update/$forceUpdate
    renderMixin(Vue)
    
    展开全文
  • vue_source_analysis Vue源码解读 本人的Vue源码阅读笔记 第一轮阅读仅考虑data、method、computed、watch以及最基本的双向绑定实现,有可能会顺便提及一些API的,但不会涉及组件、自定义指令、插件
  • vue源码解析 以及vue框架详解 以及vue使用 解压后即可查阅
  • Vue源代码 vue源码阅读
  • vue-admin-source:后台管理系统vue源码
  • Vue源码注释详解分析

    2021-01-05 17:37:34
    Vue源码注释
  • zhufeng_vue-source-code:Vue源码教程
  • vue-origin-source-research:vue源码研究
  • vue源码解析大局观(梳理执行流程) 上次写了一个简单版的vue其实就是通过读源码,加上看一些前辈的博客撸出来的。但是呢其实vue的源码我并没有看的太明白…,于是产生了死磕之心。 首先随便找一个自己写的vue项目 ...

    开头,中国加油,武汉加油。
    把混乱的时期拉回正轨。
    以现在的形式还有加一句全人类加油。

    vue源码解析大局观(梳理执行流程)

    上次写了一个简单版的vue其实就是通过读源码,加上看一些前辈的博客撸出来的。但是呢其实vue的源码我并没有看的太明白…,于是产生了死磕之心。

    首先随便找一个自己写的vue项目

    在项目目录下 node_modules/vue 撸一波

    结构

    简单粗暴一张图片
    我们重点先放在core(核心)上梳理入口 -> 流程

    1. core/index.js
      这时候发现它不是最终的入口,它还在import Vue
    2. core/instance/index.js
      这里是定义Vue函数的地方,看看它都做了什么
      凡是有这类代码** process.env.NODE_ENV **的地方先忽略
      1. this._init(options)
      2. initMixin(Vue)
        1. Vue.prototype._init = XXXX扩展了_init
        2. initLifecycle(vm)
          1. 修正parent$children
          2. $parent $children $refs的初始化
          3. 组件一些状态的初始化
        3. initEvents(vm)
          1. 主要工作初始化vm._events
        4. initRender(vm)
          这个厉害了渲染的一系列逻辑在这里
          我们先撸最重要的
          1. vm._cvm.$createElement都指向了createElement(划重点
          2. 下面搞了一波$attrs $listeners
        5. initInjections(vm)
          inject和provide是一对,有点类似react的上下文也是跨组件传值的一种方法,其实还挺少用的
          1. 如何查找provide
        6. initState(vm)
          一打开这也代码,哇偶。。 发际线不保的赶脚。 不方,首先兴奋一下终于出现了平时用vue写项目时频繁用到的,data、methods、props、computed、watch。(划重点)
          1. initProps
          2. initMethods
          3. initData
          4. initComputed
          5. initWatch
        7. initProvide(vm)
          1. 定义vm._provide,provide可以是函数
        8. if (vm.$options.el) {vm.$mount(vm.$options.el)}如果有el相关的配置执行$mount
      3. stateMixin(Vue)
        1. $set
        2. $delete
        3. $watch
      4. eventsMixin(Vue)
        1. $on
        2. $once
        3. ```$off``
        4. $emit
        5. 事件列表vm._events
      5. lifecycleMixin(Vue)
        1. _update定义(划重点)
          1. 数据更新
          2. 渲染vm.__patch__(划重点)
        2. $forceUpdate
          1. 强制更新vm._watcher.update()
        3. $destroy销毁
      6. renderMixin(Vue)
        1. $nextTick
        2. _render生成虚拟dom
          1. 初始化vnode

    今天梳理到这里,到这呢就把大概的流程梳理的差不多了,下次再开始那些画重点的地方。在梳理代码时,发现了很多Ts的语法,想起vue3要全面靠拢Ts吓得我赶紧温习温习Ts,一入前端坑似海。。。

    展开全文
  • vue-source-code:vue源码学习
  • vue源码学习 1模拟vue功能 03-12 喜欢Vue vue-ctr deepProps check-getValueByPath check-createGetValueByPath deepProps 创建虚拟dom 修补 咖喱化 JGVue 每个文件内有响应的代码及学习内容 //待办事项待...
  • Vue源码注释版本及Vue源码详细解析本项目介绍的二进制代码版本是当前(17年2月23日)1.x版本的最新版本v1.0.26,2.x版本的源码会在之后更新。 Vue原始码详细解析 Vue元数据详细解析教程包含了Vue中从数据观察到模板...
  • vue源码.vue项目,vue全家桶,vue所学的所需要的.这一个资源就够了.经过检验,资源完整度和资源的质量得到保证.里面10+的vue资源,5+的vue项目.还有源码解析
  • mini-vue:模拟vue源码师承Mr Ma的项目
  • Vue源码浅析

    2021-04-19 10:43:47
    Vue源码浅析Vue.js 源码Vue.js 源码构建构建脚本构建过程Runtime Only VS Runtime + Compiler总结Vue源码入口Vue 的入口Vue 的定义`initGlobalAPI`总结 Vue.js 源码 Vue.js 的源码都在 src 目录下,其目录结构如下...

    Vue.js 源码

    • Vue.js 的源码都在 src 目录下,其目录结构如下。
    src
    ├── compiler        # 编译相关 
    ├── core            # 核心代码 
    ├── platforms       # 不同平台的支持
    ├── server          # 服务端渲染
    ├── sfc             # .vue 文件解析
    ├── shared          # 共享代码
    
    • compiler 目录包含 Vue.js 所有编译相关的代码。它包括把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能。编译的工作可以在构建时做(借助 webpack、vue-loader 等辅助插件);也可以在运行时做,使用包含构建功能的 Vue.js。显然,编译是一项耗性能的工作,所以更推荐前者——离线编译。

    • core 目录包含了 Vue.js 的核心代码,包括内置组件、全局 API 封装,Vue 实例化、观察者、虚拟 DOM、工具函数等等。这里的代码可谓是 Vue.js 的灵魂,也是我们之后需要重点分析的地方。

    • platform: Vue.js 是一个跨平台的 MVVM 框架,它可以跑在 web 上,也可以配合 weex 跑在 native 客户端上。platform 是 Vue.js 的入口,2 个目录代表 2 个主要入口,分别打包成运行在 web 上和 weex 上的 Vue.js。重点分析 web 入口打包后的 Vue.js,对于 weex 入口打包的 Vue.js,感兴趣可以自行研究。

    • server:Vue.js 2.0 支持了服务端渲染,所有服务端渲染相关的逻辑都在这个目录下。注意:这部分代码是跑在服务端的 Node.js,不要和跑在浏览器端的 Vue.js 混为一谈。服务端渲染主要的工作是把组件渲染为服务器端的 HTML 字符串,将它们直接发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序。

    • sfc:通常我们开发 Vue.js 都会借助 webpack 构建, 然后通过 .vue 单文件来编写组件。这个目录下的代码逻辑会把 .vue 文件内容解析成一个 JavaScript 的对象。

    • shared:Vue.js 会定义一些工具方法,这里定义的工具方法都是会被浏览器端的 Vue.js 和服务端的 Vue.js 所共享的。

    总结:
    从 Vue.js 的目录设计可以看到,作者把功能模块拆分的非常清楚,相关的逻辑放在一个独立的目录下维护,并且把复用的代码也抽成一个独立目录。

    这样的目录设计让代码的阅读性和可维护性都变强,是非常值得学习和推敲的

    Vue.js 源码构建

    Vue.js 源码是基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下。

    构建脚本

    通常一个基于 NPM 托管的项目都会有一个 package.json 文件,它是对项目的描述文件,它的内容实际上是一个标准的 JSON 对象。

    我们通常会配置 script 字段作为 NPM 的执行脚本,Vue.js 源码构建的脚本如下:

    {
      "script": {
        "build": "node scripts/build.js",
        "build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer",
        "build:weex": "npm run build -- weex"
      }
    }
     
    

    这里总共有 3 条命令,作用都是构建 Vue.js,后面 2 条是在第一条命令的基础上,添加一些环境参数。

    当在命令行运行 npm run build 的时候,实际上就会执行 node scripts/build.js,接下来我们来看看它实际是怎么构建的。

    构建过程

    我们对于构建过程分析是基于源码的,先打开构建的入口 JS 文件,在 scripts/build.js 中:

    let builds = require('./config').getAllBuilds()
    
    // filter builds via command line arg
    if (process.argv[2]) {
      const filters = process.argv[2].split(',')
      builds = builds.filter(b => {
        return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
      })
    } else {
      // filter out weex builds by default
      builds = builds.filter(b => {
        return b.output.file.indexOf('weex') === -1
      })
    }
    
    build(builds)
    

    这段代码逻辑非常简单,先从配置文件读取配置,再通过命令行参数对构建配置做过滤,这样就可以构建出不同用途的 Vue.js 了。接下来我们看一下配置文件,在 scripts/config.js 中:

    const builds = {
      // Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
      'web-runtime-cjs': {
        entry: resolve('web/entry-runtime.js'),
        dest: resolve('dist/vue.runtime.common.js'),
        format: 'cjs',
        banner
      },
      // Runtime+compiler CommonJS build (CommonJS)
      'web-full-cjs': {
        entry: resolve('web/entry-runtime-with-compiler.js'),
        dest: resolve('dist/vue.common.js'),
        format: 'cjs',
        alias: { he: './entity-decoder' },
        banner
      },
      // Runtime only (ES Modules). Used by bundlers that support ES Modules,
      // e.g. Rollup & Webpack 2
      'web-runtime-esm': {
        entry: resolve('web/entry-runtime.js'),
        dest: resolve('dist/vue.runtime.esm.js'),
        format: 'es',
        banner
      },
      // Runtime+compiler CommonJS build (ES Modules)
      'web-full-esm': {
        entry: resolve('web/entry-runtime-with-compiler.js'),
        dest: resolve('dist/vue.esm.js'),
        format: 'es',
        alias: { he: './entity-decoder' },
        banner
      },
      // runtime-only build (Browser)
      'web-runtime-dev': {
        entry: resolve('web/entry-runtime.js'),
        dest: resolve('dist/vue.runtime.js'),
        format: 'umd',
        env: 'development',
        banner
      },
      // runtime-only production build (Browser)
      'web-runtime-prod': {
        entry: resolve('web/entry-runtime.js'),
        dest: resolve('dist/vue.runtime.min.js'),
        format: 'umd',
        env: 'production',
        banner
      },
      // 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
      },
      // Runtime+compiler production build  (Browser)
      'web-full-prod': {
        entry: resolve('web/entry-runtime-with-compiler.js'),
        dest: resolve('dist/vue.min.js'),
        format: 'umd',
        env: 'production',
        alias: { he: './entity-decoder' },
        banner
      },
      // ...
    }
    

    这里列举了一些 Vue.js 构建的配置,关于还有一些服务端渲染 webpack 插件以及 weex 的打包配置就不列举了。

    对于单个配置,它是遵循 Rollup 的构建规则的。其中 entry 属性表示构建的入口 JS 文件地址,dest 属性表示构建后的 JS 文件地址。format 属性表示构建的格式,cjs 表示构建出来的文件遵循 CommonJS 规范,es 表示构建出来的文件遵循 ES Module 规范。 umd 表示构建出来的文件遵循 UMD 规范。

    web-runtime-cjs 配置为例,它的 entry
    resolve('web/entry-runtime.js'),先来看一下 resolve 函数的定义。

    源码目录:scripts/config.js

    const aliases = require('./alias')
    const resolve = p => {
      const base = p.split('/')[0]
      if (aliases[base]) {
        return path.resolve(aliases[base], p.slice(base.length + 1))
      } else {
        return path.resolve(__dirname, '../', p)
      }
    }
    

    这里的 resolve 函数实现非常简单,它先把 resolve 函数传入的参数 p 通过 / 做了分割成数组,然后取数组第一个元素设置为 base。在我们这个例子中,参数 pweb/entry-runtime.js,那么 base 则为 webbase 并不是实际的路径,它的真实路径借助了别名的配置,我们来看一下别名配置的代码,在 scripts/alias 中:

    const path = require('path')
    
    module.exports = {
      vue: path.resolve(__dirname, '../src/platforms/web/entry-runtime-with-compiler'),
      compiler: path.resolve(__dirname, '../src/compiler'),
      core: path.resolve(__dirname, '../src/core'),
      shared: path.resolve(__dirname, '../src/shared'),
      web: path.resolve(__dirname, '../src/platforms/web'),
      weex: path.resolve(__dirname, '../src/platforms/weex'),
      server: path.resolve(__dirname, '../src/server'),
      entries: path.resolve(__dirname, '../src/entries'),
      sfc: path.resolve(__dirname, '../src/sfc')
    }
    

    很显然,这里 web 对应的真实的路径是 path.resolve(__dirname, '../src/platforms/web'),这个路径就找到了 Vue.js 源码的 web 目录。然后 resolve 函数通过 path.resolve(aliases[base], p.slice(base.length + 1)) 找到了最终路径,它就是 Vue.js 源码 web 目录下的 entry-runtime.js。因此,web-runtime-cjs 配置对应的入口文件就找到了。

    它经过 Rollup 的构建打包后,最终会在 dist 目录下生成 vue.runtime.common.js

    Runtime Only VS Runtime + Compiler

    通常我们利用 vue-cli 去初始化我们的 Vue.js 项目的时候会询问我们用 Runtime Only 版本的还是 Runtime + Compiler 版本。下面我们来对比这两个版本。

    • Runtime Only

    我们在使用 Runtime Only 版本的 Vue.js 的时候,通常需要借助如 webpack 的 vue-loader 工具把 .vue 文件编译成 JavaScript,因为是在编译阶段做的,所以它只包含运行时的 Vue.js 代码,因此代码体积也会更轻量。

    • Runtime + Compiler

    我们如果没有对代码做预编译,但又使用了 Vue 的 template 属性并传入一个字符串,则需要在客户端编译模板,如下所示:

    // 需要编译器的版本
    new Vue({
      template: '<div>{{ hi }}</div>'
    })
    
    // 这种情况不需要
    new Vue({
      render (h) {
        return h('div', this.hi)
      }
    })
    

    因为在 Vue.js 2.0 中,最终渲染都是通过 render 函数,如果写 template 属性,则需要编译成 render 函数,那么这个编译过程会发生运行时,所以需要带有编译器的版本。

    很显然,这个编译过程对性能会有一定损耗,所以通常我们更推荐使用 Runtime-Only 的 Vue.js。

    总结

    通过这一节的分析,我们可以了解到 Vue.js 的构建打包过程,也知道了不同作用和功能的 Vue.js 它们对应的入口以及最终编译生成的 JS 文件。尽管在实际开发过程中我们会用 Runtime Only 版本开发比较多,但为了分析 Vue 的编译过程,我们这门课重点分析的源码是 Runtime + Compiler 的 Vue.js。

    Vue源码入口

    • 我们之前提到过 Vue.js 构建过程,在 web 应用下,我们来分析 Runtime + Compiler 构建出来的 Vue.js,它的入口是 src/platforms/web/entry-runtime-with-compiler.js:
    /* @flow */
    
    import config from 'core/config'
    import { warn, cached } from 'core/util/index'
    import { mark, measure } from 'core/util/perf'
    
    import Vue from './runtime/index'
    import { query } from './util/index'
    import { compileToFunctions } from './compiler/index'
    import { shouldDecodeNewlines, shouldDecodeNewlinesForHref } from './util/compat'
    
    const idToTemplate = cached(id => {
      const el = query(id)
      return el && el.innerHTML
    })
    
    const mount = Vue.prototype.$mount
    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
      el = el && query(el)
    
      /* istanbul ignore if */
      if (el === document.body || el === document.documentElement) {
        process.env.NODE_ENV !== 'production' && warn(
          `Do not mount Vue to <html> or <body> - mount to normal elements instead.`
        )
        return this
      }
    
      const options = this.$options
      // resolve template/el and convert to render function
      if (!options.render) {
        let template = options.template
        if (template) {
          if (typeof template === 'string') {
            if (template.charAt(0) === '#') {
              template = idToTemplate(template)
              /* istanbul ignore if */
              if (process.env.NODE_ENV !== 'production' && !template) {
                warn(
                  `Template element not found or is empty: ${options.template}`,
                  this
                )
              }
            }
          } else if (template.nodeType) {
            template = template.innerHTML
          } else {
            if (process.env.NODE_ENV !== 'production') {
              warn('invalid template option:' + template, this)
            }
            return this
          }
        } else if (el) {
          template = getOuterHTML(el)
        }
        if (template) {
          /* istanbul ignore if */
          if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
            mark('compile')
          }
    
          const { render, staticRenderFns } = compileToFunctions(template, {
            shouldDecodeNewlines,
            shouldDecodeNewlinesForHref,
            delimiters: options.delimiters,
            comments: options.comments
          }, this)
          options.render = render
          options.staticRenderFns = staticRenderFns
    
          /* istanbul ignore if */
          if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
            mark('compile end')
            measure(`vue ${this._name} compile`, 'compile', 'compile end')
          }
        }
      }
      return mount.call(this, el, hydrating)
    }
    
    /**
     * Get outerHTML of elements, taking care
     * of SVG elements in IE as well.
     */
    function getOuterHTML (el: Element): string {
      if (el.outerHTML) {
        return el.outerHTML
      } else {
        const container = document.createElement('div')
        container.appendChild(el.cloneNode(true))
        return container.innerHTML
      }
    }
    
    Vue.compile = compileToFunctions
    
    export default Vue
    
    

    那么,当我们的代码执行 import Vue from 'vue' 的时候,就是从这个入口执行代码来初始化 Vue,
    那么 Vue 到底是什么,它是怎么初始化的,我们来一探究竟。

    Vue 的入口

    在这个入口 JS 的上方我们可以找到 Vue 的来源:import Vue from './runtime/index',我们先来看一下这块儿的实现,它定义在 src/platforms/web/runtime/index.js 中:

    import Vue from 'core/index'
    import config from 'core/config'
    import { extend, noop } from 'shared/util'
    import { mountComponent } from 'core/instance/lifecycle'
    import { devtools, inBrowser, isChrome } from 'core/util/index'
    
    import {
      query,
      mustUseProp,
      isReservedTag,
      isReservedAttr,
      getTagNamespace,
      isUnknownElement
    } from 'web/util/index'
    
    import { patch } from './patch'
    import platformDirectives from './directives/index'
    import platformComponents from './components/index'
    
    // 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
    
    // public mount method
    Vue.prototype.$mount = function (
      el?: string | Element,
      hydrating?: boolean
    ): Component {
      el = el && inBrowser ? query(el) : undefined
      return mountComponent(this, el, hydrating)
    }
    
    // ...
    
    export default Vue
    
    

    这里关键的代码是 import Vue from 'core/index',之后的逻辑都是对 Vue 这个对象做一些扩展,可以先不用看,我们来看一下真正初始化 Vue 的地方,在 src/core/index.js 中:

    import Vue from './instance/index'
    import { initGlobalAPI } from './global-api/index'
    import { isServerRendering } from 'core/util/env'
    import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
    
    initGlobalAPI(Vue)
    
    Object.defineProperty(Vue.prototype, '$isServer', {
      get: isServerRendering
    })
    
    Object.defineProperty(Vue.prototype, '$ssrContext', {
      get () {
        /* istanbul ignore next */
        return this.$vnode && this.$vnode.ssrContext
      }
    })
    
    // expose FunctionalRenderContext for ssr runtime helper installation
    Object.defineProperty(Vue, 'FunctionalRenderContext', {
      value: FunctionalRenderContext
    })
    
    Vue.version = '__VERSION__'
    
    export default Vue
    

    这里有 2 处关键的代码,import Vue from './instance/index'initGlobalAPI(Vue),初始化全局 Vue API(我们稍后介绍),我们先来看第一部分,在 src/core/instance/index.js 中:

    Vue 的定义

    import { initMixin } from './init'
    import { stateMixin } from './state'
    import { renderMixin } from './render'
    import { eventsMixin } from './events'
    import { lifecycleMixin } from './lifecycle'
    import { warn } from '../util/index'
    
    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)
    }
    
    initMixin(Vue)
    stateMixin(Vue)
    eventsMixin(Vue)
    lifecycleMixin(Vue)
    renderMixin(Vue)
    
    export default Vue
    

    在这里,我们终于看到了 Vue 的庐山真面目,它实际上就是一个用 Function 实现的类,我们只能通过 new Vue 去实例化它。

    有些同学看到这不禁想问,为何 Vue 不用 ES6 的 Class 去实现呢?我们往后看这里有很多 xxxMixin的函数调用,并把 Vue 当参数传入,它们的功能都是给 Vue 的 prototype 上扩展一些方法(这里具体的细节会在之后的文章介绍,这里不展开),Vue 按功能把这些扩展分散到多个模块中去实现,而不是在一个模块里实现所有,这种方式是用 Class 难以实现的。这么做的好处是非常方便代码的维护和管理,这种编程技巧也非常值得我们去学习。

    initGlobalAPI

    Vue.js 在整个初始化过程中,除了给它的原型 prototype 上扩展方法,还会给 Vue 这个对象本身扩展全局的静态方法,它的定义在 src/core/global-api/index.js 中:

    export function initGlobalAPI (Vue: GlobalAPI) {
      // config
      const configDef = {}
      configDef.get = () => config
      if (process.env.NODE_ENV !== 'production') {
        configDef.set = () => {
          warn(
            'Do not replace the Vue.config object, set individual fields instead.'
          )
        }
      }
      Object.defineProperty(Vue, 'config', configDef)
    
      // exposed util methods.
      // NOTE: these are not considered part of the public API - avoid relying on
      // them unless you are aware of the risk.
      Vue.util = {
        warn,
        extend,
        mergeOptions,
        defineReactive
      }
    
      Vue.set = set
      Vue.delete = del
      Vue.nextTick = nextTick
    
      Vue.options = Object.create(null)
      ASSET_TYPES.forEach(type => {
        Vue.options[type + 's'] = Object.create(null)
      })
    
      // this is used to identify the "base" constructor to extend all plain-object
      // components with in Weex's multi-instance scenarios.
      Vue.options._base = Vue
    
      extend(Vue.options.components, builtInComponents)
    
      initUse(Vue)
      initMixin(Vue)
      initExtend(Vue)
      initAssetRegisters(Vue)
    }
    

    这里就是在 Vue 上扩展的一些全局方法的定义,Vue 官网中关于全局 API 都可以在这里找到,这里不会介绍细节,会在之后的章节我们具体介绍到某个 API 的时候会详细介绍。有一点要注意的是,Vue.util 暴露的方法最好不要依赖,因为它可能经常会发生变化,是不稳定的。

    总结

    那么至此,Vue 的初始化过程基本介绍完毕。这一节的目的是让同学们对 Vue 是什么有一个直观的认识,它本质上就是一个用 Function 实现的 Class,然后它的原型 prototype 以及它本身都扩展了一系列的方法和属性,那么 Vue 能做什么,它是怎么做的,我们会在后面的章节一层层帮大家揭开 Vue 的神秘面纱。

    展开全文
  • vue源码学习

    2019-11-18 16:31:24
    vue源码学习准备 vue源码阅读记录(一)
    展开全文
  • 浅析Vue源码

    2018-10-11 17:41:53
    浅析Vue源码(一)—— 造物创世 Vue解析--如何应对面试官提问 浅析Vue源码(二)—— initMixin(上) 浅析Vue源码(三)—— initMixin(下) 浅析Vue源码(四)—— $mount中template的编译--parse 浅析Vue源码...
  • read-vue-source-code:第一次阅读vue源码
  • 慕克生鲜 Vue源码

    2018-07-08 14:12:22
    Vue+Django REST framework 打造生鲜电商项目,慕克生鲜 Vue源码,分享给大家
  • Vue源码结构

    2019-10-14 16:13:27
    Vue源码结构

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 38,719
精华内容 15,487
关键字:

vue源码

vue 订阅