likes
comments
collection
share

开坑,我又写了个前端框架,专注于下一代 Web Component UI 库

作者站长头像
站长
· 阅读数 18

大家好我是 anuoua,我之前写了个前端框架叫 Unis,Github:anuoua/unis,在掘金发了几篇介绍的文章:

骗了不少赞和评论互动,然而这里面有个老哥貌似不买账,他想要一个不需要构建的又好用的前端框架,需求很强烈。

评论截图

开坑,我又写了个前端框架,专注于下一代 Web Component UI 库

我当时的想法是,这年头前端框架基本和编译分不开,真的没啥必要排斥,就没有理他。

嗯?

在某个机缘巧合之下,我开始想这个问题,其实不需要编译的前端框架很简单,主要是需要接受全新的视图写法以代替 jsx ,首先想到的是直接在 react 中写 createElement 函数就行了,这确实是可以的,但是不美观。

长这样:

const h = createElement;
const App = () => {
  return h("div", { class: "main" },
    h("div", null,
        h("span", null,
            "hello world!"
        )
    )
  );
};

可以优化,直到我看到 van 这个前端框架,受它的写法启发,是可以这么写的,干净不少:

const App = () => 
    div({ class: "main" },
        div(null,
            span(null,
                "hello world"
            )
        )
    );

这样是不是好看多了?改造成这种形态可以直接生成对应的 ReactElement ,这样就可以在不使用编译的情况下使用 React 了,但是看着 null 还是有点膈应。

要不再改一下,利用高阶函数

const App = () => 
    div({ class: "main" })(
        div()(
            span()(
                "hello world"
            )
        )
    );

这套工具包我顺手就做了,后来才发现,这个老哥并不是要这个东西。。

但是东西我已经写好了(没几行代码,哈哈),来都来了,感兴趣的可以点的 start 呗。

Github: github.com/anuoua/jsx-…

进入正题

前面只是导火索,刚才我有提到 van 这个框架,这个框架是无虚拟 DOM 的非编译型响应式框架,对应目前很火的 solid 则是无虚拟 DOM 编译型响应式框架。

我突然对无虚拟 DOM 这件事产生了兴趣,真实的 DOM vs 虚拟 DOM ,这里面有什么惊为天人的秘密吗?

开坑,我又写了个前端框架,专注于下一代 Web Component UI 库

所以我研究了一下 van 和 solid,稍微懂了点无虚拟 DOM 前端框架的门道。

思索过后我有点自己的想法,于是开始琢磨写一个这种类似的框架,给这个框架列了个简单的目标:

  • 响应式
  • 无虚拟 DOM ,不用编译
  • 专注于 webcomponent ,专注于 ui 库

以上特点,solid 也不是不可以,但是它的主要目标不是不编译和专注 webcomponent 组件,真要那样用 DX 体验没有那么好,不了解的可以看它的文档。

技术方案

响应式 api

我看了下 van 的实现太简单了,van 本身为了小巧舍弃了不少 DX 体验,这不是我要的。当我看 solid 实现的时候,发现它的响应式 api 和 @vue/reactivity 很像,类似的还有 @preact/signals ,大差不差,只是做了点取舍。

这么看来,基于 proxy 的响应式大体都是这么回事,无非大家的考虑和取舍不太一样。

这个我不打算自己写了,@preact/signals @vue/reactivity 都是可以直接用的,但 @vue/reactivity 是这类响应式 api 的集大成者,功能是目前最全的,例如 @preact/signals 对深层数据的响应就不太行。

所以暂时用 @vue/reactivity 作为响应 api 。

无虚拟 DOM ,不用编译

@vue/reactivity 是可以直接引入浏览器用的,摆在面前的困难就是视图 dsl 怎么整比较优雅。

通过真实的 DOM 构建用户界面,如果不能借助 jsx 编译或者 html 模板编译那么挺难受的,但是上面提到的那套视图构建函数可以勉强接近 jsx 开发体验,而且类型友好,那套函数不仅可以产出虚拟 DOM 元素,同样可以直接创建 DOM 。

// 实现示例
const div =
  (attrs) =>
  (...children) => {
    const el = document.createElement("div");
    el.append(...children);
    return el;
  };

// 但是每个都要写就很麻烦,所以写个方便的 proxy,搭配 typescript 体验很是ok。
const tags = new Proxy(
  {},
  {
    get(target, key) {
      // ...
    },
  }
);

const { div, span } = tags;

// prettier-ignore
div({ class: "main" })(
    div()(
        span()(
            str("hello world")
        )
    )
);

// <div><div><span>hello world</span></div></div>

至于核心逻辑,响应式数据如何绑定到 DOM 元素,以及视图突变怎么处理。这里我简要说一下,界面突变无非这三种 “增”,“删”,“改”。

“改”是最简单的,既监听数据变更,通过 effect 处理 DOM 的 attributes 更新。 “增”和“删”比较复杂,想想我们平时使用其他框架的时候,用于实现界面突变的方法,主要就两个

  • 条件渲染:对应 vue 的 v-if else,react 的 xxx && ()、xxx ? () : ()
  • 列表渲染:对应 vue 的 v-for,react 的 list.map()

然后再想想,条件逻辑貌似也是列表逻辑,既列表 [true] 和 列表 [false] 的相互切换,所以本质上只需要完成列表逻辑即可,至于列表更改后怎么处理 DOM ,建议直接看源码吧,挺简单的。

专注于 webcomponent

我预测下一代前端 ui 库一定会大规模使用 webcomponent ,ui 库全框架化将成为主要潮流。所以本框架将专注于 webcomponent ,专注于下一代 ui 库。

是的,后续应该和 stencil 目标一致,是成为下一代全框架 ui 库的编译器(编译最终还是要上的)!

掘金的老哥们给点力,点点赞,点点 start,给我力量,让我把它最终做出来,干掉 stencil ,国产框架雄起!😘

项目进度

借助于现成的 @vue/reactivity,很快就实现了 demo。

现在已经实现基本的组件逻辑,以及常见视图变更逻辑

  • defineComponent
  • If
  • Switch
  • For

可以做 demo 了。

成果展示

如下图,这个“精致”的 Todo list,意味着框架基本逻辑已经完成。

开坑,我又写了个前端框架,专注于下一代 Web Component UI 库

webcomponent 组件

开坑,我又写了个前端框架,专注于下一代 Web Component UI 库

最后

地址:anuoua/j20 ,老哥们点个 star 吧

项目中文名: 歼 20,是的,你没听错

项目状态:正在开发中 (WIP) 还没发包

代码质量:能跑就行