`
yiminghe
  • 浏览: 1461450 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

构建前端 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 ]()

 

 

 

分享到:
评论
2 楼 yiminghe 2012-10-12  
luolonghao 写道
docs.kissyui.com 被墙了吗,无法访问,上次给过我的IP再发给我吧。


你翻下墙不就知道了么...: 204.232.175.78

改到 dnspod 了,应该马上就会恢复解析
1 楼 luolonghao 2012-10-12  
docs.kissyui.com 被墙了吗,无法访问,上次给过我的IP再发给我吧。

相关推荐

    前端开源库-cake-build

    蛋糕构建以其简洁易读的语法和丰富的插件生态系统,深受前端开发者和全栈工程师的喜爱。 ### 1. 什么是Cake Build? 蛋糕构建(Cake Build)是一种跨平台的构建工具,它使用C#方言(基于Roslyn编译器)编写构建脚本...

    Android-KotlinDSLhttp客户端okhttp前端

    本篇将详细介绍如何在Android项目中使用Kotlin DSL与OkHttp来构建高效的前端HTTP客户端。 首先,我们需要了解Kotlin DSL的基本概念。Kotlin DSL允许我们创建自己的构建语法,使得配置或构建过程变得更加直观和易读...

    人工智能-项目实践-搜索引擎-使用Vue.js搭建的ElasticSearch搜索引擎的前端

    使用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 HTTP客户端(OKHTTP前端).zip

    kohttp是一个基于Kotlin语言构建的DSL(Domain Specific Language)风格的HTTP客户端库,它主要在OKHTTP的基础上提供了一种更为简洁、流畅的API接口,使得开发者在进行网络请求时可以享受到Kotlin语言的优雅与便利。...

    基于BPMN流程引擎驱动的前端研发平台

    文章进一步提出了一系列的开发和部署活动,包括:包管理、脚手架开发、合并、压缩、构建、打包、线上监控、灰度发布、自动化测试、前端性能和错误监控、源站版本管理和组件管理。这些活动共同构成了现代前端开发和...

    amis低代码前端框架,它使用 JSON 配置来生成页面

    Amis 是一个强大的低代码前端框架,其核心理念是通过 JSON 配置文件来构建复杂的 Web 应用页面。这个框架极大地简化了前端开发者的工作,尤其是对于那些需要快速搭建和迭代页面的项目,Amis 提供了一种高效、灵活的...

    dsl2code:DSL转换原始文件(reactvue)

    在这个umi项目中,DSL2Code帮助开发者快速构建基于React或Vue的前端应用。 umi是一个强大的企业级前端框架,由阿里Alibaba团队维护,它提供了丰富的功能,如路由管理、状态管理、插件机制等,以加速大型项目的开发...

    DSL Engine-开源

    DSL Engine开源项目为开发者提供了一个平台,让他们可以更轻松地构建这样的自定义语言,提高代码的可读性、可维护性和效率。 元编程(Metaprogramming)是程序设计的一种高级技术,它是指在运行时或编译时能够处理...

    《阿里前端在智能工程化上的探索-刘亚中.pdf》

    3. **DSL(Domain Specific Language)**:DSL 在这个上下文中指的是为特定领域设计的语言,例如 Pipcook 使用的 DSL 用于定义模型训练和插件生成规则,使得非专业人员也能进行机器学习模型的构建。 4. **Plugin ...

    前端项目-elasticsearch.zip

    **Elasticsearch简介** ...在前端项目中,通过这个客户端,开发者可以构建高性能、可扩展的搜索和分析功能,提升用户体验,同时利用 Elasticsearch 的强大功能进行数据挖掘和分析,为企业决策提供有力支持。

    前端项目-reactive-coffee.zip

    【标题】"前端项目-reactive-coffee.zip" 涉及到的是一个基于CoffeeScript的轻量级库或DSL(领域特定语言),专门用于在前端开发中实现反应式编程和声明性构建可伸缩的Web UI。这个项目的名字是"reactive-coffee",...

    《自己动手写前端框架》电子书.pdf

    尤其值得注意的是书中提到的“自己动手写前端框架”的章节,这部分内容可能会详细讲解如何从零开始构建自己的前端框架,并可能提供一些指导原则和最佳实践。 电子书还涉及了一些与开发环境有关的话题,例如在Linux...

    前端开源库-astring

    它还可以用于自动生成测试代码、元编程任务,甚至是构建DSL(领域特定语言)。 在"astring-master"压缩包中,可能包含了astring库的源码、文档、示例以及测试用例。通过阅读源码和文档,开发者可以更深入地理解如何...

    前端开源库-myna-parser

    3. **DSL(领域特定语言)**:构建自己的小型语言,用于特定业务场景的配置或脚本编写。 4. **Web组件通信**:解析不同组件间传递的复杂数据结构。 **六、社区支持与文档** 作为一款开源库,`myna-parser`拥有活跃...

    前端项目-pegjs.zip

    3. **DSL(领域特定语言)**:构建轻量级的DSL,用于简化复杂任务的表示,如图形编辑器的指令语言。 4. **配置文件解析**:解析应用程序的配置文件,使其支持自定义的配置格式。 **总结** "前端项目-pegjs.zip" ...

    dSL网站

    在这个名为“dSL网站”的项目中,我们可以推测这可能是一个利用JavaScript来构建的、专注于某特定业务或功能的网站。JavaScript作为Web开发中的主要脚本语言,被广泛用于前端交互、后端开发(如Node.js)以及浏览器...

    使用Rails 数据库DSL与PHP协作开发 - 色色

    2. **与PHP的协作**:讨论如何在Rails项目中集成PHP代码或服务,可能是通过API接口进行数据交换,或者是Rails作为前端应用,PHP作为后端服务。 3. **数据库设计**:可能涉及到跨语言环境下的数据库设计原则,如如何...

    データ収集とデータ表示DSLの実現1

    为了改善系统框架并提升效率,作者所在的esco Japan株式会社尝试构建了一种面向目的的领域特定语言(DSL),用于自动化数据收集和数据显示。本文将详细介绍这种技术,并分析其实际应用的结果,探讨其有用性。 首先...

Global site tag (gtag.js) - Google Analytics