Open tronicboy1 opened 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.
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.
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.
@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.
My attempts feel much more like a hack rather than a solution 😅
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.
@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.
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.
Custom element support is gonna land in React 19.
Building gutenberg blocks with Webcomponents would be the final step to create a developer friendly way.
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.