Git Product home page Git Product logo

vue-source's Introduction

Vue 源码阅读

react-router

目录

01-准备工作

阅读方式

这里推荐两种方式:

  • 按照commit-log来阅读 commit-log一般对应某一个版本的迭代。通过阅读每一次迭代的代码,可以更清晰的了解迭代原因,迭代优化项以及 Vue 的完整历史。这种阅读方式需要的时间比较多。

  • 按照 Vue 入口中各个模块来阅读 每个模块各司其职,可以从入口文件中找到相应模块位置,并各个阅读击破。这种方式耗时短一些。

两种方式都很好,因为这里时间不够充裕,所以使用第二种方式来阅读。

目录结构

图片源自《Vue.js 技术揭秘》

完整流程

图片源自网络

vue-source's People

Contributors

fightinghao avatar

Stargazers

Wang WenHua  avatar  avatar sihan avatar

Watchers

James Cloos avatar  avatar

vue-source's Issues

01-准备工作

本周主要熟悉 Vue 的源码架构、flowrollup、构建指令、入口等前备知识。文末有作者阅读源码时遇到的一些问题,欢迎解答和补充!

源码架构

|-vue
  |-.circleci     // ci 相关配置
  |-.github       // github 提交相关脚本
  |-benchmarks    // 测试基准相关文件
  |-dist          // 打包目录
  |-examples      // 测试用例
  |-flow          // 全局 flow 相关声明
  |-node_modules  // packages 打包的 npm 包
  |-scripts       // 构建脚本
  |-src
    |-compiler    // 编译相关
    |-core        // vue 核心
    |-platforms   // 平台相关
      |-web       // web
      |-weex      // weex
    |-server      // ssr 相关
    |-sfc         // .vue 文件解析
    |-shared      // 共用代码,比如 utils
  |-test          // 测试脚本,使用 ts 编写
  |-types         // 测试脚本的 ts 类型声明文件

flow

类似于 typescript,提供了静态类型检测功能

const vm: Component = this
export function initMixin (Vue: Class<Component>) {}
// @flow
function square(n: number): number {
  return n * n;
}

square('2'); // Error!

Vue 的 flow 相关类型声明配置都在根目录的 flow 文件夹下

rollup

简单的来说 rollup 是一个 JS 模块打包器,可以将小块代码编译成大块复杂的代码。现在已经有很多类库都在使用 rollup 进行打包了,比如:react, vue, preact, three.js, moment, d3 等。

rollup & webpack

  • rollup

    1. 打包 js 文件的时候如果发现无用变量,会将其删掉。
    2. 可以将你的 js 中的代码,编译成你想要的格式 (commonJS、ES6、UMD)
    3. rollup 所有资源放同一个地方,一次性加载, 利用 tree-shake 特性来剔除未使用的代码,减少冗余
    4. 适用于类库
  • webpack

    1. 静态资源导入(如 js、css、图片、字体等)
    2. 拆分代码、按需加载
    3. 拥有如此强大的功能,所以 webpack 在进行资源打包的时候,就会产生很多冗余的代码。
    4. 适用于复杂应用

Vue 的 rollup 相关构建配置都在 scripts 目录下,构建命令可以在 package.json文件中找到

Runtime Only & Runtime + Compiler 两种模式

  • Runtime Only 版本通常需要借助 webpack 的 vue-loader 工具把 .vue 文件编译成浏览器可识别的 JS 文件,这个过程是在编译阶段做的,所以只需要用到运行时的 vue 代码,相对来说体积更加轻量

  • Runtime + Compiler 版本没有对 .vue 文件进行预编译的操作,所以额外的编译器做编译工作,所以对于性能上有所损耗

在实际开发中,更推荐使用 Runtime Only 版本

Tree-Shaking

直译为——树摇,可以理解为通过工具"摇"我们的 JS 文件,将其中用不到的代码"摇"掉。

// 模块1  module1.js
export function a() {}
export function b() {}
export function c() {}
// 模块2  module12.js
import { a } from 'module1' // 只引入 module1 模块中的 a 函数

a() // 执行 a 函数
// rollup 经过 Tree-Shaking 打包后结果
function a() {} // 只打包 a 函数,b、c 函数被 shaking 掉
a()

构建指令

- dev: Runtime + compiler development build (Browser)
- dev:cjs: Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
- dev:esm: Runtime only ES modules build (for bundlers)
- dev:test: 测试所有对外暴露的特性、全局API、错误格式、debug信息是否符合预期
- dev:ssr: 服务端渲染相关
- dev:compiler: Web compiler (CommonJS)
- dev:weex: Weex runtime framework (CommonJS).
- dev:weex:factory: Weex runtime factory.
- dev:weex:compiler: Weex compiler (CommonJS). Used by Weex's Webpack loader.

- build: no more bb
- build:ssr: web Runtime + Web server renderer (CommonJS).
- build:weex: weex 相关的构建都会执行

- sauce: 浏览器兼容测试
- bench:ssr:

- release: lint + test + build + npm publish + git push
- release:note: generate release notes
- commit: check Commit message

入口

入口在 src/platforms 下,分为 web 和 weex 两种平台。以 web 为例,可以看到之前说的 Runtime Only & Runtime + Compiler 两种模式的入口文件:

  • entry-runtime-with-compiler.js
  • entry-runtime.js

两个文件入口中都引入了 import Vue from './runtime/index' Vue 的运行时部分,找到 ./runtime/index 这部分代码

import Vue from 'core/index' // vue 的核心
import config from 'core/config'

这部分代码引入了 vue 的核心

import Vue from './instance/index'

vue 核心引入了 instance 中的代码,揭晓了 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) { // vue 的构造函数
  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 本质就是一个构造函数,所以我们一般会使用 new Vue() 的方式来创建 vue 的实例。除此之外,Vue 其它功能模块由对应的 Mixin 来完成,这些 Minxin 把 Vue 当参数传入,然后在 Vue 的 prototype 上拓展功能,所以我们创建的 vue 实例可以直接调用一些 API。

问题汇总

  1. 如何理解「运行时」(Runtime only) ?

  2. Bench:ssr 的作用?

  3. 依赖部分没有 dependencies 只有 devDependencies

  4. commitizenscripts/verify-commit-msg.js 指令区别?

  5. 实时编译的性能瓶颈在哪?

  6. 为什么不使用 class Vue {} 的形式来实现?

问题解答

  1. Vue 有 Runtime + Compiler & Runtime Only 两种模式,分别对应打包后 dist 文件夹下的 vue.jsvue.runtime.js
    我们从 src/platforms/web 入口文件可以看到两种模式对应的入口:
|-web
  |-entry-runtime-with-compiler.js
  |-entry-runtime.js
  • entry-runtime-with-compiler.js 中额外引入了编译部分相关的代码,这部分代码最终会被 rollup 打包到 dist 目录的 vue.js 中,所以相对于 vue.runtime.js 来说体积更大。
  • Runtime Only 版本通常需要借助 vue-loader 工具把 .vue 文件编译成浏览器可识别的 JS 文件。例如将 template 转化为对应的 render 函数。这个过程是在离线编译阶段做好的,所以只需要用到运行时的 vue 代码。
  • Runtime + Compiler 版本没有对 .vue 文件进行预编译的操作,需要额外的编译器做编译工作。这个工作是在运行时动态做编译的,所以对于性能上有所损耗,更加推荐使用 runtime 版本。
  1. bench:ssr 主要对应根目录下的 benchmarks/ssr 文件夹,做一些 ssr 相关基准的测试工作,返回相应服务端模板字符串渲染的总耗时。

相关代码:

// renderToStream.js
stream.on('end', () => {
  complete = self.performance.now() - s
  console.log(`first chunk: ${first.toFixed(2)}ms`)
  console.log(`complete: ${complete.toFixed(2)}ms`)
  console.log()
})

// renderToString.js
renderToString(new Vue(gridComponent), (err, res) => {
  if (err) throw err
  // console.log(res)
  console.log('Complete time: ' + (self.performance.now() - self.s).toFixed(2) + 'ms')
  console.log()
})
  1. 问题待解决

  2. commitizen 以便捷的命令行提示,相对新手比较友好,方便提交代码。scripts/verify-commit-msg.js 无提示,直接做提交检测,相对第一种提交方式更加快捷,但需要一定的开发经验来支撑。

  3. 实时编译最终需要走到 new Vue(),vue 的实例相对复杂,私有属性、原型链属性生态庞大,所以开销很大,也是性能的一大瓶颈。

  4. 原因如下

  • 历史原因,vue 诞生时 class 写法不太成熟
  • function 写法性能更好
  • function 更方便模块管理,所有拓展功能模块可在 prototype 上拓展

参考

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.