1.1 Flow
Flow是facebook出品的JavaScript代码的静态类型检查器。
Vue.js 的源码利用了 Flow 做了静态类型检查。
Flow的工作方式:
类型推断:通过变量的使用上下文来推断,然后根据这些推断来判断类型。
类型注释:事先注释数据类型,Flow会基于注释来判断。
使用
// 类型推断
// @flow
function square(n) {
return n * n; // Error!
}
square("2");
//Flow 检查上述代码后会报错,因为函数期待的参数是数字,而我们输入了字符串
// 类型注释
// @flow
function square(n: number): number {
return n * n;
}
square("2"); // Error!
//添加类型注释,现在 Flow 就能检查出错误,因为函数参数的期待类型为数字,而我们提供了字符串。
1.2 Vue.js源码目录
Vue.js 的源码都在 src 目录下,其目录结构如下:
src
├── compiler # 编译相关
├── core # 核心代码
├── platforms # 不同平台的支持
├── server # 服务端渲染
├── sfc # .vue 文件解析
├── shared # 共享代码
compiler
compiler 目录包含 Vue.js 所有编译相关的代码。它包括把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能。
core
core 目录包含了 Vue.js 的核心代码,包括内置组件、全局 API 封装,Vue 实例化、观察者、虚拟 DOM、工具函数等等。
platforms
Vue.js 是一个跨平台的 MVVM 框架,它可以跑在 web 上,也可以配合 weex 跑在 native 客户端上。platform 是 Vue.js 的入口,2 个目录代表 2 个主要入口,分别打包成运行在 web 上和 weex 上的 Vue.js。
这里重点分析一下web入口打包后的Vue.js。
server
所有服务端渲染相关的逻辑都在这个目录下。
sfc
通常我们开发 Vue.js 都会借助 webpack 构建, 然后通过 .vue 单文件来编写组件。
这个目录下的代码逻辑会把 .vue 文件内容解析成一个 JavaScript 的对象。
shared
Vue.js定义的一些工具方法都放在这个目录下。
1.3 Vue.js构建方式
Vue.js 源码是是众多module(模块)基于 Rollup 构建的,它的构建相关配置都在 scripts 目录下。
在vue.js源码其实位置可以看到
"scripts": {
...
"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev",
...
}
我们从vue源码的scripts/config.js文件中找到 TARGET:web-full-dev
'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/entry-runtime-with-compiler.js”
1.4 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