Skip to content

gitborlando/frame3

Repository files navigation

介绍

  • frame 取自 "framework" 的 "frame", 是我两年前写的 frame.js 的第三代
  • frame3 只是长得像 react, 其内核还是 vue3 那套, 换句话说就是 react 的外表, vue 的内心
  • 尽管原理上与 vue3 如出一辙, 但由于一些细小改动, 使得实际开发还是与 vue3 有一点不同
  • 尽管 frame3 是一个可正常使用(非玩具, 支持 ts)的框架, 但其更大的作用还是作为 vue3 的 mini 版本供开发者研究其原理
  • frame3 源码类型友好(几乎不用any), 每个函数都有 tsdoc, 部分有详细注释, 方便食用

体验

git clone https://github.com/gitborlando/frame3.git
cd frame3
pnpm install
cd example
npx vite

或者

在线 play ground

例子

size.ts

import { computed$ } from 'frame3'

export let size$ = 1
export let outOfBound$ = computed$(() => size$ >= 100)

export function setSize(s: number) {
  size$ = s
}

button.tsx

import { size$, outOfBound$, setSize } from './size'

export const Button = () => {
  return (
    <div>
      <div>{!outOfBound$ ? size$ : 'out of bound'}</div>
      <button onClick={() => setSize(size$ + 1)}>+</button>
    </div>
  )
}

疑问

相信看了上面的例子你肯定已经似懂非懂了. 写法上和 react 是一摸一样的, 然后从 api 上看得出一丢丢 vue3 的影子. 就是为啥:

  • 直接给变量赋值就能触发更新
  • 这满屏的带 $ 的变量是啥意思
  • 如果是基于 Proxy API, 为啥 import 不会丢失响应式

答案就是:

frame3 在编译时除了几种特殊情况, 会给每个带 $ 的变量加上一个.value, 除了:

  • 变量声明时不加
  • import, export 不加
  • 是对象的健时不加
  • .....等等其他情况

你以为用的是基本值, 其实它是个对象, 例如以上例子编译后会变为

// size.ts
import { reactive, computed } from 'frame3'

export let size$ = reactive(1)
export let outOfBound$ = computed(() => size$.value >= 100)

export function setSize(s: number) {
  size$.value = s
}

// counter.tsx
import { size$, outOfBound$, setSize } from './size'

interface IProps {}

export const Counter = ({}: IProps) => {
  return () => (
    <div>
      <div>{!outOfBound$.value ? size$.value : 'out of bound'}</div>
      <button onClick={() => setSize(size$.value + 1)}>+</button>
    </div>
  )
}

所以很明显, frame3 就是靠 Proxy API 来实现响应式的

而所有带$的变量, 不管是什么类型, 都会被编译成这样{ value: xxx }的对象

免得开发者手动加.value, 也不用担心任何 import 或解构赋值啥的会失去响应式的问题, 根本不用考虑 toRefs 等心智负担

CSS

你以为这就完了? frame3 甚至还能让 css 变响应式

div {
  width: ('70 * (size$ * 0.2 + 1.5)') px;
  height: ('20 * (size$ * 0.2 + 1.5)') px;
  border-radius: 5px;
  border: 1px solid rgb(0, 0, 0, 0.5);
}

frame3 也会编译组件引入的 css 文件, 会把每个带有(xx)或('xx')的声明 (xx 必须是合法的 js 表达式) 提取出来, 编译成类似这样

// 这是简化版
effect(() => {
  style.innerHTML = `
    .div {
      width: `${70 * (size$.value * 0.2 + 1.5)}` px
    } `
})

插入到组件代码中, 只要其依赖的响应式变量变了, 就会修改style标签内容, 实现样式更新.

其余部分仍保持原样不改动, 并且在编译过程中还会给每个选择器添加scope, 实现组件样式隔离

文档

Frame3 文档

指南

源码阅读指南 :

  • 阅读顺序: vnode.ts -> render-dom.ts -> component.ts -> reactive.ts -> scheduler.ts
  • 整个源码几乎没有行内注释, 而是由函数及类型声明上的 tsdoc 来替代
  • 阅读时可以将鼠标移到变量名上, 会很详细的解释这个变量或者函数有什么作用
  • 注: frame3 有些地方具体实现和 vue3 及各种 mini 版不同, 而变量命名则完全不同, 以及由于使用的是 jsx, 所以并没有模板编译部分, 不过这对理解 vue3 原理及其运行流程并无影响, 甚至可能更有帮助

框架使用指南 :

  • 首先yarn create vite创建一个空的原生 ts 的项目
  • 然后再yarn add frame3 vite-plugin-frame3
  • 在 vite.config.ts 里, 先import frame3 from vite-plugin-frame3, 然后在 plugin 里添加frame3()
  • 在 tsconfig.json 里添加"jsx": "preserve""jsxImportSource": "frame3" (这两个是对 tsx 进行编译和智能提示的)
  • api 的使用去看文档就行

初衷

之所以写这个框架, 是因为

  • 之前曾尝试直接看 vue3 源码, 发现根本看不懂(太多兼容性代码, 无从下手)
  • 于是转向一些专供研究的 mini 版, 发现少了兼容性代码, 流程上清晰许多
  • 但这些 mini 版本仍然是缺少有效注释(该注的不注), 各种any类型, 一运行 demo 就 bug 报错满天飞
  • 于是 frame3 就在这种环境下诞生了, 目的很明确, 就是: 至少能正常使用, 然后对 ts 类型友好, 尽量使代码好读
  • 但 frame3 显然不止于此, 正如上面例子, 它也有属于自己的特色(类 react 函数组件写法, 无需手动加.value, 响应式 css 等)
  • 这些特色可能会给开发者带来更友好的开发体验, 但肯定的是, 这些特色使得 frame3 成为 frame3, 而不是又一个 vue3 mini 版

最后

欢迎提建议, 当然如果你有什么不太重要的新项目, 可以试试 frame3 哦.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Packages

No packages published