这里推荐两种方式:
-
按照
commit-log
来阅读commit-log
一般对应某一个版本的迭代。通过阅读每一次迭代的代码,可以更清晰的了解迭代原因,迭代优化项以及 Vue 的完整历史。这种阅读方式需要的时间比较多。 -
按照 Vue 入口中各个模块来阅读 每个模块各司其职,可以从入口文件中找到相应模块位置,并各个阅读击破。这种方式耗时短一些。
两种方式都很好,因为这里时间不够充裕,所以使用第二种方式来阅读。
Vue 源码阅读:green_book:
这里推荐两种方式:
按照commit-log
来阅读
commit-log
一般对应某一个版本的迭代。通过阅读每一次迭代的代码,可以更清晰的了解迭代原因,迭代优化项以及 Vue 的完整历史。这种阅读方式需要的时间比较多。
按照 Vue 入口中各个模块来阅读 每个模块各司其职,可以从入口文件中找到相应模块位置,并各个阅读击破。这种方式耗时短一些。
两种方式都很好,因为这里时间不够充裕,所以使用第二种方式来阅读。
本周主要熟悉
Vue
的源码架构、flow
、rollup
、构建指令、入口等前备知识。文末有作者阅读源码时遇到的一些问题,欢迎解答和补充!
|-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 类型声明文件
类似于 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 是一个 JS 模块打包器,可以将小块代码编译成大块复杂的代码。现在已经有很多类库都在使用 rollup 进行打包了,比如:react, vue, preact, three.js, moment, d3 等。
rollup & webpack
rollup
webpack
Vue 的 rollup 相关构建配置都在 scripts 目录下,构建命令可以在 package.json
文件中找到
Runtime Only & Runtime + Compiler 两种模式
Runtime Only 版本通常需要借助 webpack 的 vue-loader 工具把 .vue 文件编译成浏览器可识别的 JS 文件,这个过程是在编译阶段做的,所以只需要用到运行时的 vue 代码,相对来说体积更加轻量
Runtime + Compiler 版本没有对 .vue 文件进行预编译的操作,所以额外的编译器做编译工作,所以对于性能上有所损耗
在实际开发中,更推荐使用 Runtime Only 版本
直译为——树摇,可以理解为通过工具"摇"我们的 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 两种模式的入口文件:
两个文件入口中都引入了 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。
如何理解「运行时」(Runtime only) ?
Bench:ssr
的作用?
依赖部分没有 dependencies
只有 devDependencies
?
commitizen
和 scripts/verify-commit-msg.js
指令区别?
实时编译的性能瓶颈在哪?
为什么不使用 class Vue {}
的形式来实现?
Runtime + Compiler
& Runtime Only
两种模式,分别对应打包后 dist
文件夹下的 vue.js
和 vue.runtime.js
。src/platforms/web
入口文件可以看到两种模式对应的入口:|-web
|-entry-runtime-with-compiler.js
|-entry-runtime.js
rollup
打包到 dist
目录的 vue.js
中,所以相对于 vue.runtime.js
来说体积更大。vue-loader
工具把 .vue
文件编译成浏览器可识别的 JS
文件。例如将 template
转化为对应的 render
函数。这个过程是在离线编译阶段做好的,所以只需要用到运行时的 vue
代码。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()
})
问题待解决
commitizen
以便捷的命令行提示,相对新手比较友好,方便提交代码。scripts/verify-commit-msg.js
无提示,直接做提交检测,相对第一种提交方式更加快捷,但需要一定的开发经验来支撑。
实时编译最终需要走到 new Vue()
,vue 的实例相对复杂,私有属性、原型链属性生态庞大,所以开销很大,也是性能的一大瓶颈。
原因如下
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.