构建前端 DSL

目前在传统的软件开发领域 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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索前端
, 前端开发工具
, 模板
, 代码
, 语法
, 单词勘误
, dsl
XTemplate
前端 dsl、前端构建工具、前端自动化构建工具、前端构建工具有哪些、前端自动化构建,以便于您获取更多的相关知识。

时间: 2024-10-03 19:29:42

构建前端 DSL的相关文章

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码]

原文:构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)-easyui构建前端页面框架[附源码] 开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用户的体验已经需要越来越注重,这次我们是左右分栏,左边是系统菜单,右边是一个以tabs页组成的页面集合,每一个tab都可以单独刷新和关闭,因为他们会是一个iframe 工欲善其事必先利其器.需要用到以下工具. Visual Studio 2012 您可以安装MVC4 for vs2010用VS2010

Gulp构建前端自动化工作流

## Gulp构建前端自动化工作流 ### Gulp构建前端自动化工作流之:常用插件介绍及使用 在对Gulp有了一个初步的了解之后,我们开始构建一个较为完整的Gulp开发环境. 本文主要分为6个段落: * 1\. 构建项目目录结构(Directory Structure Build)* 2\. 插件介绍及使用方法(Tasks and dependencies)* 3\. 扩展优化(Extend & Optimize Task)* 4\. 其他插件介绍(Other plug-ins)* 5\. 匹

基于Bootstrap和jQuery构建前端分页工具实例代码_jquery

前言 为啥名字叫[前端分页工具]?因为我实在想不到什么好名字,如果想要更加贴切的理解这个工具,应该从业务来看 业务是这样的,有一个数据从后台传到前台,因为数据量不大,因此传过来之后直接显示即可,但是=.=所谓的数据量不大,最多也达到成百上千条,不可能全部显示出来,那么就需要分页 常规的分页是利用Ajax,通过传页偏移量到后台,后台查询数据库再返回数据,可以实现无刷新分页,拿到的数据也是最新的 前端分页 优点:一次传输数据,避免用户反复请求服务器,减少网络带宽.服务器调度压力.数据库查询.缓存查询

打造可靠的Ajax应用程序: 第1部分:构建前端

简介:如今,Ajax 仍然是业界的热门字眼,越来越多的应用程序都采用 Ajax 技术构建.然而,构建一个好的 应用程序并不容易.本文将着重讨论如果构建 直 观易用的受 Ajax 驱动的应用程序. Ajax 并不只是一种技术.大多数开发人员却认为它是,并试图借助诸如 XML 和 JavaScript 这类语言证明其观点.但这种观点非常局限,并且,忽视了付钱 给您的人:客户,不管是咨询代理还是您的老板(只有您建立了令人满意的用户 群,他们才能获得收入). 客户并不关心技术:他们关心的是应用程序的外在

构建前端UI组件的新思路

前端UI组件,目前流行的实现方式大多源自传统客户端的UI设计体系.无论是早期的Bindows,还是近几年兴盛的ExtJS,其UI组件都在模仿客户端软件,代码实现建立在复杂的继承体系上.好处是可以构建出和客户端体验一致的一整套UI组件,但弊端也很明显:组件长得都差不多,代码则继承太深,牵三挂四,不够轻便. 如何才能让前端UI组件轻便灵活起来呢?首先得意识到Web UI设计有自己的独特性.Web页面可分为两种:一种是以展现信息为主的Web页面(web page),另一种是以操作信息为主的Web应用(

前端工程化:云构建

背景 通常个人在开发项目的时,都是在本地编写构建脚本对项目进行构建,这个脚本可能是 Gulp,可能是 Grunt, 可能是 webpack,也可能是其他的一些脚本,每次代码发布之前,都要对代码进行构建,代码仓库里面包含构建脚本和构建之后的代码.对于个人开发,这样做是没有问题的,但是涉及到多人开发或者团队开发就会有一定的问题.说是问题也不是问题只不过是会导致开发效率降低,构建错误的情况越来越多. 在本地对项目进行构建,通过脚手架工具来分发构建脚本对于团队开发来说有很多问题: 构建脚本的开发维护者很

构建ASP.NET MVC4+EF5+EasyUI+Unity2.x注入的后台管理系统(2)

easyui构建前端页面框架[附源码] 开始,我们有了一系列的解决方案,我们将动手搭建新系统吧. 用户的体验已经需要越来越注重,这次我们是左右分栏,左边是系统菜单,右边是一个以tabs页组成的页面集合,每一个tab都可以单独刷新和关闭,因为他们会是一个iframe 工欲善其事必先利其器.需要用到以下工具. Visual Studio 2012 您可以安装MVC4 for vs2010用VS2010来开发,但是貌似你将不能使用EF5.0将会是EF4.4版本,但这没有多大的关系. MVC4将挂载在.

使用Spring Cloud和Docker构建微服务

本文讲的是使用Spring Cloud和Docker构建微服务,[编者的话]这是系列博文中的第一篇,本文作者使用Spring Cloud和Docker构建微服务平台,文章的例子浅显易懂. 本系列博文主要向大家介绍如何使用Spring Cloud和Docker构建微服务平台. 什么是Spring Cloud? Spring Cloud 是Pivotal提供的用于简化分布式系统构建的工具集.Spring Cloud引入了云平台连接器(Cloud Connector)和服务连接器(Service Co

前端知识图谱,你值得收藏

综合类 - [前端知识体系](http://www.cnblogs.com/sb19871023/p/3894452.html) - [前端知识结构](https://github.com/JacksonTian/fks) - [Web前端开发大系概览](https://github.com/unruledboy/WebFrontEndStack) - [Web前端开发大系概览-中文版](http://www.cnblogs.com/unruledboy/p/WebFrontEndStack.h