Vue源码该如何入手?

前言

这是一个对Vue.js源码解析的系列,会持续更新,欢迎关注;话很少说,下面咱们就从怎么读Vue.js源码开始。html

一. 源码目录

首先咱们先看看Vue.js源码的项目结构:Vue.js源码GitHubvue

咱们先了解一下src这个目录的各模块分工:node

src
├── compiler        # 编译相关 
├── core            # 核心代码 
├── platforms       # 不一样平台的支持
├── server          # 服务端渲染
├── sfc             # .vue 文件解析
├── shared          # 共享代码
复制代码

1. compiler

compiler模块包含Vue.js了全部编译相关的代码。它包括把模板解析成AST语法树,AST语法树优化,代码生成等功能。webpack

2. core

core目录包含了Vue.js的核心代码,包括内置组件、全局 API 封装,Vue 实例化、观察者、虚拟 DOM、工具函数等。git

3. platform

Vue.js是一个跨平台的MVVM框架,它能够跑在 web上,也能够配合weex跑在native客户端上。platformVue.js的入口,会分别打包成运行在 web上和weex上的Vue.jsgithub

4. server

这是与服务端渲染相关的部分,这部分代码是跑在服务端的Node.jsweb

5. sfc

一般咱们开发Vue.js都会借助webpack构建,而后经过.vue单文件来编写组件,这个模块的功能就是将.vue文件内容解析成一个 JavaScript的对象。npm

6. shared

这里是Vue.js定义的一些共享工具方法,会供以上模块所共享。json

大概了解了以上模块功能后,咱们就知道了对于web端的源码,咱们主要分析的就是core模块。weex

二. 源码的构建入口

想一想日常咱们使用vue的时候是经过npm来安装使用的,那说明Vue.js其实就是一个 node包,但它是基于Rollup构建的,但咱们也能够用webpack的一些打包思路去理解它,若是对webpacknode包还不太了解的同窗能够看看我以前写的webpack4.x最详细入门讲解不会发布node包?进来看看

简单理解的话就是Vue.js经过构建工具将其打包,这个包会导出一个Vue构造函数供咱们使用。

因此咱们从Vue.js源码中的package.json文件入手,由于其包含了打包的一些配置记录,主要了解两个地方:

1. 导出口

"module": "dist/vue.runtime.esm.js"
复制代码

这个配置能够理解为出口或者入口,理解为出口时就是指它会导出一个Vue构造函数供咱们使用;理解为入口的话就从这个vue.runtime.esm.js开始集成Vue.js作须要的代码。

2. 打包入口

"scripts": {"build": "node scripts/build.js"}
复制代码

能够理解为打包入口,会经过build.js找到Vue.js所须要的依赖代码,而后对其进行打包,全部咱们能够从这里入手,去scripts/build.js路径下的build.js文件中看看:

// scripts/build.js 
let builds = require('./config').getAllBuilds()
...
build(builds)
复制代码
// 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
  },
  // ...
}

exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
复制代码

以上逻辑其实就是从配置文件config.js中读取配置,再对构建配置作过滤,进而根据不一样配置构建出不一样用途的Vue.js,其中就有web使用的两个版本:Runtime OnlyRuntime + Compiler

3. Runtime Only

在使用Runtime Only版本的Vue.js的时候,一般须要借助如webpackvue-loader工具把.vue文件编译成JavaScript,由于是在编译阶段作的,因此它只包含运行时的Vue.js代码,所以代码体积也会更轻量。

4. Runtime + Compiler

若是没有对代码作预编译,但又使用了Vuetemplate属性并传入一个字符串,则须要在客户端编译模板,因此须要带有编译器的版本,即Runtime + Compiler

由于后续系列咱们会将到编译模块,全部咱们就从带编译器的版本入手,即以上入口是entry: resolve('web/entry-runtime-with-compiler.js'),的文件,根据源码的路径解析咱们获得最终的文件路径是src/platforms/web/entry-runtime-with-compiler.js

// src/platforms/web/entry-runtime-with-compiler.js
import Vue from './runtime/index'
// ...
export default Vue
复制代码

能够看到这个文件不是定义Vue构造函数的地方,也是从其余文件引入,而后再加工导出,那咱们从./runtime/index这个文件继续找:

// src/platforms/web/runtime/index
import Vue from 'core/index'
// ...
export default Vue
复制代码

依旧如此……,继续往上找,最终通过几回查找,在src/core/instance/index.js中能够看到Vue的真身:

// src/core/instance/index.js
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) {
  // 判断是不是开发环境且必须是new调用
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  // new一个实例时会调用_init方法,该方法在下面的initMixin(Vue)中有定义
  this._init(options)
}

initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue
复制代码

因此到此咱们终于看到了Vue的庐山真面目,能够看到Vue是一个构造函数,且通过了一系列的Mixin,进而在Vue的原型上拓展方法。

最后

经过以上梳理,咱们大概了解到了咱们平时使用的Vue是怎么来的,后续系列会继续对源码进行梳理,若是对你的有帮助的话欢迎来波关注!

相关参考:Vue.js源码全方位深刻解析

相关文章
相关标签/搜索