Reference: "How TinyVue Component Library Implements Cross-Framework (Vue2, Vue3, React, Solid)?"
This article introduces the necessity and practical operation of a cross-framework component library. The title caught my interest, so I'll provide a quick review. I will quote the original article, and my understanding and thoughts will be marked as my own.
Background#
OpenTiny is a component library developed by Huawei, which includes TinyNG, TinyVue, TinyEngine, and other components.
The ability to output a unified set of component libraries and APIs that can be used across different technology stacks can enhance user confidence, increase development efficiency, and achieve consistent UI performance across different technology stacks. Additionally, it helps establish a reputation for your own component library and explore potential users.
Of course, there are challenges involved. It requires abstracting logic and smoothing out differences between different solutions.
This is the architecture diagram provided by the official source. The diagram and the article may not be very well-explained, but "Talk is cheap, show me the code." The article provides a GitHub repository demo that can help with understanding.
The article mentions two technologies or approaches, abstracted as follows:
- Common adaptation layer
- Renderless layer without rendering logic
For example, a tab menu or button can be divided into UI presentation and logic. UI presentation can be classified under the common adaptation layer, while inputs and outputs can be classified under the logic layer.
Technical Implementation#
Using pnpm + monorepo
to manage the component library.
Technical implementation approach:
Environment Setup#
Create a monorepo
environment.
Prepare different scripts, such as vue3
, vue2
, react
, solid
, and use micro-frontends to achieve management without boundaries.
Dependency Handling#
Some dependencies need to be differentiated between Vue2 and Vue3, so pnpm.packageExtensions
is used for differentiation, which is a usage I haven't seen before.
- The article gives an example of how to simultaneously support React and Solid. First, define
react-button
andsolid-button
. - Also, create the
packages/components/{platform}/common
folder. - Interestingly, the article mentions the purpose of the
ahooks
dependency, which is to provide reactive capabilities in React similar to Vue's reactive data. It's funny to see that: https://ahooks.gitee.io/zh-CN/hooks/use-reactive
- Solid itself is based on Signal and comes with reactivity.
- React uses
ahooks
to simulate reactive data. - Simulating Vue's
emit
. - Simulating Vue's
nextTick
.
The article provides an example of how to write React and Solid code, implementing emit
, useNextTick
, and useSetup
, where useSetup
returns the content of the render method.
Code is omitted.
Understanding Renderless Logic#
This part of the code can be divided into two parts:
- Framework-related entry functions
- Framework-independent pure functions
The article is not very clear, and after reading it several times, I'm still a bit confused. It may require practical implementation to fully understand.
Taking the button component as an example, it needs to implement the click event and the timer for disabling repeated clicks on different platforms.
For example, in the renderless approach, how to write code for React and Solid is similar. Both need to implement the renderless
method, which returns the state
and the methods that need to be referenced, such as handleClick
and timer
. Since this is the adaptation layer, it only focuses on defining common state and framework-related methods.
In the index
file, the framework-independent logic is implemented. Here, the handleClick
and timer
related logic is implemented.
For the button component:
- In
react.js
andsolid.js
, state management and click timer methods are implemented. - The specific implementation of click and timer is done in
index.js
using a framework-independent approach.
The general understanding of how the logic is implemented is as follows. Next is the UI presentation, which doesn't involve any black magic. It's just implementing the render method, but React and Vue both support JSX, so the logic is similar.
In the end, a demo example is provided, which makes it much clearer:
https://github.com/opentiny/cross-framework-component
Taking packages/components/react
as an example, this is the demo content of the React component library. You can see the common/src/index.js
file, which is used to simulate framework differences and define useSetup
. It also exists in Solid, Vue2, and Vue3.
Next, look at src/button/src/pc.jsx
, which defines the UI presentation of the button component.
These two files define the UI part. How is the logic part handled? Let's look at the following diagram:
Inside renderless/src/button
is the logic of the button component. The common part is placed in index.js
, and the adaptation part is placed in react.js
.
Continuing with the example, how is the button component defined in Vue? It is defined in both vue/button
and vue/common
.
Earlier, I mentioned micro-frontends, which is used to create a playground and display different framework effects on a single page.
This corresponds to the packages/home
directory. Here, the micro-frontend wujie
is used to embed different pages.
Outlook#
This demonstrates a design approach for components, abstracting and smoothing out differences.
Given the opportunity, further understanding can be achieved.