seed-rs / seed

A Rust framework for creating web apps
MIT License
3.8k stars 153 forks source link

Web Components support #336

Open MartinKavik opened 4 years ago

MartinKavik commented 4 years ago

Hey guys, I'm thinking about implementing first-class support for not-only-Rust Web Components. Before I write some reasoning about it I would like to know your opinions and experience. So.. what do you think?

TatriX commented 4 years ago

Makes perfect sense to me. If I can reuse existing components easily, I can get results faster. This property is crucial for decision making in commercial projects.

MartinKavik commented 4 years ago

@TatriX do you any experience with them?

rebo commented 4 years ago

So as mentioned on discord I think in theory this could be a great idea however the interop between seed infrastructure and a Web Component would need to be carefully thought through.

I.e. what api will seed expose to web components and what will it hook into. For instance will connectedCallback and attributeChangeCallback trigger seed messages etc. If so could this fall into the same inconsistent problems that virtual dom diffing triggering lifecycle hooks have?

So in short a good idea but needs careful thought.

David-OConnor commented 4 years ago

I can't comment at this time, due to not being familiar with Web Components.

MuhannadAlrusayni commented 4 years ago

It would be great to have this functionality, especially Shadow Dom which would allow using CSS animations/selector without relying on CSS files, thus making very dynamic components.

MartinKavik commented 4 years ago

@David-OConnor In a nutshell:

David-OConnor commented 4 years ago

Thank you for the detailed explanation

mkroehnert commented 4 years ago

Hi @MartinKavik I would be interested in generating webcomponents with Seed. ~~Since @rebo mentioned discussions on discord, I wanted to know where I can find them. Unfortunately, there is no link or mention on the seed.rs webpage or Github repo.~~ Edit: found the link in #303 after skimming through open issues. Would it make sense to make the channel more public or do you still want to wait to see if discord is the right choice?

Since I have a small personl project in which I used webcomponents and one where I would like to use them, I could at least do testing, if time permits.

MartinKavik commented 4 years ago

Ad chat - https://github.com/seed-rs/seed-rs.org/issues/22

MartinKavik commented 4 years ago

I did some research about implementation and found a blocker - wasm-bindgen isn't smart enough (yet) to create a necessary bridge between the Rust and JS world to create custom elements.

Unfortunately I don't have enough free time to help them to add needed support. So I have to stop working on this issue until wasm-bindgen is improved or I have a generous sponsor 💰

So.. you can use JS/TS components at the moment, but they are reconnected on each DOM render and not very tested. We/I'll add better support once the blocker above is resolved and I can write a library for creating custom elements.

lastmjs commented 4 years ago

IMO, I think it would be wise to consider exposing the base web components APIs as directly as possible, starting with an focusing on the custom elements API. A Seed component should be an HTML custom element. It should have all of the lifecycle methods of a custom element. It should be a DOM object under the hood. Any conveniences, like automatic getters and setters, can be built on top. This is what I would love to see.

MartinKavik commented 4 years ago

@lastmjs If I understand you correctly - that's the plan. You would be able to use custom elements as black boxes - it's not important if they were written in/with VanillaJS, Typescript, Rust, LitElement, etc. The next step would be to create our web component API wrapper/library - so you can reuse your Seed knowledge (e.g. write HTML with Seed macros) and it's not as painful as writing custom elements with the original API.

lastmjs commented 4 years ago

Sounds pretty good then. Though, there are only a few major pain points with the raw custom elements API, IMO. Having a templating library with data binding to properties and event handlers, and automatically rendering when attributes or properties change. I use vanilla custom elements, extending directly from HTMLElement in JavaScript/TypeScript. Using a simple templating library like lit-html and some state management like Redux makes writing custom elements simple and elegant. I suppose my point is, I don't think you need to do much over the custom element APIs.

I also think it would be important to expose the entire custom element API just in case the developer needs access to it. I would still love to be able to hook into connectedCallback and create my own getters and setters

akhilman commented 4 years ago

https://hybrids.js.org/ does nice job to wrap custom elements with functional API.

import { html, dispatch } from 'hybrids';

function change(host) {
  host.value += 1;
  // Trigger not bubbling `change` custom event
  // Element user can subscribe to this event with
  // `el..addEventListener('change', callback)
  dispatch(host, 'change', { detail: host.value }); 
}

const MyElement = {
  // This `value` becomes an attribute of the custom element.
  // When the user of the element sets new value, 
  // the system calls `render` function with a new value.
  value: 0, 
  render: ({ value }) => html`
    <button onclick="${change}">You clicked me ${value} times!</button>
  `,
};

Receiving attributes from the user could be done as a method for the application builder Builder::handle_attribute(Builder, Fn(String, Strung) -> Ms) where the first argument is the attribute name and the second is the value. And dispatch could be added to Orders trait.