Heim  >  Artikel  >  Web-Frontend  >  etpl-wrap的产生_html/css_WEB-ITnose

etpl-wrap的产生_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-21 08:49:121403Durchsuche

这周发了个etpl的node包装器,到npm上,以及对应的github地址: https://github.com/wslx520/etpl-wrap

为什么会有etpl-wrap?

etpl是我用过的一款非常强大的模板引擎,该有的功能都有。

etpl是可以用在node环境下的,但用法与我想像中的不一样。

这就要从我学习koa说起了,我学的koa2,他有一个koa-views的中间件,用来接入渲染模板文件的功能。但理所当然的是,无法与etpl配合起来使用。

之前express也是如此,如果有某引擎要与express配合起来,需要额外设置,也许还要在源码里专门做些工作。

我觉得这样很别扭,web框架与模板引擎关系大吗?不应该是互相独立的吗?

比如koa,使用了koa-views并接入模板引擎用,为的就是在渲染模板的时候,可以使用

ctx.body = ctx.render(‘index’,data)

这样的语法来渲染。但我想,假如我有一个完全独立的模板引擎,难道不可以这样用?:

ctx.body = etpl.render(‘index’,data)

这样的用法,模板引擎与web框架完全无关。你甚至可以在express中,按同样的语法使用:

res.end(etpl.render(‘index’,data))

这样不才是更好的状态吗?为啥模板引擎必须要注入到web框架里?

etpl在Node下的不一样

Node好歹也是服务器环境,如果他有模板文件 ,一般也是一个文件。但 etpl不具备直接渲染文件的能力

如果我们使用etpl来渲染一个Node下的模板文件,按正常流程,我们需要先读取到文件的内容,转换成字符串,然后传给etpl.compile,然后render。

但这样太不智能了,我不能接受。

所以我就想写这么一个包装器,用来在node.js下方便的使用etpl.

包装原理

包装器有个原则:不能改动原始的源代码。也就是说,我不能对etpl本身做什么,不然etpl以后升级了,我就难办了。

我粗看了一个etpl的源代码,但复杂了,而我时间有限,看完他不现实(其实是我看不太懂)

本来我打算的是,在render时,动态读取对应的模板文件,如果未编译,就编译,再渲染,并要把编译结果缓存起来(避免重复编译的消耗);如果已编译,就马上渲染

但这样有些难了,而且说不定必须改etpl源码。

后来我自我安慰说,一个网站的模板文件,加起来应该也不超过10M吧,小case,我 从一进来就读取所有的模板文件,并依次调用etpl.compile编译了,以后etpl.render的时候,就不用担心“有没有编译过”的问题。

虽然这样肯定 在启动服务器时,就会有额外的消耗,但应该可以接受。

target

etpl为了方便编译不同的“模块”,使用了target。比如我们新建了一个index.html的模板文件,如果以后想etpl.render(‘index’,data)的话,则index.html的第一句必须是一个target声明,如:

但这样对服务器端显然不合理,因为在服务器端,每个不同的文件,就是不同的模块。

所以包装器做了个处理:

如果模板文件第一句不是target声明,则以当前模板文件的名字作为target的名字

 

还有,如果你非要在模板文件第一句声明target,则target name需要与模板文件名一致

这么一算还是不写target划算

另外,在浏览器端,用户需要自行规避target同名的问题。但在服务器端,根目录下可以有list.html,子目录下也可以有,二者理论上是完全不冲突的

子目录下的模板文件

2016/5/5下午想明白一个原则:“ 同目录下的所有target都是同级的”。这原则相信没人会反对,基于本原则,很多关于子目录下的模板问题都能简单解决

如果子目录下有多个模板文件,则默认以index当作主文件。如有子目录:main,则其下的index会自动变成target:main

此时如有想引用main/index的,引用main就行了。

,其他文件如main/content,则会变成target: main/content

但其实main与main/content是同级的(因为main=main/index)

可以 考虑增加一个“默认主模板”的参数,可以设置为index,main等

子目录下的模块与父级模板互引用

服务器环境的模板,还有个问题,就是子目录下的模板。

比如根目录下的index.html可能会 import: list/list1.html

而子目录下的模板也可能会引用父级目录的模板如:import : ../header

这是浏览器端的etpl不会碰到的情况

所幸如果 直接把target名字取为一个路径的话,在etpl里也能正常使用,如:

target: header/head-detail

同文件下多个target的情况

etpl当然是允许一个模板文件下有多个target的,所以我不能去掉这个功能

那么,在一个模板文件中,有import其他target时,此时就要考虑:

是引用的本文件的其他某target?

是引用的本文件同级下的其他模板文件?

如果引用的target,在同级或父级的其他模板文件中,也有,优先级是?–本文件最高

按最简单的原则,优先级应该是:同文件下的target==> 同级下的其他文件里target

一个文件引用其他文件下的其他target

比如有个header.html,会被默认当作target:header,但他后面有另一个target: li,此时,有另一个模板文件list.html,也想使用target:li,该如何引用?

本来我考虑在import时,使用 import: header.li 来引入,但测试发现这样的target名字会导致etpl报错(后来查看源码,可以通过修改源码修正这个问题,但这不合我的要求)

如果允许这个引用,可能会出现: import: head/head-left/logo.image的情况

暂时打算禁止 从一个模块文件引入其他模板文件中的非主target。(不过我想,有的人会给非主target取个不会冲突的名字,其他模板文件当成一个全局target一样引用,应该是合法的呢,不应该禁止)

2016/5/5:

今天想到一个思路:同文件下多target,非主target会被当作主target的子target。如:主target:main,则本文件中的其他target分别是main/li, main/p等等。这样一来,有外部文件想引用他们,则直接import: main/li 即可

但这样就有一个要求: 须保证同级目录下的所有模板文件里的所有target,不能重名。但这点是可以做到的。

下午,又想到个问题:

如子目录main下的主模板文件index,里面有其它target: good,编译时会被编译成target: main/good

而main目录下有另一个模板文件content.html,里面也有其他target:other,此时应编译成 main/content/other,还是main/other?

暂时决定是后者,因为需要保证“ 同目录下的所有target都是同级的”,即使你的target是在其他次模板文件里声明的

引用target时的不同

因为node端有了目录概念,所以target也有就有路径,不能像浏览器一样,import:target1,import:target2,而可能会变成:import:list/li1, import:list/li2, import:../main/list2

但前面也说了,target中出现.会让etpl报错

所以我决定在包装器里,将../这种相对路径换算成从 模板根目录出发的绝对路径。比如,root/main/list/ul.html模板文件,import:../list2/li,则会换算成:import:/main/list2/li

最后

鉴于fn.call这样执行函数,效率会低几倍,所以给其中几个函数加入了额外的参数,以避免用call执行

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn