How should you write a good component and how do you integrate it with many view engines such as React, Angular and Vue?
Nowadays it is pretty common to have multiple applications written in different frameworks and libraries — that is the case with Trio, we have React and Angular applications as well as Vue. We understand how hard it is to maintain consistency between components, libraries, and even useful functions across apps. It’s even harder task to do this with different view engines like a React App or an Angular App, right?
p.s. for a better readability experience I’m using the word ‘view engine’ to represent ‘UI frameworks and libraries’.
So… why should I write a VanillaJS component instead of just writing one for each different view engine?
There are scenarios where you and your teammates should build the exact features across different view engines. If you encounter these scenarios, consider using these three distinct approaches:
1) To write different render packages for each view engine
This approach is all about you writing different packages even if they’re similar or even the same.
That’s when we have to stop and think… if we’re looking for easy maintainability, this is absolutely not the right path because you’ll have to deal with different packages with duplicated lines of code.
e.g. Let’s pretend that you have to write a Video Player component for React, Vue, and Angular. You’ll end up maintaining three packages… one for each different view engine.
Real World Sample
Take a look at this React package’s file and also take a look at these lines of the Vue’s version… that’s what I meant when I said that you’d probably end up with duplicated lines of code. Both of them implemented a Full Screen feature.
2) To write a Core VanillaJS package + different render packages for each view engine
I know that, at first, this approach seems weird but it’s interesting especially if you have some lines of code beyond rendering (e.g. helpers functions).
If you do have some logic to share between the view engines, that’s a better approach than the first one when we think about maintainability, because even if you have to maintain a core package and one package per view engine, it is valuable since you wouldn’t have duplicated lines of code which makes it easier for changes affect all view engines at once.
In order to implement this approach, make sure to follow these steps:
- Write a Core package which contains shared code between the view engines;
- Write a render package for each of the different view engine and make use of the Core package when needed.
When using this approach, just make sure to strictly follow a versioning flow (e.g. semantic versioning) to avoid breaking code without awareness.
Real World Sample
It has several packages that depend on and compose each other.
This is an excellent sample because this component currently supports two different view engines (React and Vue) and it also has a really nice sub-packages organization. They compose each other… I love this repo. 😌
3) To write a render VanillaJS package and integrate it with different view engines through wrapper packages
This approach aims to have a view engine agnostic core. In other words: it has its own render logic and works without any view engine dependency.
It could be a good catch if your component doesn’t have too much rendering complexity because you’d have to write it on your own without the help of view engines.
By using this approach, you’ll likely have:
- Core package which is responsible for the Vanilla rendering;
- Wrapper packages for each different view engine that use the Core package in order to render the component.
Real World Sample
We got a really nice sample about this approach: Final Form.
Like its description says: it’s a “Framework agnostic” component because it handles rendering logic just by itself. I really like this project because it handles the logic of when the form should be rendered but not DOM mutations… it’s up to you.
Final Form has a really great API documentation 😍. All public methods are very well described.
Another amazing thing is that they’ve got the same samples:
And to prove that they don’t actually handle DOM mutations… they got a VanillaJS sample: