告别 HTML、Template、JSX,像 Flutter 和 Swift 一样用 OOP 语法开发 Web 前端的新尝试

2,349 阅读6分钟

flutter语法

image.png

swiftUI语法

image.png

为什么想要尝试oop开发ui界面

由于同一种语法之间的互操作,比两种语法之间的互操作要容易和灵活的多,所以web前端能不能也像flutter和swiftUI那样使用oop语法那样更灵活的开发ui呢,于是我开始了尝试

OVS(object view js)

我为他命名为ovs(object view js),一种面向对象的视图ts扩展语法,目前还仅仅是一个最简示例demo,但接下来我会持续完善这个语法

语法

div{
    'hello world',
     button({style: { color: 'red' }}){ 'click me' }
}

经过编译会转换为

h('div', [
  '123',
    h('button',{style: { color: 'red' }},'click me')
])

目前对这个语法的支持是在vue渲染函数的基础上实现的

实现思路

ovs语法只是一种语法糖,他完全等同于vue的渲染函数,所以我要做的仅仅是在编译阶段,将ovs语法转为vue的渲染函数即可

扩展后的typescript语法,不能再是.ts文件,因为他不是标准的ts语法,所以需要新建一种文件类型为.ovs

开发环境和三方依赖

开发环境是 vite + vue, 代码转换使用 chevrotain + typescript 实现,

image.png

chevrotain

具体实现

开发一个vite插件(vite-plugin-ovs),让vite可以识别.ovs后缀的文件

image.png

使用此插件,并配置vue处理ovs,因为是基于vue的渲染函数实现的,所以需要vue处理编译后的逻辑

image.png

将读取到的ovs中的代码,转换为原生ts代码
寻找支持ovs语法的编译器
  1. 我们需要识别ovs语法的代码,由于这是我们自创的语法,所以是没有其他编译器支持这种结构的,所以我们必须自己创建支持这个语法的编译器,
放弃编译器babel,babel不支持扩展js语法

经历了一天多的了解,我首先尝试了babel,发现babel并不支持自定义语法,babel对于ts的扩展语法都是内置插件,所有插件对语法的支持也都是因为已经内置了对语法的支持,只是通过配置项开启和关闭而已

www.zhihu.com/question/66…

github.com/babel/babel…

放弃编译器acorn,仅支持js,不支持ts

github.com/acornjs/aco…

放弃编译器typescript、typescript-eslint 等

不支持语法扩展插件,需要修改源码,太重了,后续维护问题,还有需要对源码的高度理解,都劝退了我

支持任意自定义语法的编译器,chevrotain

经过不断地了解,pegjs、antrl4等等各种支持自定义语法的js编译器,我找到了一个最简单易用的编译器,chevrotain,

大部分自定义编译器都需要使用ebnf语法定义语法,需要使用一种js之外的语言定义语法,然后将定义好的语法经过编译成为代码,在使用这个经过编译生成的代码来处理你需要处理的代码,这就有点麻烦了,antrl4就是这样

chevrotain却简单了很多,他完全使用js,不涉及ebnf语法,这是我选择他的原因,他还有很多好处,比如性能更快等等,大家可以去官网了解

使用chevrotain处理ovs语法,生成cst

但是chevrotain的解决方案也不是那么完美,chevrotain官方仅仅提供了ecma5语法的语法文件,这代表着要支持typescript还需要扩展ecma5的语法,幸运的是chevrotain支持语法扩展,使得这个难度没那么大,但依旧不小

目前我还没有做到这个阶段,目前还是只将ovs转为es5,没有转为ts

  1. 扩展chevrotain的es5语法支持ovs,继承ECMAScript5Parser,定义一个名为OvsDomRender的新语法,
语法定义

// (参数) 可选,元素数组可选 标识符(){ 元素数组 }

image.png

这样chevrotain就可以支持ovs语法了,经过chevrotain处理,我们就可以得到chevrotain处理后的cst了

将chevrotain处理后得到的cst转换为typescript的ast
  1. 这部分就是自己手撸代码了,没找到什么方便取巧的办法,总之就是将 chevrotain 处理
div{
    'hello world',
     button({style: { color: 'red' }}){ 'click me' }
}

得到的cst,转为

h('div', [
  '123',
    h('button',{style: { color: 'red' }},'click me')
])

对应的typescript的ast,两种数据结构的转换,自己想办法对应上就行了

将typescript的ast转为vue渲染函数代码

这部分比较简单,直接调用typescript的api就行了,通过printer对象实现,printer对象为typescript编译器的内置对象,得到渲染函数代码

将渲染函数代码放到vue的render函数中,返回

放到vue的render函数中,然后将这个vue文件交给vue处理

image.png

页面正确渲染了

image.png

灵感来源

  1. 灵感来自于很久以前,但以前只是想了想

image.png

前端能否参考swiftui和flutter开发一个不使用html的面向对象的UI框架?

  1. 最近开发,而且又被模板和jsx语法搞得头痛,我的业务需要开发一个基础界面模板,同时又需要使用者可以对基础模板进行各种插槽,对已有界面部分内容进行重写,使用vue插槽来实现,需要定义各种插槽,很麻烦

于是最近又提了一系列相关问题

image.png

  1. 最终还是自己决定尝试试一试

专栏

前端编译原理开发日记:subhuti(语法文件自动转换编程语言),ovs(纯js开发前端界面语法

相关推荐

【编译原理创新尝试(一)】parser代码解析篇:不再写代码生成器generator,用类ebnf语法实现不同编程语言的自动转换,200行js示例入门编译原理

【编译原理创新尝试(二)】generator代码生成篇:不再写代码生成器generator,用类ebnf语法实现不同编程语言的自动转换

结尾

本人菜鸡,文中的不足之处,请谅解

如果本文的思路存在问题,或者有更便捷的实现方式,希望您能告知,不足之处也请您指出,非常感谢

本文只是尝试一种新思路,仅为一个简单demo,细节处理中存在漏洞,请谅解

特别鸣谢 chatGPT,chevrotain,vue

  1. 如果在没有chatGPT之前,完全无法想象这是我这个菜鸡可以做的事情,chatGPT扩展了我的能力边界,使我可以去尝试那些原本能力之外的事

  2. chevrotain,可以通过js的语法扩展js的语法,让自定义语法变的很简单,部分初始灵感来自于chevrotain

  3. 感谢vue的render函数,没有render函数,ovs做起来也没这么简单

求职

30岁,成人本科,10年前端(3年java,7年前端)20年代码经验求职,坐标(北京、天津、唐山)