There are three dominated front-end frameworks: Angular, Vue, React. All of those are good!
Angular is good just I don't like the class component, it's too heavy; React is good just I don't like the VDOM; I never used Vue.
So I try to create my own reactivity front-end framework, I think it's similar to Solid as like use Signal.
I implemented a simple, signal based reactivily library: dvorakjs
First, which component?
Which Component I want to use?
Not class component as like Angular, because it's to heavy as I said above. What about the file component like Vue, I would need a file with extension .vue
? No, I like the function component as like React.
For example a file named app.tsx or app.jsx
function App() {
return <div>This is a Function Component</div>
}
Yeap it's a smalllest component, I like this writing called jsx or tsx.
And how does that component works? Return a <div>
is illegal. That's because the compiler would convert it to some normal JS codes,
<div></div>
might convert to document.createElement('div')
.
We can did it by some compiler as like Babel or SWC.
SWC
SWC is an extensible Rust-based platform for the next generation of fast developer tools. We can use it to convert JavaScript/TypeScrpt and supperting jsx/tsx.
You can conveniently look into how SWC convert jsx/tsx to normal JavaScript: SWC playground.
Source jsx:
function App() {
return <div>Component</div>;
}
Convert to:
function App() {
return /*#__PURE__*/ React.createElement("div", null, "Component");
}
As you see above <div></div>
become React.createElement('div', null, "Component")
by default.
Also you can config it, use Dvorak
instead of React
. It's very simple, just need create a file named .swcrc
, and config it:
{
"jsc": {
"parser": {
"syntax": "typescript",
"tsx": true
},
"target": "es5",
"loose": false,
"minify": {
"compress": false,
"mangle": false
},
"transform": {
"react": {
"pragma": "Dvorak.createElement",
"pragmaFrag": "Dvorak.createFragment"
}
}
},
"module": {
"type": "es6"
},
"minify": false,
"isModule": true
}
The field transform - react
specified how to convert the jsx. So we can implement our own logic of Dvorak.createElement
, and that's I did.
How reactivity
Reactivity, the data in the view would be changed when we updated the data.
The Angular did that through binding variable, the React did that through VDOM. or like Solid used Signal
. I'll going to use Signal cause I don't like VDOM, Signal writting like below:
const [count, setCount] = createSignal(0);
const interval = setInterval(
() => setCount(count => count + 1),
1000
);
onCleanup(() => clearInterval(interval));
return <div>Count value is {count()}</div>;
It created a signal by createSignal
and it returns two variables count, setCount
, use count
into HTML, and while calling setCount
, the count
in HTML would update. I like this writting, so I declaring a function useSignal
, but how to implement it?
function useSignal<T>(default: T): [getter, setter] {
// ???
}
It just is a simplest publisher-subscriber partten, imagine the setter useSignal returned is a publisher, while we update the value by calling setter, every place we used getter in HTML would update the value, every place we used getter in HTML would subscribing the value.
How subscribing it? That is what the Dvorak.createElement
should do.
<div>{count}</div>
would be translated to Dvorak.createElement('div', null, count);
Attributes
The first of parameters of it, div
if element node name; the second is attributes, for example: name="name"
, id="theId"
, class="container"
; third are children, they are the rest parameters, so you can passing as like Dvorak.createElement('div', null, count, count2, count3);
Then we can let our function createElement
to subscribe the value. There are a couple situation: attribute, children.
If we need to reactive the attributes, like <div name={count}></div>
, it's easy, just simply bind the attribute value, and subscribe the publisher:
function createElement(nodeName, attributes, ...children) {
const ele = document.createElement(nodeName);
const attribute = attributes.find(t => t[0] === 'name');
let changeAttribute = () => {
ele.setAttribute('name', attribute[1]);
};
publisher.subscribe(changeAttribute);
}
The code above is just a demonstration for how a simple reactive do. A publisher observes a value, and changeAttribute
subscribes publisher, when publisher received a new value, it will notifies every subscriber as like calling the changeAttribute
, then would update the attribute of element.
What about the Children? Okay let's wrap a function reactiveChildren
for demonstration. Children of element have three situation, Text or element or function.
Children
If the child of element is a function that reactively, we will thought it's returns something we need, and it would be changed at any time. So we can just replace the old element to the new element.
And if is Text or Element it's static that means don't need update at any time.
function reactiveChildren(host, child) {
if (typeof child === 'function') {
let preNode = child();
host.appendChild(preNode);
let changeChild = () => {
let newNode = child();
host.replace(newNode, preNode);
preNode = newNode;
};
publisher.subscribe(changeChild);
} else {
// ...
}
You could see the function changeChild
do the replace node, and it subscribed the publish, so it would be notified while publisher received a new value.
Conclusion
So you can implement a simple, signal based reactively library.
柏老师nb
这篇博客介绍了作者自己创建的简单响应式前端框架,并对框架的核心理念进行了阐述和演示。博客中提到了三个主流的前端框架(Angular、Vue、React),并指出了它们各自的优点和不足。作者提到不喜欢Angular的类组件和React的虚拟DOM,因此决定创建自己的前端框架。
博客中介绍了作者选择使用函数组件的方式来创建组件,并举例说明了一个简单的函数组件的写法。作者还介绍了SWC这个工具,用于将jsx/tsx转换为普通的JavaScript代码。作者提到可以通过配置文件来自定义转换规则,例如将React替换为自定义的Dvorak。
博客接着讲解了响应式的实现方式,提到了Angular使用绑定变量,React使用虚拟DOM,而作者选择使用Signal。作者展示了如何使用Signal创建一个计数器,并通过调用setCount方法来更新计数器的值。作者还介绍了如何实现一个类似React的createElement函数,用于订阅和更新值。作者还讨论了如何处理组件的属性和子元素,并给出了相应的代码示例。
整体而言,这篇博客对作者自己创建的简单响应式前端框架进行了清晰的介绍和演示。博客中的代码示例和解释相对简洁明了,易于理解。作者通过比较不同前端框架的优缺点,选择了适合自己的方式来创建前端框架,这是一个很好的创新尝试。
然而,博客中可能存在一些改进的空间。首先,在介绍框架的核心理念时,可以更详细地解释Signal的工作原理和实现方式。其次,在代码示例中,可能需要更多的注释和解释,以帮助读者更好地理解每个步骤的作用和原理。最后,博客可以进一步扩展,例如介绍如何处理组件之间的通信、状态管理等其他常见问题。
总的来说,这篇博客是一个很好的创新尝试,作者展示了自己创建的简单响应式前端框架的核心思想和实现方式。希望作者能继续扩展和改进这个框架,并分享更多关于前端开发的经验和见解。
这篇博客介绍了作者自己创建的一个简单的响应式前端框架,并提到了一些主流的前端框架(Angular、Vue、React)。作者列举了自己对这些框架的喜好和不喜欢的地方,并决定创建自己的框架。博客中提到了一些工具和概念,如SWC、Signal和createElement函数,并给出了示例代码。最后,博客总结了如何实现一个简单的基于Signal的响应式库。
博客的闪光点是作者提出了自己创建响应式前端框架的想法,并展示了一些实现细节。这种创新和探索的精神值得赞赏。此外,博客中提到的SWC和Signal等工具和概念也为读者提供了一些有用的信息。
然而,博客中有一些可以改进的地方。首先,博客中的一些观点没有提供足够的理由或依据。例如,作者对于Angular的不喜欢只是简单地说"it's too heavy",但没有进一步解释为什么。这样的观点需要更多的支持和解释。其次,博客中的示例代码比较简单,没有涉及到更复杂的场景和用法。读者可能会希望看到更多实际应用的示例,以便更好地理解作者的想法和框架的潜力。
总的来说,这篇博客展示了作者的创新思维和对前端框架的独特见解。博客可以通过提供更多理由和示例来改进,以使读者更好地理解和应用作者的想法。