iis服务器助手广告广告
返回顶部
首页 > 资讯 > 前端开发 > VUE >Vue编译器源码分析compileToFunctions作用详解
  • 351
分享到

Vue编译器源码分析compileToFunctions作用详解

2024-04-02 19:04:59 351人浏览 泡泡鱼
摘要

目录引言Vue.prototype.$mount函数体shouldDecodeNewlinesoptions.delimiters & options.commentscom

目录
  • 引言
    • Vue.prototype.$mount函数体
    • shouldDecodeNewlines
    • options.delimiters & options.comments
    • compileToFunctions函数逐行分析
    • createFunction 函数源码

引言

接上篇Vue编译器源码分析文章我们来分析:compileToFunctions的作用。

经过前面的讲解,我们已经知道了 compileToFunctions 的真正来源你可能会问为什么要弄的这么复杂?为了搞清楚这个问题,我们还需要继续接触完整的代码。

下面我们继续探索compileToFunctions是如何把模板字符串template编译成渲染函数render的。

Vue.prototype.$mount函数体

回归到Vue.prototype.$mount函数体内。

var ref = compileToFunctions(template, {
	shouldDecodeNewlines: shouldDecodeNewlines,
	shouldDecodeNewlinesForHref: shouldDecodeNewlinesForHref,
	delimiters: options.delimiters,
	comments: options.comments
}, this);

在此传递给compileToFunctions的第一个参数就是模板字符串template,而第二个参数则是一个配置选项options。

先说说这些配置选项中的属性!

shouldDecodeNewlines

源码出处

// check whether current browser encodes a char inside attribute values
var div;
function getShouldDecode(href) {
	div = div || document.createElement('div');
	div.innerhtml = href ? "<a href=\"\n\"/>" : "<div a=\"\n\"/>";
	return div.innerHTML.indexOf('&#10;') > 0
}
// #3663: IE encodes newlines inside attribute values while other browsers don't
var shouldDecodeNewlines = inBrowser ? getShouldDecode(false) : false;
// #6828: chrome encodes content in a[href]
var shouldDecodeNewlinesForHref = inBrowser ? getShouldDecode(true) : false;

这个是什么意思呢?

大致的翻译下,在我们innerHTML获取内容时,换行符和制表符分别被转换成了&#10和&#9。在IE中,不仅仅是 a 标签的 href 属性值,任何属性值都存在这个问题。

这就会影响Vue的编译器在对模板进行编译后的结果,为了避免这些问题Vue需要知道什么时候要做兼容工作,如果 shouldDecodeNewlines 为 true,意味着 Vue 在编译模板的时候,要对属性值中的换行符或制表符做兼容处理。而shouldDecodeNewlinesForHref为true 意味着Vue在编译模板的时候,要对a标签的 href 属性值中的换行符或制表符做兼容处理。

options.delimiters & options.comments

两者都是当前Vue实例的$options属性,并且delimiters和comments都是 Vue 提供的选项。

现在我们已经搞清楚了这些配置选项是什么意思,那接下来我们把目光放在《Vue编译器源码分析(二)》针对compileToFunctions函数逐行分析。

compileToFunctions函数逐行分析

function createCompileToFunctionFn(compile) {
	var cache = Object.create(null);
	return function compileToFunctions(
		template,
		options,
		vm
	) {
		options = extend({}, options);
		var warn$$1 = options.warn || warn;
		delete options.warn;
		
		{
			// detect possible CSP restriction
			try {
				new Function('return 1');
			} catch (e) {
				if (e.toString().match(/unsafe-eval|CSP/)) {
					warn$$1(
						'It seems you are using the standalone build of vue.js in an ' +
						'environment with Content Security Policy that prohibits unsafe-eval. ' +
						'The template compiler cannot work in this environment. Consider ' +
						'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
						'templates into render functions.'
					);
				}
			}
		}
		// check cache
		var key = options.delimiters ?
			String(options.delimiters) + template :
			template;
		if (cache[key]) {
			return cache[key]
		}
		// compile
		var compiled = compile(template, options);
		// check compilation errors/tips
		{
			if (compiled.errors && compiled.errors.length) {
				warn$$1(
					"Error compiling template:\n\n" + template + "\n\n" +
					compiled.errors.map(function(e) {
						return ("- " + e);
					}).join('\n') + '\n',
					vm
				);
			}
			if (compiled.tips && compiled.tips.length) {
				compiled.tips.forEach(function(msg) {
					return tip(msg, vm);
				});
			}
		}
		// turn code into functions
		var res = {};
		var fnGenErrors = [];
		res.render = createFunction(compiled.render, fnGenErrors);
		res.staticRenderFns = compiled.staticRenderFns.map(function(code) {
			return createFunction(code, fnGenErrors)
		});
		// check function generation errors.
		// this should only happen if there is a bug in the compiler itself.
		// mostly for codegen development use
		
		{
			if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
				warn$$1(
					"Failed to generate render function:\n\n" +
					fnGenErrors.map(function(ref) {
						var err = ref.err;
						var code = ref.code;
						return ((err.toString()) + " in\n\n" + code + "\n");
					}).join('\n'),
					vm
				);
			}
		}
		return (cache[key] = res)
	}
}

注意compileToFunctions函数是接收三个参数的,第三个参数是当前Vue实例。

首先:

options = extend({}, options);
var warn$$1 = options.warn || warn;
delete options.warn;

通过extend 把 options 配置对象上的属性扩展一份到新对象上,定义warn$$1变量。warn是一个错误信息提示的函数。

接下来:

// detect possible CSP restriction
try {
	new Function('return 1');
} catch (e) {
	if (e.toString().match(/unsafe-eval|CSP/)) {
		warn$$1(
			'It seems you are using the standalone build of Vue.js in an ' +
			'environment with Content Security Policy that prohibits unsafe-eval. ' +
			'The template compiler cannot work in this environment. Consider ' +
			'relaxing the policy to allow unsafe-eval or pre-compiling your ' +
			'templates into render functions.'
		);
	}
}

这段代码使用 try catch 语句块对 new Function('return 1') 这句代码进行错误捕获,如果有错误发生且错误的内容中包含如 'unsafe-eval' 或者 'CSP' 这些字样的信息时就会给出一个警告。

CSP全称Content Security Policy ,可以直接翻译为内容安全策略,说白了,就是为了页面内容安全而制定的一系列防护策略. 通过CSP所约束的的规责指定可信的内容来源(这里的内容可以指脚本、图片、iframe、fton、style等等可能的远程的资源)。通过CSP协定,让WEB处于一个安全的运行环境中。

如果你的策略比较严格,那么 new Function() 将会受到影响,从而不能够使用。但是将模板字符串编译成渲染函数又依赖 new Function(),所以解决方案有两个:

  • 1、放宽你的CSP策略
  • 2、预编译

这段代码的作用就是检测 new Function() 是否可用,并在某些极端情况下给你一个有用的提示。

接下来是:

var key = options.delimiters ?
	String(options.delimiters) + template :
	template;
if (cache[key]) {
	return cache[key]
}

options.delimiters这个选项是改变纯文本插入分隔符,如果options.delimiters存在,则使用String 方法将其转换成字符串并与 template 拼接作为 key 的值,否则直接使用 template 字符串作为 key 的值,然后判断 cache[key] 是否存在,如果存在直接返回cache[key]。

这么做的目的是缓存字符串模板的编译结果,防止重复编译,提升性能,我们再看一下compileToFunctions函数的最后一句代码:

return (cache[key] = res)

这句代码在返回编译结果的同时,将结果缓存,这样下一次发现如果 cache 中存在相同的 key则不需要再次编译,直接使用缓存的结果就可以了。

接下来:

// compile
var compiled = compile(template, options);
// check compilation errors/tips
if (compiled.errors && compiled.errors.length) {
	warn$$1(
		"Error compiling template:\n\n" + template + "\n\n" +
		compiled.errors.map(function(e) {
			return ("- " + e);
		}).join('\n') + '\n',
		vm
	);
   }
if (compiled.tips && compiled.tips.length) {
	compiled.tips.forEach(function(msg) {
		return tip(msg, vm);
	});
   }
}

compile 是引用了来自 createCompileToFunctionFn 函数的形参稍后会重点来介绍它。

在使用 compile 函数对模板进行编译后会返回一个结果 compiled,返回结果 compiled 是一个对象且这个对象可能包含两个属性 errors 和 tips 。这两个属性分别包含了编译过程中的错误和提示信息。所以上面那段代码的作用就是用来检查使用 compile 对模板进行编译的过程中是否存在错误和提示的,如果存在那么需要将其打印出来。

接下来:

// turn code into functions
var res = {};
var fnGenErrors = [];
res.render = createFunction(compiled.render, fnGenErrors);
res.staticRenderFns = compiled.staticRenderFns.map(function(code) {
	return createFunction(code, fnGenErrors)
});

res 是一个空对象且它是最终的返回值,fnGenErrors 是一个空数组

在 res 对象上添加一个 render 属性,这个 render 属性,就是最终生成的渲染函数,它的值是通过 createFunction 创建出来的。

createFunction 函数源码

function createFunction(code, errors) {
	try {
		return new Function(code)
	} catch (err) {
		errors.push({
			err: err,
			code: code
		});
		return noop
	}
}

createFunction 函数接收两个参数,第一个参数 code 为函数体字符串,该字符串将通过new Function(code) 的方式创建为函数。

第二个参数 errors 是一个数组,作用是当采用 new Function(code) 创建函数发生错误时用来收集错误的。

已知,传递给 createFunction 函数的第一个参数是 compiled.render,所以 compiled.render 应该是一个函数体字符串,且我们知道 compiled 是 compile 函数的返回值,这说明:compile函数编译模板字符串后所得到的是字符串形式的函数体。

传递给 createFunction 函数的第二个参数是之前声明的 fnGenErrors 常量,也就是说当创建函数出错时的错误信息被 push 到这个数组里了。

在这句代码之后,又在 res 对象上添加了 staticRenderFns 属性:

res.staticRenderFns = compiled.staticRenderFns.map(function(code) {
	return createFunction(code, fnGenErrors)
});

由这段代码可知 res.staticRenderFns 是一个函数数组,是通过对compiled.staticRenderFns遍历生成的,这说明:compiled 除了包含 render 字符串外,还包含一个字符串数组staticRenderFns ,且这个字符串数组最终也通过 createFunction 转为函数。staticRenderFns 的主要作用是渲染优化,我们后面详细讲解。

最后的代码:

// check function generation errors.
// this should only happen if there is a bug in the compiler itself.
// mostly for codegen development use

if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
	warn$$1(
		"Failed to generate render function:\n\n" +
		fnGenErrors.map(function(ref) {
			var err = ref.err;
			var code = ref.code;
			return ((err.toString()) + " in\n\n" + code + "\n");
		}).join('\n'),
		vm
	);
}
return (cache[key] = res)

这段代码主要的作用是用来打印在生成渲染函数过程中的错误,返回结果的同时将结果缓存,接下来我们讲讲compile 的作用。

Vue编译器源码分析之compile解析

以上就是Vue编译器源码分析compileToFunctions作用详解的详细内容,更多关于Vue编译器compileToFunctions的资料请关注编程网其它相关文章!

--结束END--

本文标题: Vue编译器源码分析compileToFunctions作用详解

本文链接: https://www.lsjlt.com/news/34281.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Vue编译器optimize源码分析
    目录引言optimize 源码之旅markStatic$1源码isStatic源码复杂点的回归到markStatic$1markStaticRoots 源码引言 接上文 p...
    99+
    2024-04-02
  • Vue编译器分析compile源码
    这篇文章主要介绍“Vue编译器分析compile源码”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Vue编译器分析compile源码”文章能帮助大家解决问题。引言在 compileToFunctio...
    99+
    2023-07-02
  • Vue3 编译流程-源码解析
    前言: Vue3 发布已经很长一段时间了,最近也有机会在公司项目中用上了 Vue3 + TypeScript + Vite 的技术栈,所以闲暇之余抽空也在抽空阅读 Vue3 的源码。...
    99+
    2024-04-02
  • 使用idea+gradle编译spring5.x.x源码分析
    目录一、编译环境二、安装gradle1、下载2、配置2.1、gradle下载后不需要安装,直接解压到磁盘2.2、配置gradle环境变量2.3、配置gradle默认的本地仓库2.4、...
    99+
    2024-04-02
  • 详解Windows下源码编译PaddlePaddle
    目录1.环境准备1.1 cmake1.2 python1.3 cuda1.4 python包1.5 创建编译文件夹1.6 启用visual studio终端1.7 开始编译1.8 d...
    99+
    2023-05-14
    Windows下源码编译PaddlePaddle Windows PaddlePaddle
  • 编译.NET Core 源码的示例分析
    小编给大家分享一下编译.NET Core 源码的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!一:Windows 编译VS 2019 16.6(不要安装预览版)Win 10 专业版,最新版本 (1903/2004)...
    99+
    2023-06-14
  • 【投屏】Scrcpy源码分析一(编译篇)
    Scrcpy源码分析系列 【投屏】Scrcpy源码分析一(编译篇) 【投屏】Scrcpy源码分析二(Client篇-连接阶段) 【投屏】Scrcpy源码分析三(Client篇-投屏阶段) 【投屏】Sc...
    99+
    2023-09-13
    android 音视频
  • Vue源码分析之虚拟DOM详解
    为什么需要虚拟dom? 虚拟DOM就是为了解决浏览器性能问题而被设计出来的。例如,若一次操作中有10次更新DOM的动作,虚拟DOM不会立即操作DOM,而是将这10次更新的diff内...
    99+
    2024-04-02
  • Nginx源码编译安装的示例分析
    这篇文章将为大家详细讲解有关Nginx源码编译安装的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。rpm包安装比较简单,这里不做说明。对于大多数开源软件,如果找不到安装包,可以使用源码安装方式,源...
    99+
    2023-06-25
  • .NET Core 源码编译的问题解析
    引言: .NET Core 源码编译 https://github.com/dotnet git clone https://github.com/dotnet/runtime.gi...
    99+
    2024-04-02
  • vue使用源码分析
    本篇内容主要讲解“vue使用源码分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“vue使用源码分析”吧!生命周期0版本1.哪些生命周期接口initCreatedbeforeCompileCom...
    99+
    2023-07-04
  • Reactcommit源码分析详解
    目录总览commitBeforeMutationEffectscommitMutationEffects插入 dom 节点获取父节点及插入位置判断当前节点是否为单节点在对应位置插入节...
    99+
    2022-11-13
    React commit React commit源码
  • 源代码编译安装PHP PDO MySQL:详细步骤解析
    源代码编译安装PHP PDO MySQL:详细步骤解析 在搭建Web服务器的过程中,PHP和MySQL是两个不可或缺的重要组件。而PHP的PDO扩展(PHP Data Objects)...
    99+
    2024-03-07
    编译 源代码 安装。
  • Ceph源码编译与打包的示例分析
    小编给大家分享一下Ceph源码编译与打包的示例分析,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!1clone repository源码打包docker 7u机器:lvjian100081200005.et15sqagit ...
    99+
    2023-06-04
  • 解析C/C++ Capstone 引擎源码编译问题
    Capstone 是一个轻量级的多平台、多架构的反汇编框架。Capstone 旨在成为安全社区中二进制分析和反汇编的终极反汇编引擎。Capstone的编译非常简单只需要一步即可轻松得...
    99+
    2024-04-02
  • 深入解析golang编译器的编译过程:从源码到可执行文件
    从源码到可执行文件:解析golang编译器的编译过程概述:Golang是一种快速、简单和可靠的编程语言,而其编译器是将Golang代码转换为可执行文件的关键工具。在这篇文章中,我们将深入探究Golang编译器的编译过程,从源码到最终生成的可...
    99+
    2023-12-29
    编译器 (Compiler) 源码 (source code) 可执行文件 (executable file)
  • Golang HTTP编程的源码解析详解
    目录1、网络基础2、Golang HTTP编程2.1 代码示例2.2 源码分析3. 总结1、网络基础 基本TCP客户-服务器程序Socket编程流程如如下图所示。 TCP服务器绑定到...
    99+
    2023-02-21
    Golang HTTP编程 Go HTTP编程 Golang HTTP
  • Java ConcurrentHashMap的源码分析详解
    目录概述ForwardingNode节点TreeNodeTreeBinSizeCtl初始化初始化流程查找插入扩容红黑树的读&写读操作写操作小结容器计数总结概述 Concurr...
    99+
    2023-03-02
    Java ConcurrentHashMap源码 Java ConcurrentHashMap
  • Vue中AST源码解析的示例分析
    这篇文章主要介绍Vue中AST源码解析的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!从这个函数开始的:// Line-3924  Vue.prototy...
    99+
    2024-04-02
  • postgresql9.6主从高可用源码环境编译配置详解
    系统版本:centos78核32G内存主从服务器IP:192.168.125.33 postgreSQL master192.168.125.34 postgreSQL slave1、创建数据库管理账户# ...
    99+
    2024-04-02
软考高级职称资格查询
推荐阅读
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作