- 浏览: 1461450 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
luhouxiang:
写的很不错,学习了
Extjs 模块化动态加载js实践 -
kingkongtown:
如果想改成淘宝后台那样,可以在编辑器批量上传图片呢?
kissy editor 阶段体会 -
317966578:
兄弟我最近也在整jquery和caja 开放一些接口。在git ...
caja 原理 : 前端 -
liuweihug:
Javascript引擎单线程机制及setTimeout执行原 ...
setTimeout ,xhr,event 线程问题 -
辽主临轩:
怎么能让浏览器不进入 文档模式的quirks模式,进入标准的
浏览器模式与文本模式
目前在传统的软件开发领域 [DSL ]() 已经比较普遍,特别是 [Martin Fowler ]() 的突出贡献。而在前端领域尚较少涉及,而如果在前端开发中合理使用 DSL 同样也可以有效得**减少代码数量,提高可读性**,常见的一个应用场景即前端模板的构建。本质上说模板也是一个微型语言,因此可以从DSL的角度着手,使用工具快速构建一个适合于特定前端框架的模板引擎。本文将以 [KISSY XTemplate ]()为例介绍如何构建前端的 DSL。
注:
本文持续更新地址:
[xtemplate at github ]().
[xtemplate at docs.kissyui.com ]().
DSL 也是初学,敬请勘误.
# 首先 npm 安装 kissy
npm install -g kissy
# xtemplate 示例代码
this is kissy xtemplate: {{date}} {{#if n > n*2}} {{{no escape}}} {{each array}} index: {{xindex}} count: {{xcount}} value: {{value}} {{set t = value*2}} subValue: {{#with this.subValue}} {{subSubValue + ../t}} {{/with}} {{/each}} {{else}} {{#custom_block param}} {{custom_tpl param2}} {{/custom_block}} {{/if}}
# 模板词法/语法
这一步主要是为了下一步构建自定义语言的语法树做准备,这里采用使用工具**自动生成语法解析器**(parser)的方向来做,如果你打算手写解析器则可以略过此步(事实上可以略过本文)。
由于本文关注前端技术,故词法以及语法都采用 json 格式描述,词法直接采用正则表达式,语法采用变形的 [BNF ]() 形式,例如 xtemplate 的 [词法语法文件 ]()
工具采用 kissy 开发的 [LALR ]() 语法解析器生成器 [kison ]().
词法关注如何从输入代码中解析出最基本的代码单元(关键词,字符串,数字...),例如 xtemplate 的部分词法
{ state: 't', regexp: /^{{/, token: 'OPEN' }, { state: 't', regexp: /^}}/, token: 'CLOSE' }, { state: 't', regexp: /^<=/, token: 'LE' }, { state: 't', regexp: /^\+/, token: 'PLUS' }, { state: 't', regexp: /^[a-zA-Z0-9_$-]+/, token: 'ID' },
其中 state 表示单个状态,词法解析过程也是一个状态机变换状态的过程.
而语法解析关注与从词法单元中识别出有效的程序结构,即语法解析树,例如 xtemplate 的部分语法描述:
{ symbol: 'Expression', rhs: ['ConditionalOrExpression'] }, { symbol: 'ConditionalOrExpression', rhs: ['ConditionalAndExpression'] }, { symbol: 'program', rhs: ['statements', 'inverse', 'statements'] }, { symbol: 'statement', rhs: ['openBlock', 'program', 'closeBlock'] }
其中对应 BNF 形式中: symbol ::= rhs
# 构建模板抽象语法树
语法词法只是描述了如何识别模板语言,而构建语法树的过程则需要在语法识别过程中由调用者自行构建,kison 支持在每个语法规则项中添加动作函数,通过工具在识别语言过程中(遍历[语法解析树 ]())同时有选择性得构建异型[抽象语法树 ](),例如 xtemplate 的树节点构建过程:
{ symbol: 'program', rhs: ['statements', 'inverse', 'statements'], action: function () { return new this.yy.ProgramNode(this.lexer.lineNumber, this.$1, this.$3); } }, { symbol: 'PrimaryExpression', rhs: ['path'] }, { symbol: 'RelationalExpression', rhs: ['RelationalExpression', 'LE', 'AdditiveExpression'], action: function () { return new this.yy.RelationalExpression(this.$1, '<=', this.$3); } }
其中 最基本的表达式(PrimaryExpression)可以直接是变量词法单元的值,而复杂的比较表达式以及整个程序则是自底向上由子树构建起来.
最后使用 **kissy-kison** 命令
kissy-kison -g parser.kison -m xtemplate/parser
就可以生成模板解析函数模块,大致为:
KISSY.add('xtemplate/parser', function(){ function parse(code){ // ... } return parse; });
# 模板编译
最后一步即是模板编译过程,将模板代码编译为 javascript 代码,填入数据执行后即可得到真正的渲染 html.
## 调用 parse
经过上一步得到解析函数后,调用
parse(tempalteCode)
即得到一棵抽象语法树,例如 xtemplate 的一段代码:
{{#each data}} {{#if n === ../n2 * 5}} {{n + 10.1}} {{/if}} {{/each}}
对应的抽象语法树:
## 翻译代码
接着就可以采用 [visitor ]() 模式将生成具体代码的逻辑写入 visitor 对象,遍历 ast 将对应的子树或节点转换成 javascript 代码,
这步可以继续优雅得采用代码模板,将代码模板的数据替换成模板对应的 javascript 单元。
不过为了不折磨大脑,最后放松下,可以直接采用原生的代码拼接:
visitor.tplNode=function(node){ if(node.escapeHTML){ codes.push("if("+node.id+" in data) { ret.push(KISSY.escapeHTML(data."+node.js+");) }"+ " else { KISSY.warn('not found')!; }"); }else{ } };
不过确实还是挺折磨.
## 离线编译
大多数 DSL 都是推荐在使用前就转换成目标语言,而客户端在不太注重性能的情况下也可以在终端用户使用时在线编译。
xtemplate 通过 **kissy-xtemplate** 命令支持将模板代码离线编译为模板函数模块,这样客户端可以直接require该模块,省去了客户端编译过程,同时开发中直接面对 html 类似的模板代码,省去了字符串嵌入模板的繁琐。
例如 t-tpl.html
{{ offline }} compile
运行
kissy-xtemplate -t t-tpl.html -m tests/t -w
可得到 t.js
KISSY.add('tests/t',function(){ function render(data){ } return render; });
离线编译的一个缺点是编译出来的代码肯定比原生模板大很多,这也正体现了 DSL 节省代码,易读的特性(代码肯定不可读了)。
# 下一步
目前存在两大问题:
## 体积较大
压缩前 130k, 不过 gzip+compress 后由于生成的重复代码比较多,降到 10k,不过仍然需要优化生成代码: 减少模板解析器的代码。同时也可优化模板转化为最终代码的大小,这在离线编译情况下很有用。
## xtemplate 模块需要拆分
当选择离线编译,实际上 xtemplate 的编译代码可以不用下载,可拆分为两个模块: xtemplate/runtime 以及 xtemplate/compiler
这样当选择离线编译时直接use xtemplate/runtime 载入模板的功能基础设施即可。
# xtemplate 文档
[api ]()
[demo ]()
[tutorial ]()
# 推荐书籍
感谢这些作者,没有这些书籍, 这个任务不可能完成
[Compilers: Principles,Techniques and Tools ]()
[DSL In Action ]()
[Language Implementation Patterns: Create Your Own Domain-Specific and General Programming Languages ]()
# 致谢
在开发过程中参考一了下工具:
[velocity ]()
[closure templates ]()
[bison ]()
[jison ]()
[handlebar ]()
[mustache ]()
评论
你翻下墙不就知道了么...: 204.232.175.78
改到 dnspod 了,应该马上就会恢复解析
发表评论
-
continuation, cps
2013-09-12 16:49 2796起 随着 nodejs 的兴起,异步编程成为一种潮流 ... -
一种基于匹配回朔的 css3 选择器引擎实现
2013-05-07 20:40 3401一种基于匹配回朔的 css3 选择器引擎实现 介绍 C ... -
模块化高扩展性的前端框架 KISSY
2013-03-14 14:58 8620模块化高扩展性的前端框架 KISSY 注:本文为 2 ... -
cubic-bezier 模拟实现
2013-01-05 16:34 14090cubic-bezier 曲线是 css3 动画的一个重要基石 ... -
KISSY kisses bootstrap navbar
2012-08-03 01:12 6029看了下 bootstrap 的导航菜单,立刻非常喜欢,注意是浅 ... -
Get cursor position and coordinates from textarea
2012-04-10 20:50 5044最近需要从 textarea 中获 ... -
兼容 ie 的 transform
2012-02-23 14:00 6427css 2d transform 是 css3 引入的一个新的 ... -
promise api 与应用场景
2012-02-07 17:34 7381promise 是 commonjs 社区中提出的异步规范,其 ... -
closure compiler 代码优化实例
2012-01-08 03:23 2832closure compiler 可以进行不少有意思的优化 ... -
circular dependency
2011-12-11 18:23 3923循环依赖是和语言无关 ... -
write html parser
2011-12-01 02:48 2917首先需要声明 html 不能用正则表达式来直接匹配进行内容抽取 ... -
获取剪贴板数据
2011-11-07 23:31 6449兼容性: 获取剪贴板数据这块各个浏览器间存在很大的 ... -
url 映射问题
2011-11-07 21:52 3221背景 url mapping 我最早知道是作为 j ... -
tip:如何原生播放声音
2011-10-19 12:45 2979如果不想考虑浏览器间 ... -
unified event model
2011-10-14 23:02 1786为了处理原生事件在各 ... -
转载:瀑布流布局浅析
2011-09-29 19:02 2845简介 如果你经 ... -
cross domain request
2011-09-29 18:39 2846场景 跨域请求是随着 ... -
基于多继承的树设计
2011-09-18 03:42 2269分类 树是一种常见 ... -
caja 原理 : 前端
2011-09-01 16:48 7049作为前端开放的基础安全保证,caja 是目前比较合 ... -
tokenization of html
2011-08-29 22:38 2787html 符号解析问题 场景: 在页面上输出包 ...
相关推荐
蛋糕构建以其简洁易读的语法和丰富的插件生态系统,深受前端开发者和全栈工程师的喜爱。 ### 1. 什么是Cake Build? 蛋糕构建(Cake Build)是一种跨平台的构建工具,它使用C#方言(基于Roslyn编译器)编写构建脚本...
本篇将详细介绍如何在Android项目中使用Kotlin DSL与OkHttp来构建高效的前端HTTP客户端。 首先,我们需要了解Kotlin DSL的基本概念。Kotlin DSL允许我们创建自己的构建语法,使得配置或构建过程变得更加直观和易读...
使用Vue.js搭建的ElasticSearch搜索引擎的前端 Build Setup # install dependencies npm install # serve with hot reload at localhost:8080 npm run dev # build for production with minification npm run ...
kohttp是一个基于Kotlin语言构建的DSL(Domain Specific Language)风格的HTTP客户端库,它主要在OKHTTP的基础上提供了一种更为简洁、流畅的API接口,使得开发者在进行网络请求时可以享受到Kotlin语言的优雅与便利。...
文章进一步提出了一系列的开发和部署活动,包括:包管理、脚手架开发、合并、压缩、构建、打包、线上监控、灰度发布、自动化测试、前端性能和错误监控、源站版本管理和组件管理。这些活动共同构成了现代前端开发和...
Amis 是一个强大的低代码前端框架,其核心理念是通过 JSON 配置文件来构建复杂的 Web 应用页面。这个框架极大地简化了前端开发者的工作,尤其是对于那些需要快速搭建和迭代页面的项目,Amis 提供了一种高效、灵活的...
在这个umi项目中,DSL2Code帮助开发者快速构建基于React或Vue的前端应用。 umi是一个强大的企业级前端框架,由阿里Alibaba团队维护,它提供了丰富的功能,如路由管理、状态管理、插件机制等,以加速大型项目的开发...
DSL Engine开源项目为开发者提供了一个平台,让他们可以更轻松地构建这样的自定义语言,提高代码的可读性、可维护性和效率。 元编程(Metaprogramming)是程序设计的一种高级技术,它是指在运行时或编译时能够处理...
3. **DSL(Domain Specific Language)**:DSL 在这个上下文中指的是为特定领域设计的语言,例如 Pipcook 使用的 DSL 用于定义模型训练和插件生成规则,使得非专业人员也能进行机器学习模型的构建。 4. **Plugin ...
**Elasticsearch简介** ...在前端项目中,通过这个客户端,开发者可以构建高性能、可扩展的搜索和分析功能,提升用户体验,同时利用 Elasticsearch 的强大功能进行数据挖掘和分析,为企业决策提供有力支持。
【标题】"前端项目-reactive-coffee.zip" 涉及到的是一个基于CoffeeScript的轻量级库或DSL(领域特定语言),专门用于在前端开发中实现反应式编程和声明性构建可伸缩的Web UI。这个项目的名字是"reactive-coffee",...
尤其值得注意的是书中提到的“自己动手写前端框架”的章节,这部分内容可能会详细讲解如何从零开始构建自己的前端框架,并可能提供一些指导原则和最佳实践。 电子书还涉及了一些与开发环境有关的话题,例如在Linux...
它还可以用于自动生成测试代码、元编程任务,甚至是构建DSL(领域特定语言)。 在"astring-master"压缩包中,可能包含了astring库的源码、文档、示例以及测试用例。通过阅读源码和文档,开发者可以更深入地理解如何...
3. **DSL(领域特定语言)**:构建自己的小型语言,用于特定业务场景的配置或脚本编写。 4. **Web组件通信**:解析不同组件间传递的复杂数据结构。 **六、社区支持与文档** 作为一款开源库,`myna-parser`拥有活跃...
3. **DSL(领域特定语言)**:构建轻量级的DSL,用于简化复杂任务的表示,如图形编辑器的指令语言。 4. **配置文件解析**:解析应用程序的配置文件,使其支持自定义的配置格式。 **总结** "前端项目-pegjs.zip" ...
在这个名为“dSL网站”的项目中,我们可以推测这可能是一个利用JavaScript来构建的、专注于某特定业务或功能的网站。JavaScript作为Web开发中的主要脚本语言,被广泛用于前端交互、后端开发(如Node.js)以及浏览器...
2. **与PHP的协作**:讨论如何在Rails项目中集成PHP代码或服务,可能是通过API接口进行数据交换,或者是Rails作为前端应用,PHP作为后端服务。 3. **数据库设计**:可能涉及到跨语言环境下的数据库设计原则,如如何...
为了改善系统框架并提升效率,作者所在的esco Japan株式会社尝试构建了一种面向目的的领域特定语言(DSL),用于自动化数据收集和数据显示。本文将详细介绍这种技术,并分析其实际应用的结果,探讨其有用性。 首先...