WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
9.99k stars 4.01k forks source link

Better integration with Web Components #49814

Open tronicboy1 opened 1 year ago

tronicboy1 commented 1 year ago

What problem does this address?

What is your proposed solution?

Create a template that allows users to build Gutenberg plugins in a framework agnostic approach.

tronicboy1 commented 1 year ago

I have experimented quite a bit with this and have a working model with Vite compiling web components written in TypeScript.

https://github.com/tronicboy1/todo-api-block

I think creating a native JS template (without Lit or TS as above) would be a great way to open the doors up for developers to use Web Components.

tronicboy1 commented 1 year ago

To be honest, my motivation for this issue is largely disapointment in the fact that Gutenberg almost forces you to adopt React to implement blocks.

React has a host of performance issues that should not be ignored when trying to make accessable pages to underpowered devices, which WordPress has historically been the go to CMS for.

I also think we should have an opt out for people who do not want to include it in their bundles. Load speeds mean everything for a lot of us ecommerce developers and being forced to add React and React DOM packages to our initial bundle size is a big problem when we go to optimize.

Mamaduka commented 1 year ago

Thanks for the proposal, @tronicboy1,

Blocks using Web Components could eliminate the need for React packages to be downloaded in the view, offering page load performance improvements for users

Do you mean the visitor-facing part of a page or the editor itself?

cc @gziolo, @swissspidy, if I recall correctly, you've experimented with using web components in the block editor.

tronicboy1 commented 1 year ago

@Mamaduka Thanks for the reply!

Do you mean the visitor-facing part of a page or the editor itself?

I mean in the view.

I think the biggest hurdle to using Web Components is getting the editor attributes to integrate well with react.

I tried a work around where I can get the attributes to be set directly to the element to be consumed in the Web Component. I also added the setAttributes function as a property of the Web Component, which allows us to feed data to the editor from the Web Component's input.

However, you cannot select the Web Components element as below because it is not necessarily rendered when we run createElement, and React gives us no way to know when it is actually rendered.

function registerBlock(blocks: WpBlocks, element: WpElement, blockEditor: BlockEditor) {
  const { createElement } = element;
  blocks.registerBlockType("create-block/todo-api-block", {
    edit: ({ attributes, setAttributes }) => {
      const blockProps = blockEditor.useBlockProps();
      const reactEl = createElement("wc-demo", 
          // Add attributes to the element directly, this works pretty good actually
         { ...blockProps, ...attributes, edit: true },
       "");
      // this is null first time around, react doesnt actually create it until after the first round
      const el = document.querySelector(tagName);
      if (el) {
        // allow the web component to set attributes, ie add user input in edit mode
        el.setAttributes = setAttributes;
      }
      return reactEl;
    },
    save: ({ attributes }) => createElement("wc-demo", attributes, ""),
  });
}

Sometimes I get a mismatch error with the attributes but this may be unrelated.

Screenshot 2023-04-15 at 7 27 35
tronicboy1 commented 1 year ago

My attempts feel much more like a hack rather than a solution 😅

swissspidy commented 1 year ago

You might want to check out https://felix-arntz.me/blog/leveraging-the-power-of-custom-elements-in-gutenberg/ and especially https://github.com/facebook/react/issues/11347. Right now React doesn't have great support for web components (custom elements), but this is set to change with React 19.

tronicboy1 commented 1 year ago

@swissspidy That is a great article and my thoughts are exactly the same. If only there were a simpler process in accessing the props and component update callback in custom elements!

If we could check whether or not the provided tag in createElement was for a custom element or not, we could then assign the props and callbacks for Gutenberg as properties to that element on render.

I do not think it would be that hard to implement, you would have to use a React ref to get access to the actual custom element though.

Right now React doesn't have great support for web components (custom elements), but this is set to change with React 19.

I wouldn't bet your money on that! They have been promising better interoperability for a very long time with no results.

tronicboy1 commented 1 year ago

Here's a better example.

https://github.com/tronicboy1/wc-attributes-demo/tree/master/src

If only we could somehow define the setAttributes callback when react renders it, not when I patch it in after react happens to render it and re render.

mhsdef commented 2 months ago

It's official.

Custom element support is gonna land in React 19.