hybridsjs / hybrids

Extraordinary JavaScript UI framework with unique declarative and functional architecture
https://hybrids.js.org
MIT License
3.03k stars 85 forks source link

Convert a Whole Component to Web Component #263

Closed muhammadfaseehbinnaeem closed 1 month ago

muhammadfaseehbinnaeem commented 1 month ago

Hi,

I have a component 'MyComponent.js' having a lot of logic, states, hooks and functions in it. It also calls some common components in it. I want to make it a web component and want the tag 'my-component', so that I may be able to call it in index.html as . I am not finding a specific code snippet in the to do so. I have tried many things from the documentation of hybrids but my issue did not resolve. Can you please guide me how to make a tag and render a whole component through hybrids tag?

Qsppl commented 1 month ago

As far as I know, hybrids creates web components by default. Example: https://codepen.io/qsppl/pen/mdZRLwo

If I misunderstood the question, please clarify what you mean.

Qsppl commented 1 month ago

To import a component into an html file, simply import the script file in which the corresponding define(...) function was called:

<body>
    ...
</body>

<script type="module" src="/path/to/my-component.component.ts">
muhammadfaseehbinnaeem commented 1 month ago

I have a component e.g. MyComponent.js:

import React from 'react';
import ChildCompoent from './ChildComponent';

const MyComponent = () => {
    return (
        <div>
            <h1>My Component</h1>
            <ChildComponent />
        </div>
    );
};

export default MyComponent;

It may have some states, hooks, functions and may also include some child components in it. What I want is to access this whole component through a tag in index.html file. I don't want to use the code of hybrids for writing html part of this component i.e. I don't want to use the following code:

import { define, html } from 'hybrids';

export default define({
    tag: "my-component",
    name: '',
    render: () => html`
        <div>
            <h1>My Component</h1>
        </div>
    `,
});

I want a feature or any argument of hybrids in which I may pass my whole MyComponent, so that all of the logic in MyComponent will be rendered in hybrids i.e. something like following:

   import { define, html } from 'hybrids';
   import MyComponent from './MyComponent';

   ...
   render: () => <MyComponent />

I don't know the render syntax for this case but I hope you have understood what I want to do. Please suggest me something and please give me a code snippet of hybrids to do so.

Qsppl commented 1 month ago

@smalluban

Qsppl commented 1 month ago

I don't know how to integrate Vue/React/Angular/Spring/Next.js/Laravel/Yii or other frameworks into Hybrids/Lit/Stencil or other component libraries.

Usually they do the opposite - In legacy applications they integrate a component library into the framework: You can freely use components written in hybrids in your React code. You can also use events and \<slots>'s to enable interaction between React and components.

<!-- some code of view/component in your framework -->
<?php if (!empty($model->memberContactDataset)) : ?>
    <?= $this->render('@app/modules/...', ['model' => $model]) ?>
<?php endif; ?>

<hr>
<div style="background-color: white">
    <!-- hybrids web-component - you can control its state and track the various events it emits! -->
    <contact-comments required contact-id="<?= $model['id'] ?>" style="--bs-body-font-size: 11px;">
        <!-- some view/component code in your framework, inserted into the hybrids web-component slot -->
        <div class="col-md-1 mobiletable__hr">
            <a target="_blank" ...>
                <img style="width:18px;height:18px;" src="..." alt="" class="img-fluid">
            </a>
        </div>
    </contact-comments>
</div>

The modern MVVM-applications I work with are written without frameworks and use only WebAPI and one of the component libraries.

However, there is a much more experienced developer here - @smalluban. Most likely you should wait for his answer. Maybe a React component can actually be rendered by a hybrids component.

muhammadfaseehbinnaeem commented 1 month ago

Sure @Qsppl, will give it a try also. And waiting for @smalluban if he can guide me further in achieving what I am exactly looking for.

yaserarshad1 commented 1 month ago

@muhammadfaseehbinnaeem , @smalluban , @Qsppl I am facing the same issue did you guys find any solution to it because I don't see a proper solution. I have been reaching out to some guys from this repo on their personals, but I couldn't find a solution. I was following your issue since some time now, if you have found a feasible solution; pls let me know. The project I am working on is a big application but I think the solution might work if you got any. Thanks

smalluban commented 1 month ago

Before v9 it was officially supported and documented how to render React components inside the render property: https://github.com/hybridsjs/hybrids/blob/v8.2.23/docs/component-model/structure.md#custom-function

function reactify(fn) {
  // get the component using the fn and host element
  const Component = fn(host); 

  // return the update function
  return (host, target) => {
    ReactDOM.render(Component, target);
  }
}

const MyComponent = {
  tag: 'my-component',
  name: '',
  render: {
    value: reactify(({ name }) => <MyComponent name={name} />),
    shadow: false,
  }
};

From v9 the structure slightly has changed (the shadow detection moved to the template engine part), but still you can force it by setting shadow: ... option for the render property. The rest from the v8 version docs should be fine (use the above link).

The need is rare, and I think there are better solutions to make a React/Vue/... component a web component. Keep in mind, that hybrids can use any valid web component inside of the template, so you can use an external tool to make your React component a web component, and then use it with hybrids.