WordPress / gutenberg

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

Gutenberg as a framework: streamline the experience #53874

Open youknowriad opened 1 year ago

youknowriad commented 1 year ago

Gutenberg can be used as a platform/framework to build block editors. Mainly thanks to the @wordpress/block-editor package. That said, the experience today is not as straightforward as it can be. There can be a lot of small gotchas and hacks you need to do in order to achieve the desired result. This issue is going to serve as an overview issue to collect and fix all these issues.

cc @WordPress/gutenberg-core

spencerfinnell commented 1 year ago

https://github.com/Automattic/isolated-block-editor/ is likely a good indicator of the additional scaffolding currently needed to use Gutenberg in a more isolated environment.

https://github.com/WordPress/gutenberg/discussions/46693 has discussions about the potential advantages of reducing the footprint needed to utilize Gutenberg/WordPress packages.

mtias commented 1 year ago

Thanks for starting this!

andrewserong commented 1 year ago

+1 thanks for writing this up!

Block supports and server side rendering: A lot of recent features of the block editor (theme.json and block supports) rely on server side rendering to generate the frontend styles, even for static markup and static blocks.

It could be good to break this out into a separate issue, but just adding a couple of thoughts and previous discussions for this one:

Can we solve this by introducing a "styles engine" that has two implementations: one on the server, one on the client. The client implementation is opt-in (used in the editor and also can be used by third-party block editors to render their blocks as needed), the server implementation is preferred for the frontend in WordPress. (From https://github.com/WordPress/gutenberg/discussions/37495)

From those discussions, it sounded like dynamic injection was preferable for a few reasons:

Those discussions also raised the downside that 3rd party editors would need their own approach for outputting dynamic styles. So, it's good to raise that here. I like the idea of a canonical approach for 3rd party editors to "switch on" rendering output of block supports in some way via a render function.

Overall, is the goal to still move toward a state where styles are all generated dynamically, or is it more of a case-by-case scenario depending on the kind of block supports we're designing/working with?

Provide a way to generate the final HTML including styles (some kind of render function) that can be used by third-party editors.

In terms of how we define when to dynamically inject styles, would a potential solution be to have a boolean flag somewhere, where we flag whether or not to output at render time? Some block supports (e.g. layout and elements) in JS are hooked in to output only within BlockEdit, so I imagine there'd need to be an API of some kind for these block supports, so that they can be supported in both contexts (edit and "JS render" 🤔)

youknowriad commented 1 year ago

@andrewserong Please go ahead with the issue, we can link to it from here. I agree that this deserve its own issue. At the moment, I didn't give too much thoughts and I'm not too opinionated. All what I can say is that we should provide third-party editors with a way to retrieve the final HTML for these static blocks (paragraph, headings....) including all the block supports that are not really dynamic (don't depend on any server-side stored value). I don't think the decision to store the styles inline or not need to change, it's fine we're opinionated there per block support but third-party editors (JS only) should be able to render the posts properly without writing PHP and just calling a function we provide.

ellatrix commented 1 year ago
  • The block-library package provides a set of core blocks to be used by third-party block editors. The problem is that the package doesn't make a distinction between WordPress specific blocks and generic blocks. And even for generic blocks, there might be WordPress specific features. Find a way to clarify which blocks are generic and independent of WordPress and which are not, provide a way for platforms to provide platform specific behaviors on top of core blocks.

I wonder if each block should be its own package. That's what I was considering for footnotes at first. CKEditor for example does this: https://ckeditor.com/docs/ckeditor5/latest/api/paragraph.html

andrewserong commented 1 year ago

Please go ahead with the issue, we can link to it from here.

Thanks for the extra context @youknowriad! I've opened up a separate issue for this in #54047 and linked it in the issue description. Feel free to edit as needed 🙂

gziolo commented 1 year ago

I wonder if each block should be its own package. That's what I was considering for footnotes at first. CKEditor for example does this: https://ckeditor.com/docs/ckeditor5/latest/api/paragraph.html

It’s already possible to import individual blocks which isn’t that far from as if they were in separate packages and it’s documented in:

https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library#registering-individual-blocks

youknowriad commented 1 year ago

@gziolo oh that's really cool, I missed that I think. it would be cool to have a dedicated entry point in block-library that is for universal blocks only (blocks that don't require server side code to work fully).

youknowriad commented 1 year ago

@ellatrix for the typewriter mode, I decided not to bundle it for now. I hesitated about whether I should add a flag to enable it in BlockCanvas. It's still an option at some point if there's demand for it but for now, I left it as an optional external hook you may decide to apply. There's also an extra padding (40vh) that is added when the typewriter mode is enabled that could also be added automatically if the flag is set to true.

tellthemachines commented 1 year ago

Rendering the block editor requires including the stylesheets of a couple packages at least (@wordpress/components and @wordpress/block-editor) even if we're not directly depending on one of these packages (components).

Not sure I understand, components is a dependency of block-editor, right?

The block-library package provides a set of core blocks to be used by third-party block editors. The problem is that the package doesn't make a distinction between WordPress specific blocks and generic blocks.

Even if we distinguish between WP and generic blocks, block-library has core-data as a dependency so anyone installing it will get that bundled in. Perhaps we could have two packages instead? like generic-block-library and wp-block-library?

youknowriad commented 1 year ago

Not sure I understand, components is a dependency of block-editor, right?

Yes, but when you do import something from '@wordpress/block-editor' the CSS produced by @wordpress/block-editor or @wordpress/components is not imported automatically. That's one of the reasons most UI libraries use CSS in JS instead of shipping separate CSS files.

Our packages do ship CSS files but the consumer has to include them manually https://github.com/WordPress/gutenberg/blob/1cfad2ca1744e8aea15b0d517fbf8e73a509b713/platform-docs/docs/intro.md?plain=1#L83-L90

Even if we distinguish between WP and generic blocks, block-library has core-data as a dependency so anyone installing it will get that bundled in. Perhaps we could have two packages instead? like generic-block-library and wp-block-library?

Yes that's one option, that's the work we need to do: rule out all WP specific dependencies and potentially have a way to "augment" the blocks that are "mixed". In the sense that some blocks are in general "universal" but when they are used within WordPress, they need to check the post or something, so we need to figure out if we can have a way to filter/extend/augment these blocks in the wordpress specific package.

youknowriad commented 1 year ago

Status update:

There's a lot of remaining work though (and some big undertakings). These are the things I'd love if we could tackle next:

Any help with these things would be highly appreciated.

xstaticwebdev commented 1 year ago

@spencerfinnell asked me to comment on this, so here's my two cents. First of all I'm not a WordPress developer so I'm not intimately familiar with the Gutenberg/WordPress architecture and I don't know the technical limitations therein. As a consumer of "WordPress as a service" I really just need 3 things:

1.) The HTML blob that is generated by the block editor for a given post. This is already available using the rest api. 2.) The css blob that corresponds to the post, ideally minified. As a nextjs user I can then dump the css blob into a styled jsx block and the content will be displayed just as it would be in native WordPress. Other frameworks would have something similar to styled jsx. 3.) The javascript blob associated with a given post. Some blocks could rely on Javascript so the ability to ship that to the front end to run seems important. Yes, this is a little messy, but I'm not sure what other alternatives would be.

So an api route that returns something like this would be ideal:

post: { html: {"

.....
"}, css: {"body:{......}"}, js: {"document.QuerySelector......"} }

I'm not at all sure that this is possible, but it would make building headless sites with WordPress super easy. I'd be willing to test any implementation if/when available.

youknowriad commented 1 year ago

@xstaticwebdev Thanks for the feedback. To clarify a bit, the issue here is not necessarily about Headless WordPress. It's a bit of tangent. It's about using Gutenberg as a framework to integrate to any application or CMS. I'm certain that a lot of work here can help a bit with Headless WordPress but I do believe your use-case deserves a dedicated issue.

It's true that it's not clear at the moment how to retrieve the rendered HTML + CSS + JS using a REST API in WordPress. I'm not sure it will ever be, because a lot of hooks depend on the URL and context that is not always possible to pass to the REST API but at least it's worth exploring.

kohheepeace commented 1 year ago

Hello, In relation to this issue, I thought it would be helpful if a list of required API endpoints and expected return values were documented for core blocks.

*I am currently trying to get gutenberg to work in a ruby on rails environment.

For example, core/embed block needs /oembed/1.0/proxy endpoint which returns oEmbed json response.

I struggled with other issues related MediaUpload which needs to return a value in the appropriate json format after successfully saving an image for core/image block.

And I'm currently tackling to implement reusable blocks, I need to define GET /wp/v2/blocks/<id> and return the record in the appropriate json format.

Anyway, thank you very much for working on making gutenberg usable as a framework. There are countless wysiwyg editors, but I don't think there is any other wysiwyg editor that is so practical as a "site builder" than gutenberg.

youknowriad commented 1 year ago

@kohheepeace oh that's a big undertaking, it's exciting to see where you can take this. While the current issue is about the reusability of the "block-editor" package, I do think we need to tackle the reusability of the "editor" package at a more global level at some point. Which means relying on the "core-data" package as an API abstraction. I'd love if we can at some point offer an official API to build an "adapter" for the "core-data" to connect it within API for persistence (another REST API for instance)

kohheepeace commented 1 year ago

I'd love if we can at some point offer an official API to build an "adapter" for the "core-data" to connect it within API for persistence (another REST API for instance)

=> I can't picture it clearly now, but I'm looking forward to it 👍.

Additionally, along with this, there is another a bit troublesome task: the generation of the global-styles.css and settings.json from the theme.json.

Currently I create theme.json (+ patterns in patterns/ etc...) , then run wp-env start to start wordpress environment and run wp.data.select('core/editor').getEditorSettings() in Chrome Devtools's console to get settings.json and search global-styles css from Element tab.

I hope this process become easier (maybe JS equivalent of WP_Theme_JSON_Resolver or cli ?) 👍

*sorry for my greed to request out-of scope.

youknowriad commented 8 months ago

Status update: We now have a temporary location for the Gutenberg as framework website where we can iterate on.

As discussed here https://github.com/WordPress/wporg-main-2022/issues/379 we might want to move this to wordpress.org/gutenberg ultimately.

mrfoxtalbot commented 7 months ago

Noting that @growthwp's comment is somehow related to this other discussion on how to handle iframes https://github.com/WordPress/gutenberg/issues/59926

youknowriad commented 7 months ago

We have a question in regards to the (lack of?) Iframe component, since you can now use shouldIframe - moving forward, does the team wish to abandon the "iframe container"?

There's no intention of abandoning the iframe container. It's kind of the opposite shouldIframe default to true and it's a private API because we want most block editors to always use the iframe.

youknowriad commented 7 months ago

No problem at all, I am happy to answer questions and clarify what needs to be clarified :)

vonloxx commented 4 months ago

Finally I'm doing the refactoring for the whole Drupal Gutenberg using this framework. The first step is to set it up and check if pretty much all functionality we had from the edit-post component is there (only in terms of the editing experience).

From my initial implementation (following the documentation), here's some issues I'm having:

If anyone has any tips to help solve those issues I would appreciate it 😉 Btw, I'm using the branch wp/6.6.

cc/ @youknowriad

youknowriad commented 4 months ago

@vonloxx Thanks for the comment, Do you think it would be possible to have a codesanbox or something like that with an isolated block editor to be able to reproduce and isolate some of these more easily.

youknowriad commented 4 months ago

A request is made to /wp/v2/types?context=view&_locale=user. Is it necessary?

This seems to be related to the footnotes. I left a comment on #51201 with a potential fix.

youknowriad commented 4 months ago

Any way that the iframe auto resizes (height) according to the content?

Did you consider a 100% height instead? to avoid double scrollbars...

vonloxx commented 4 months ago

Any way that the iframe auto resizes (height) according to the content?

Did you consider a 100% height instead? to avoid double scrollbars...

I ended up resolving using a component with a resize observer (and mutation observer). It simply observes the content height of the iframe's body and set the iframe's height accordingly. It works great ;) Btw, this functionality is for when the editor is used as an isolated editor (like CKEditor/TinyMCE). For the full UX experience like edit-post, yep, we'll use a 100% height.

stokesman commented 4 months ago

I ended up resolving using a component with a resize observer (and mutation observer). It simply observes the content height of the iframe's body and set the iframe's height accordingly. It works great ;)

It’s a bit of a digression but I'm curious about this. Is the mutation observer used to limit the responses to the resize observer? I ask because trying to size an iframe by its content’s height tends to create infinite loops when heights of any contained elements depend on vh units.

vonloxx commented 4 months ago

@stokesman Actually adding two mutation observers, one for the closest container of the iframe (to wait for the iframe) and when the iframe is found, disconnect the observer and another observer is added to the iframe to look for the body when available. After the body is found, I add the resize observer to the iframe's body and disconnect the last mutation observer. I didn't try with elements with vh units tho 🤔