payload icon indicating copy to clipboard operation
payload copied to clipboard

feat(live-preview): support blocks with relationships inside richtext lexical for client side preview

Open andershermansen opened this issue 10 months ago • 6 comments

What?

This PR adds support for blocks with relationships inside richtext lexical for client side preview. Currently blocks are filled with the data that is available, but relationships are not resolved and filled. This is causing missing relationship data in those blocks in client side live preview of richtext.

Before

before

After

after

How?

Inside payload package:

  • I added richtext blocks definition to clientconfig, I could not see this exported to client side anywhere else. I'm not sure if this is the best way to extract or expose this info, so would like feedback on this.
  • Also added blocks info to richText field in fieldSchemaToJSON so it's usable by live preview.

Inside live-preview package:

  • In the traversal of richtext, hook in so that it uses traverseFields for the blocks. Using the config that was exposed above. I'm a bit unsure about the block itself where I just added the version and type, so would like feedback on this.

Inside test live-preview:

  • Just hooks up the MediaBlock to the lexicalEditor and the serializer for it.

Fixes #5285

andershermansen avatar Feb 11 '25 08:02 andershermansen

@GermanJablo Thanks for looking into this. I fixed the build errors after the merged and tested it manually. Still working.

I created #12167 to try to prepare for integration tests of this feature. Maybe it should be merged into this PR and then work on the tests here?

andershermansen avatar May 16 '25 20:05 andershermansen

Thanks to you @andershermansen. This is a challenging issue!

Inside payload package:

  • I added richtext blocks definition to clientconfig, I could not see this exported to client side anywhere else. I'm not sure if this is the best way to extract or expose this info, so would like feedback on this.
  • Also added blocks info to richText field in fieldSchemaToJSON so it's usable by live preview.

Inside live-preview package:

  • In the traversal of richtext, hook in so that it uses traverseFields for the blocks. Using the config that was exposed above. I'm a bit unsure about the block itself where I just added the version and type, so would like feedback on this.

We can be sure that the serialized blocks are already being passed to the client somehow, since they're used there. After investigating, I found this is happening with BlocksFeature, which passes the serialized blocks to BlocksFeatureClient. If we also pass the blocks to RichTextFieldClient, as you're doing now, we'd be duplicating the content that the server has to process and send to the client. How to get the serialized blocks on the client requires further investigation. We probably have a provider that does that. From what I've been seeing, it might be useEditorConfigContext or FeatureProviderClient.

I created https://github.com/payloadcms/payload/pull/12167 to try to prepare for integration tests of this feature. Maybe it should be merged into this PR and then work on the tests here?

I'll review that PR shortly to get a better answer.

GermanJablo avatar May 19 '25 15:05 GermanJablo

@GermanJablo I merged in latest main and added an integration test. It does not pass as the result in the fields is undefined. It still works when running dev, but not in integration test. Have not yet investigated why. I just thought it was good to add that integration test anyway.

andershermansen avatar May 23 '25 06:05 andershermansen

Were you able to read my previous comment? There's a problem with the PR approach.

GermanJablo avatar May 23 '25 14:05 GermanJablo

Were you able to read my previous comment? There's a problem with the PR approach.

I read it, but I do not fully understand it. Need to read up more on the code you referenced and debug more to understand how it works.

As I wrote in the initial comment on this PR this was not code ready to merge, as I was very unsure on how to do this. So appreciate your feedback so far and will look more into it.

andershermansen avatar May 23 '25 16:05 andershermansen

Ok! If it helps, a simpler tldr:

BlocksFeature already sends the serialized blocks to the client. We need to find a way to access them on the client without sending them again from somewhere else.

GermanJablo avatar May 23 '25 16:05 GermanJablo

@GermanJablo I took another approach in the latest push in this PR. I used the global blocks config and converted that to a blocksMap, it's sent it once same way as the full fields definition (fieldSchemaJSON) is sent. This way the richtext traverser can use all global defined blocks introduced in #10905

This PR then solves this for blocks defined in global blocks and used in lexical, but not blocks defined directly in the BlocksFeature. That is at least better than current situation. Please have a look and let me know what you think.

andershermansen avatar Aug 15 '25 11:08 andershermansen

Thanks again. Solving the problem for global blocks is a step forward.

Yay :smile:

My hypothesis is that the generic solution should use featureClientSchemaMap (passed in useEditorConfigContext), although I don't know how prop drilling would work here, since neither the ui nor live-preview packages have richtext-lexical as dependencies. Were you able to explore anything about featureClientSchemaMap? It seems to have information for every block in every editor.

featureClientSchemaMap has the information needed yes. You can see it's used here to create a map like the one we need: https://github.com/payloadcms/payload/blob/36fd6e905a002b203c9e7e9202f57db4dc5dddad/packages/richtext-lexical/src/features/blocks/client/index.tsx#L48-L56

But what you are mentioning is what I do not know how to solve. How to connect the dot's between the featureClientSchemaMap and the LivePreviewWindow which needs it.

andershermansen avatar Aug 20 '25 19:08 andershermansen

We're exploring a different way to solve this here: https://github.com/payloadcms/payload/pull/13619

Manually traversing and populating fields like this is only a short-term solution and will be a pain to maintain. This approach still has holes, e.g. custom link drawer fields won't be populated. Any additional functionality we add in the future which requires population would also require us to adjust this live-preview code - we'd be playing whack-a-mole.

We already handle populating relationships correctly, for all our fields including richtext - this happens in the findByID operation where we run hooks.

The idea behind the new approach is to use that existing endpoint to correctly populate our data. That way the population is faster (1 single request), and we can get rid of all custom code required to populate data on the client. Additionally, this allows us to support running hooks within live preview. This means the lexicalHTMLField will now be supported in client-side live preview!

AlessioGr avatar Aug 27 '25 23:08 AlessioGr

Closing in favor of #13619. Thanks a lot for the effort put in here @andershermansen !

GermanJablo avatar Sep 01 '25 19:09 GermanJablo