├── assets └── vue-overview-2.jpeg ├── readme-en.md ├── readme.md ├── .gitignore ├── basic-concept.md └── template-parse.md /assets/vue-overview-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/defcc/into-vue/HEAD/assets/vue-overview-2.jpeg -------------------------------------------------------------------------------- /readme-en.md: -------------------------------------------------------------------------------- 1 | ## Into Vue.js 2 | 3 | 这个系列文章将会带你走入 Vue.js 2.0 的世界,预计将会每周日更新一篇。 4 | 你会看到 Vue.js 的使用,以及 Vue.js 的核心实现分析。 5 | 6 | ## 囊括的内容 7 | 8 | 1. [基本概念](./basic-concept.md) 9 | 2. 编译期和运行期 10 | 3. 依赖收集和响应式实现 11 | 4. 渲染函数和 UI 渲染机制 12 | 5. virtual dom 13 | 6. 服务器端渲染的实现 14 | 7. 平台独立性 15 | 8. 自定义插件 16 | 9. 动画 -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## Into Vue.js 2 | 3 | 这个系列文章将会带你走入 Vue.js 2.0 的世界,预计将会每周日更新一篇。 4 | 你会看到 Vue.js 的使用,以及 Vue.js 的核心实现分析。 5 | 6 | ## 囊括的内容 7 | 8 | 1. [基本概念](./basic-concept.md) 9 | 2. 编译期 10 | 1. [模版解析](./template-parse.md) 11 | 2. ast 优化 12 | 3. 渲染函数代码生成 13 | 3. 依赖收集和响应式实现 14 | 4. 渲染函数和 UI 渲染机制 15 | 5. virtual dom 16 | 6. 服务器端渲染的实现 17 | 7. 平台独立性 18 | 8. 自定义插件 19 | 9. 动画 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | -------------------------------------------------------------------------------- /basic-concept.md: -------------------------------------------------------------------------------- 1 | ## Vue.js 2.0 basic concepts 2 | 3 | 下面这张图从宏观上展现了 Vue.js 2.0 整体流程图 4 | 5 | ![vue-overview-2.jpeg](assets/vue-overview-2.jpeg) 6 | 7 | 从这张图中,我们可以初步看到一个 Vue.js 的应用是如何运行起来的,模版通过编译生成 ast,再由 ast 生成 Vue.js 的渲染函数,渲染函数结合数据生成 virtual dom tree,diff 和 patch 后生成新的 UI。 8 | 9 | 下面分别表述一些关于 Vue.js 的基本概念。 10 | 11 | ### 模版 12 | Vue.js 的模版基于纯 html,基于 Vue 的模版语法,我们可以比较方便地声明数据和 UI 的关系。 13 | 14 | ### AST (Abstract syntax tree) 15 | AST 是抽象语法树的简称,Vue.js 使用 html parser 将 html 模版解析为 ast,并且对 ast 进行一些优化的标记处理,提取最大的静态树,方便 virtual dom 时直接跳过 diff. 16 | 17 | ### 渲染函数 18 | 渲染函数是用来生成 virtual dom 的。Vue.js 推荐使用模版来构建我们的应用界面,在底层实现中 Vue 会将模版编译成渲染函数,当然我们也可以不写模版,直接写渲染函数,以获得更好的控制。 19 | 20 | ### Virtual dom 21 | 虚拟 dom 树,Vue.js 的 virtual dom patching 算法是基于 https://github.com/paldepind/snabbdom 的实现,并在此基础上作了很多的调整和改进。 22 | 23 | ### Watcher 24 | 每一个 Vue.js 组件都有一个对应的 watcher,这个 watcher 将会在组件 render 的时候收集组件所依赖的数据,并在依赖有更新的时候,触发组件重新渲染。你根本不需要写 shouldComponentUpdate,Vue.js 会自动优化并更新需要更新的 UI。 25 | 26 | ---- 27 | 28 | Render function 可以作为一道分割线,Render function 的左边可以称之为编译期,将 Vue.js 的模版转换为渲染函数。Vue.js 2.0 对于 jsx 语法的支持即是通过 babel 插件编译实现。Render function 的右边是 Vue.js 的运行时,主要是基于渲染函数生成 virtual dom 树,diff & patch。 29 | 30 | 下面一篇我们将会详细介绍 Vue.js 的编译期,通过 parser 对模版进行解析生成 ast。 31 | -------------------------------------------------------------------------------- /template-parse.md: -------------------------------------------------------------------------------- 1 | ## Vue.js 模版解析过程分析 2 | 3 | ### 模版和解析说明 4 | 5 | 先来看一段 Vue.js 的模版 6 | 7 | ```html 8 |
9 |

10 | hello 11 |
12 | ``` 13 | 14 | Vue.js 对于 HTML 模版的解析基于 http://ejohn.org/files/htmlparser.js ,并在其之上做了一些精简和调整。Vue 基于此进行 HTML 字符串解析得到节点对象,并对节点的属性进行分析,生成想要的 AST。 15 | 16 | 本文将会从两个方面进行说明,纯 HTML 字符串解析 以及 Vue.js 的 AST 的生成。 17 | 18 | ### 纯 HTML 解析 19 | 20 | HTML 节点有 tagName,attributeList 等,一个基本的 HTML 解析器需要分析出 HTML 节点信息,最终产出一个节点树。通常为了更好的控制解析过程,会基于状态机机制进行分析。 21 | 22 | HTMLParser 中提供了三个接口: 23 | 24 | 1. option.start,在解析到新的节点时调用,包括节点 tagName, attributes 等信息 25 | 2. option.end 在节点解析结束时调用,包括节点 tagName 等信息 26 | 3. option.chars 在文本解析完成时调用,包括文本自身 27 | 28 | 拿 `123` 来说 29 | 30 | 1. 当解析到 时,会调用 start 31 | 32 | `option.start('span', [{name: 'v-show', value: 'true'}])` 33 | 34 | 2. 当解析到 123 时,会调用 chars 方法 35 | 36 | `option.chars('123')` 37 | 38 | 3. 当解析到 时,会调用 end 方法 39 | 40 | `option.end('span')` 41 | 42 | 其中有一些细节需要在解析时注意 43 | 44 | 1. 一些标签不需要手动闭合,比如 p,td,th 等。对于这些标签,如果出现了形如 `

123

` ,需要闭合第一个 p 标签。 45 | 2. 一些标签不能出现在 p 中,比如 div li 等块级标签。对于这些标签,如果出现了形如 `

123

`,需要闭合第一个 p 标签。 46 | 47 | 事实上,我们可以实现一个更严格更语义化的解析器,比如 table 里只允许有 tbody,tr 等子元素,tr 里只允许有 th,td 等字元素。只是处于代码体积方面考虑,Vue.js 目前的解析没有这么严格。 48 | 49 | HTMLParser 在解析模版的过程中,将节点信息通过 start, end 和 chars 三个方法传递给 Vue.js 的 ast 构建程序,边解析边同时构建模版的 ast。 50 | 51 | ### AST 生成 52 | 53 | 拿到模版基本节点信息后,Vue.js 将对其进行模版语法的解析,比如 if 分支,for 循环,插值表达式,slot 等,处理为 AST 节点,最终生成一个完整的 AST 树 54 | 55 | 模版的 AST 节点有 3 种类型 ASTElement,ASTText 和 ASTExpression,可以在 flow 目录的 [compiler.js](https://github.com/vuejs/vue/blob/dev/flow/compiler.js#L63) 看到节点定义信息。 56 | 57 | 1. ASTElement 基于 option.start 调用时的 tag 节点信息所创建。 58 | 2. ASTText 和 ASTExpression 两种节点是在 option.char 时创建,ASTText 即为纯文本节点,ASTExpression 包含了插值表达式。 59 | 模版语法层面的解析包含了基本语法解析,如 pre,v-for,v-if,v-else-fi,v-else,v-once,key, ref, is,以及 v-bind,v-on 和 自定义 directive 的处理。具体解析代码在 [https://github.com/vuejs/vue/blob/dev/src/compiler/parser/index.js](https://github.com/vuejs/vue/blob/dev/src/compiler/parser/index.js) 60 | 61 | 为方便扩展,Vue.js 为模版语法的解析过程提供了三个接口 preTransformNode、transformNode、postTransformNode。 62 | 63 | 1. preTransformNode,在建立 ASTElement 基本信息后,进行节点的信息转换处理 64 | 2. transformNode,方便各个平台无关性模块扩展,在处理完 Vue.js 内置的基本语法解析后调用,如 class 模块和 style 模块即在这个阶段处理分析完成。而 web platform 和 weex platform 对这两个模块的定义是不一样的,基于 transformNode 的机制变可以很好的实现核心的可扩展性。 65 | 3. postTransformNode,即在节点解析完后调用 66 | 67 | 其中 preTransformNode 和 postTransformNode 只是预留了这两个接口,目前在 Vue.js 的核心中还没使用到。 68 | 69 | 至此即得到了对应于 HTML 模版的 AST 树,下一篇将会介绍基于 AST 树的优化。 70 | 71 | ================== 72 | 73 | #### 附录补充,关于 ast 和解析相关的一些资料: 74 | 75 | 1. [ast 介绍](https://en.wikipedia.org/wiki/Abstract_syntax_tree) 76 | 2. [estree](https://link.zhihu.com/?target=https%3A//github.com/estree/estree) 77 | 3. [esprima pasring demo](https://link.zhihu.com/?target=http%3A//esprima.org/demo/parse.html) 78 | 4. [top down operator precedence](https://link.zhihu.com/?target=http%3A//javascript.crockford.com/tdop/tdop.html) 79 | --------------------------------------------------------------------------------