关于模板引擎一

本文转载于:猿2048网站⇒关于模板引擎一php

 

前端模板引擎须要有开发时的透明性

透明性即指我在搭建好开发环境后,随手写代码随手刷新浏览器就能看到最新的效果,而不须要额外地执行任何命令或有任何的等待过程。前端

因此一切依赖编译过程的模板引擎并不适合前端使用,编译只能是模板引擎的一个特性,而不能是使用的前提后端

更严格地说,使用FileWatch等手段进行文件变动检测并自动编译也不在个人考虑范围以内,由于这会形成额外的等待,设计模式

由此能够推出,前端的模板引擎应该是具有可在纯前端环境中解析使用的能力的。浏览器

前端模板引擎要有良好的运行时调试能力

因为用户行为的不肯定性、执行环境的不肯定性、各类第三方脚本的影响等,前端很难作到彻底的错误处理和跟踪,这也致使前端必然存在须要直接在线上排查问题的状况安全

而当问题出如今模板引擎这一层时,就须要模板引擎提供良好的调试能力性能优化

通常来讲,编译后生成的函数的调试能力是弱于原先手动编写的模板片段的,由于自动生成的函数基本不具有可读性和可断点跟踪性bash

所以在这一点上,一个供前端使用的模板引擎应该具有在特定状况下从“执行编译后函数获取HTML”换回“解析原模板再执行函数获取HTML”的模式,即应该支持在两种模式间切换markdown

或者更好地,一个强大的前端模板引擎编译生成的函数,可使用Source Map或其它自定义的手段直接映射回原模板片断,不过如今并无什么模板引擎实现了这一功能框架

前端模板引擎要对文件合并友好
在HTTP/2普及以前,文件合并依旧是前端性能优化中的一个重要手段,模板做为文件的一部分,依旧是须要合并的

在提供编译功能的模板引擎中,咱们可使用编译的手段将模板变为JavaScript源码,再在JavaScript的基础上作文件合并

可是若是咱们出于上文所说的调试能力等缘由但愿保留原模板片断,那就须要模板引擎自己支持模板片断合并为一个文件了

大部分仅支持将一段输入的字符串做为模板解析的引擎并不具有这一能力,他们天生并不能将一整个字符串切分为多个模板片断,于是没法支持模板片断层面上的文件合并

须要实现对文件合并的支持,最好的办法就是让模板的语法是基于“片断”的

前端模板引擎要担负XSS的防范

从安全性上来讲,前端对XSS的控制是有严格要求的

前端对XSS的防范比较合适的方法是使用“默认转义”的白名单式策略

基于此,一个合理的模板引擎是必须支持默认转义的,即全部数据的输出都默认通过escape的逻辑处理,将关键符号转为对应的HTML实体符号,以从根源上杜绝XSS的入侵路径

固然并非全部的内容都必须通过转义的,在系统中免不了有对用户输入富文本的需求,所以须要支持特定的语法来产生无转义的输出,但时刻注意无转义输出才是特例,默认状况下必须是转义输出的

前端模板引擎要支持片断的复用
这并非前端模板引擎的需求,事实上任何模板引擎都应该支持片断的复用,后端如Velocity、Smarty等无不拥有此功能
所谓片断复用,应该有如下几个层次的应用:
  1. 一个片断能够被引入到另外一处,至关于一个变量处处用的效果
  2. 一个片断被引入时,能够向其传递不一样的数据,至关于一个函数处处用的效果
  3. 一个片断能够被外部替换,但外部不提供此片断的话保持一个默认的内容,相似设计模式中的策略模式

知足第1和第2点的模板引擎并很多,而知足第3点的前端模板引擎却很少见,然后端的Razor、Smarty等都具有这一功能

前端模板引擎要支持数据输出时的处理

所谓数据输出时处理,指一个数据要在输出时作额外的转换,最多见的如字符串的trim操做,比较技术性的如markdown的转换等

诚然数据的转换彻底能够在将数据交给模板引擎前就经过JavaScript的逻辑处理完,但这会致使很多有些丑陋又有些冗余的代码,对逻辑自己的复用性也会形成负面的影响

一般模板引擎对数据作额外处理会使用filter的形式实现,相似bash中的管道的逻辑。filter的实现和注册也会有不一样的设计,如mustache其实注册的是fitler工厂,而另外一些模板引擎则会直接注册filter自己,不一样设计有不一样的考量点,咱们很难说谁好谁坏 

可是,模板引擎支持数据的输出处理后,会另咱们在编码过程当中产生一个新的纠结,即哪些数据处理应该交由模板引擎的filter实现,哪些应该在交给模板引擎前由本身的逻辑逻辑实现。这个话题展开来又是一篇长长的论述,于当前的话题无关就略过吧

前端模板引擎要支持动态数据

在开发过程当中,其实有很多数据并非静态的,如EmberJS就提供了Computed Property这样的概念,Angular也有相似的东西,Backbone则能够经过重写Model的get方法来变相实现

虽然ES5在语言层面上直接提供了getter的支持,但咱们在前端开发的大部分场景下依旧不会使用这一语言特性,而会选择将动态的数据封装为某种对象的get等方法

而模板引擎在将数据转为HTML片断的过程当中,一样应该关注这一点,对这些动态计算的数据有良好的支持

说得更明白一些,模板引擎不该该仅仅接受纯对象(Plain Object)做为输入,而应该更开放地接受相似带有get方法的动态的数据

一个比较合理的逻辑是,若是一个对象有一个get方法(模板引擎决定这个接口),则数据经过该方法获取,其它状况下视输入的对象为纯对象(Plain Object),使用标准的属性获取逻辑

前端模板引擎要与异步流程严密结合

一个很常见的例子是,咱们有一个AMD模块存放了全局使用的常量,模板引擎须要使用这些常量。固然咱们能够在使用模板引擎以前让JavaScript去异步获取这一模块,随后将常量做为数据传递给模板引擎,但这是一种业务与视图相对耦合的玩法,出于强迫症我并不以为这是一个漂亮的设计,因此咱们但愿
  • 模板的输出自己成了异步的方法,而再也不像如今同样直接返回字符串
  • 分析模板对异步操做的依赖,整个字符串的拼接逻辑被打断成多个异步
  • 异步是须要等待的,且等待是未知的,从性能上考虑,是否须要考虑Stream式的输出,以便完成一段提供一段
  • 是提供内置的固定几种异步逻辑,仍是基于Promise支持任何自定义的异步逻辑,在复杂度和实用性上做出平衡

至今我尚未彻底明确模板与异步结合的方式和接口,这个话题也没办法继续深刻探讨了

前端模板引擎要支持不一样的开发模式
前端发展至今,有不少不一样的开发模式,好比:
  • 最普通的HTML页面,使用DOMContentLoaded等事件添加逻辑,特定交互下局部刷新页面
  • 采用传统的MVC模型进行单页式开发
  • 使用MVVM方式以数据为核心,数据与视图方向绑定进行开发
  • 基于Immutable Data进行数据比对Diff转DOM更新的开发(其中可能有Virtual DOM的引入)
一个模板引擎要能支持这么多种不一样的的模式是一个很是大的挑战,特别是对双向绑定的支持尤其突出。至今为止几乎全部的支持双向绑定的开发框架都自带了专用的模板引擎,这是由于双向绑定对模板有两大要求:
  • 可以从模板中提取“这一模板对哪些数据有依赖”的元信息
  • 可以知道一个数据变化引擎的是模板的哪一块,而不至于整个刷新

而通用模板引擎不多提供这两个特性,因此没办法对不一样的前端开发模式进行全面到位的支持
从模板引擎自己的实现上来讲,一种方法是直接将模板解析后的相似AST的结构暴露出去,供其余框架合理地处理,同时提供对模板局部的刷新功能(也可与前面所说的模板片断一块儿考虑),可是大部分模板引擎为了性能等考虑,是不会解析出相似AST的语法结构来的

前端模板引擎要有实例间的隔离

在大型的前端项目,特别是单页式的项目中,会有彻底未知个数的模板片断同时存在,若是这些片断是带有名称(出于复用的考虑)的,就很容易形成名称上的冲突

对于同一层级的逻辑(如你们都是业务层代码,或者你们都是控件层代码),名称冲突是能够经过一些开发时的约定来解决的。但不一样层之间,因为封装性的要求,外部不该该知道一些仅内部使用的片断的名称,此时若是不幸有名称与其它层有冲突,会让状况变得比较麻烦,这类问题甚至都不容易跟踪,每每会致使大量的精力和时间的浪费

所以,一个好的模板引擎应该是多实例的,且不一样实例间应该相互具有隔离性,不会出现这种不可预期的冲突

将这个话题再往深地研究,就会发现单纯的隔离是不够的,不一样层间除了不冲突的需求,一样还有片断复用的需求,咱们还会须要不一样模板实例间能够开放一些固定的片断共享,所以模板引擎各个实例的关系是一种组合依赖但又具有基本的封装和隔离的状态说了这么多。

相关文章
相关标签/搜索