Vue编译器解析compile源码解析

目录
  • 引言
  • 解析 compile
    • compile 源码
    • 配置选项
    • 属性分别解析
    • finalOptions添加warn 方法
    • 两个特殊的属性处理

引言

在上篇文章 Vue编译器源码分析compileToFunctions作用中我们介绍到了,在 compileToFunctions 方法中:

// compile
var compiled = compile(template, options);

而真正的编译工作是依托于 compile 函数,接下来我们详细解析 compile 。

解析 compile

上述代码在调用 compile ,其中模板字符串 template ,选项参数 options 第二个参数传递给 compile 函数,在章节三种我们知道,这里传递过去的options如下:

{
	shouldDecodeNewlines,
	shouldDecodeNewlinesForHref,
	delimiters,
	comments,
	warn
}

compile 源码

接下来我们看下 compile 的源码。

function createCompilerCreator(baseCompile) {
	return function createCompiler(baseOptions) {
		function compile(
			template,
			options
		) {
			var finalOptions = Object.create(baseOptions);
			var errors = [];
			var tips = [];
			finalOptions.warn = function(msg, tip) {
				(tip ? tips : errors).push(msg);
			};
			if (options) {
				// merge custom modules
				if (options.modules) {
					finalOptions.modules =
						(baseOptions.modules || []).concat(options.modules);
				}
				// merge custom directives
				if (options.directives) {
					finalOptions.directives = extend(
						Object.create(baseOptions.directives || null),
						options.directives
					);
				}
				// copy other options
				for (var key in options) {
					if (key !== 'modules' && key !== 'directives') {
						finalOptions[key] = options[key];
					}
				}
			}
			var compiled = baseCompile(template, finalOptions); {
				errors.push.apply(errors, detectErrors(compiled.ast));
			}
			compiled.errors = errors;
			compiled.tips = tips;
			return compiled
		}
		return {
			compile: compile,
			compileToFunctions: createCompileToFunctionFn(compile)
		}
	}
}

·首先可以看到:

var finalOptions = Object.create(baseOptions);

配置选项

finalOptions 所有的配置选项最终都会挂载在这个对象上,baseOptions包含编译器在运作的时候所需的配置选项。

var baseOptions = {
	expectHTML: true,
	modules: modules$1,
	directives: directives$1,
	isPreTag: isPreTag,
	isUnaryTag: isUnaryTag,
	mustUseProp: mustUseProp,
	canBeLeftOpenTag: canBeLeftOpenTag,
	isReservedTag: isReservedTag,
	getTagNamespace: getTagNamespace,
	staticKeys: genStaticKeys(modules$1)
};

属性分别解析

  • 第一个属性: expectHTML 被设置为 true 。
  • 第二个属性:modules
var modules$1 = [
	klass$1,
	style$1,
	model$1
];
var klass$1 = {
	staticKeys: ['staticClass'],
	transformNode: transformNode,
	genData: genData
};
var style$1 = {
	staticKeys: ['staticStyle'],
	transformNode: transformNode$1,
	genData: genData$1
};
var model$1 = {
	preTransformNode: preTransformNode
};

我们用到了在细讲。

  • 第三个属性:directives 值是三个属性 (model、text、html) 的对象,且属性的值都是函数。
  • 第四个属性:isPreTag 它是一个函数,其作用是通过给定的标签名字检查标签是否是 'pre' 标签。
  • 第五个属性:isUnaryTag 是一个通过makeMap生成的函数,该函数的作用是检测给定的标签是否是一元标签。
  • 第六个属性:mustUseProp 它是一个函数,其作用是用来检测一个属性在标签中是否要使用props进行绑定。
  • 第七个属性:canBeLeftOpenTag 一个使用makeMap生成的函数,它的作用是检测非一元标签,但却可以自己补全并闭合的标签。比如 div 标签是一个双标签,你需要这样使用<div> text </div>,但是你依然可以省略闭合标签,直接这样写:<div> text ,且浏览器会自动补全。但是有些标签你不可以这样用,它们是严格的双标签。
  • 第八个属性:isReservedTag 它是一个函数,其作用是检查给定的标签是否是保留的标签。
  • 第九个属性:getTagNamespace 它也是一个函数,其作用是获取元素(标签)的命名空间。
  • 第十个属性:staticKeys 它的值是通过以 modules 为参数调用 genStaticKeys 函数的返回值得到的。 其作用是根据编译器选项的 modules 选项生成一个静态键字符串。

现在我们粗略的介绍了下baseOptions 中各个属性的作用,当我们用到时候再来详细讲解他们的源码。

继续往下看:

var errors = [];
var tips = [];
finalOptions.warn = function(msg, tip) {
	(tip ? tips : errors).push(msg);
};

很简单

finalOptions添加warn 方法

在 finalOptions上添加了 warn 方法,该方法接收两个参数:

  • msg 错误或提示的信息
  • tip 用来标示 msg 是错误还是提示。

warn选项主要用在编译过程中的错误和提示收集,如果收集的信息是错误信息就将错误信息添加到前面定义的errors数组里,如果是提示信息就将其添加到 tips 数组里。

继续:

if (options) {
	// merge custom modules
	if (options.modules) {
		finalOptions.modules =
			(baseOptions.modules || []).concat(options.modules);
	}
	// merge custom directives
	if (options.directives) {
		finalOptions.directives = extend(
			Object.create(baseOptions.directives || null),
			options.directives
		);
	}
	// copy other options
	for (var key in options) {
		if (key !== 'modules' && key !== 'directives') {
			finalOptions[key] = options[key];
		}
	}
}

这段代码检查 options 是否存在,这里的 options 就是使用编译器编译模板时传递的选项参数,或者可以简单理解为调用 compileToFunctions 函数时传递的选项参数。

而baseOptions理解为编译器的默认选项或者基本选项,options 是用来提供定制能力的扩展选项。而上面这段代码的作用,就是将 options 对象混合到 finalOptions 中。

两个特殊的属性处理

  • modules: 如果 options.modules 存在,就在 finalOptions 对象上添加 modules 属性,其值为 baseOptions.modules 和 options.modules 这两个数组合并后的新数组。
  • directives: 对于directives 采用原型链的原理实现扩展属性对基本属性的覆盖。

继续:

var compiled = baseCompile(template, finalOptions); {
	errors.push.apply(errors, detectErrors(compiled.ast));
}
compiled.errors = errors;
compiled.tips = tips;

上面的代码调用了 baseCompile 函数,并分别将字符串模板(template),以及最终的编译器选项(finalOptions)传递了过去。

compiled 是 baseCompile 对模板的编译结果所以上面这段代码的作用是用来通过抽象语法树来检查模板中是否存在错误表达式的,通过 detectErrors 函数实现,将compiled.ast 作为参数传递给 detectErrors 函数,该函数最终返回一个数组,该数组中包含了所有错误的收集,最终通过这句代码将错误添加到errors。

将收集到的错误(errors)和提示(tips)添加到compiled上并返回。

baseCompile 函数是在 createCompilerCreator 函数调用时传递的实参。

// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
var createCompiler = createCompilerCreator(function baseCompile(
	template,
	options
) {
	var ast = parse(template.trim(), options);
	if (options.optimize !== false) {
		optimize(ast, options);
	}
	var code = generate(ast, options);
	return {
		ast: ast,
		render: code.render,
		staticRenderFns: code.staticRenderFns
	}
});

从Vue编译器源码分析(一) 到 Vue编译器源码分析(四) 我们已经把编译器整体代码组织的结构讲分析了。

从下章节开始,就正式的进入到Vue编译器词法分析阶段,去看下模板对应的AST(抽象语法树)是怎么形成的。

Vue编译器源码AST 抽象语法树

以上就是Vue编译器解析compile源码解析的详细内容,更多关于Vue编译器compile解析的资料请关注我们其它相关文章!

(0)

相关推荐

  • vue原理Compile之optimize标记静态节点源码示例

    目录 引言 而 optimize 的作用是什么呢? 1 是否存在 v-pre 2 不能存在 node.hasBindings 3 不能存在 node.if 和 node.for 4 节点名称不能是slot 或者 component 5 isPlatformReservedTag(node.tag) 6 isDirectChildOfTemplateFor(node) 7 Object.keys(node).every(isStaticKey) 标记静态节点 1 isStatic 这个方法对 as

  • Vue 中的compile操作方法

    在 Vue 里,模板编译也是非常重要的一部分,里面也非常复杂,这次探究不会深入探究每一个细节,而是走一个全景概要,来吧,大家和我一起去一探究竟. 初体验 我们看了 Vue 的初始化函数就会知道,在最后一步,它进行了 vm.$mount(el) 的操作,而这个 $mount 在两个地方定义过,分别是在 entry-runtime-with-compiler.js(简称:eMount) 和 runtime/index.js(简称:rMount) 这两个文件里,那么这两个有什么区别呢? // entr

  • 详解如何解决Vue和vue-template-compiler版本之间的问题

    今天把远程仓库拉下项目,运行'npm run dev'时,报错 Module build failed: Error: Cannot find module 'vue-template-compiler' 报错原因:通常出现于一些依赖库的更新或者安装新的依赖库之后(可以认为npm update已经成为一种习惯),导致了vue和vue-template-compiler的版本不一致. 解决方案:统一vue和vue-template-compiler的版本 "vue": "2.3

  • 解决vue安装less报错Failed to compile with 1 errors的问题

    1.创建vue项目后安装less,执行 npm install less less-loader --save-dev 下载版本为:less-loader@6.1.0 , less@3.11.3,重启服务报错,报错信息如下: 2.报错原因 less 本版太高需要降低版本,执行代码 先移除之前版本: npm uninstall less-loader 下载指定版本: npm install less-loader@5.0.0 -D 3.重启代码就可以了,若还是报错可移除文件node_modules

  • vue原理Compile从新建实例到结束流程源码

    目录 引言 1 获取 template 模板 2 生成 render 3 保存 render createCompiler baseCompile createCompilerCreator 生成一个函数 compile 返回 compileToFunctions 和 compile 但是为什么分出一个 compileToFunctions 呢? 因为要做模板缓存!! createCompileToFunctionFn 他的缓存是怎么做的 理清思路 内部函数的作用是 引言 Compile 的内容

  • Vue编译器解析compile源码解析

    目录 引言 解析 compile compile 源码 配置选项 属性分别解析 finalOptions添加warn 方法 两个特殊的属性处理 引言 在上篇文章 Vue编译器源码分析compileToFunctions作用中我们介绍到了,在 compileToFunctions 方法中: // compile var compiled = compile(template, options); 而真正的编译工作是依托于 compile 函数,接下来我们详细解析 compile . 解析 comp

  • Vue中$nextTick实现源码解析

    目录 正文 先看一个简单的问题 内部实现 先看第一块: 再看第二块: 然后是第三块: 最后是第四块: 正文 先看一个简单的问题 <template> <div @click="handleClick" ref="div">{{ text }}</div </template> <script> export default { data() { return { text: 'old' } }, methods:

  • Vue3 AST解析器-源码解析

    目录 1.生成 AST 抽象语法树 2.创建 AST 的根节点 3.解析子节点 4.解析模板元素 Element 5.示例:模板元素解析 上一篇文章Vue3 编译流程-源码解析中,我们从 packges/vue/src/index.ts 的入口开始,了解了一个 Vue 对象的编译流程,在文中我们提到 baseCompile 函数在执行过程中会生成 AST 抽象语法树,毫无疑问这是很关键的一步,因为只有拿到生成的 AST 我们才能遍历 AST 的节点进行 transform 转换操作,比如解析 v

  • vue数据控制视图源码解析

    分析vue是如何实现数据改变更新视图的. 前记 三个月前看了vue源码来分析如何做到响应式数据的, 文章名字叫vue源码之响应式数据, 最后分析到, 数据变化后会调用Watcher的update()方法. 那么时隔三月让我们继续看看update()做了什么. (这三个月用react-native做了个项目, 也无心总结了, 因为好像太简单了). 本文叙事方式为树藤摸瓜, 顺着看源码的逻辑走一遍, 查看的vue的版本为2.5.2. 我fork了一份源码用来记录注释. 目的 明确调查方向才能直至目标

  • vue解析指令compile源码层面使用解析

    目录 概述 compile 测试代码 结果 延伸及重点讲解 1. 类数组对象 2. RegExp.$1 3. nodeType 概述 上篇文章我们已经介绍了Vue的响应式原理,并实现了对数据的监听,监听的目的是为了及时更新视图,所以这篇文章就来介绍下vue解析指令并初始化视图部分. compile 在Vue的构造函数中对根元素进行编译 class MVue { constructor (options) { // 保存options this.$options = options this.$d

  • vue parseHTML源码解析hars end comment钩子函数

    目录 引言 chars源码: parseText end 源码: 引言 接上文  parseHTML 函数源码解析(六) start钩子函数 接下来我们主要讲解当解析器遇到一个文本节点时会如何为文本节点创建元素描述对象,又会如何对文本节点做哪些特殊的处理. parseHTML(template, { chars: function(){ //... }, //... }) chars源码: chars: function chars(text) { if (!currentParent) { {

  • 详解vue mint-ui源码解析之loadmore组件

    本文介绍了vue mint-ui源码解析之loadmore组件,分享给大家,具体如下: 接入 官方接入文档mint-ui loadmore文档 接入使用Example html <div id="app"> <mt-loadmore :top-method="loadTop" :bottom-method="loadBottom" :bottom-all-loaded="allLoaded" :max-dis

  • vue loadmore 组件滑动加载更多源码解析

    上一篇讲到在项目中使用上拉加载更多组件,但是由于实际项目开发中由于需求变更或者说在webview中上拉加载有些机型在上拉时候会把webview也一起上拉导致上拉加载不灵敏等问题,我们有时候也会换成滑动到底部自动加载的功能. 既然都是加载更多,很多代码思想势必相似,主要区别在于上拉和滑动到底部这个操作上,所以,我们需要注意: 上拉加载是point指针touch触摸事件,现在因为是滑动加载,需要添加scroll事件去监听然后执行相应回调 上拉加载主要计算触摸滚动距离,滑动加载主要计算containe

  • vue 源码解析之虚拟Dom-render

    vue 源码解析 --虚拟Dom-render instance/index.js function Vue (options) { 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) } renderMixin

  • Vue源码解析之数组变异的实现

    力有不逮的对象 众所周知,在 Vue 中,直接修改对象属性的值无法触发响应式.当你直接修改了对象属性的值,你会发现,只有数据改了,但是页面内容并没有改变. 这是什么原因? 原因在于: Vue 的响应式系统是基于Object.defineProperty这个方法的,该方法可以监听对象中某个元素的获取或修改,经过了该方法处理的数据,我们称其为响应式数据.但是,该方法有一个很大的缺点,新增属性或者删除属性不会触发监听,举个栗子: var vm = new Vue({ data () { return

随机推荐