payloadcms / payload

The best way to build a modern backend + admin UI. No black magic, all TypeScript, and fully open-source, Payload is both an app framework and a headless CMS.
https://payloadcms.com
MIT License
21.1k stars 1.27k forks source link

Bug with Lexical Html converter including Fix #6962

Closed siccifolium closed 6 days ago

siccifolium commented 6 days ago

Link to reproduction

No response

Describe the Bug

Whenever a Lexical editor feature comes with a html converter, this converter is added to the default list of converters which lets the list of default converters grow infinitely. The problem are these lines of code: https://github.com/payloadcms/payload/blob/320dcc0a08eea35943d843df114651c0b5c9728e/packages/richtext-lexical/src/field/features/converters/html/field/index.ts#L29-L33 I assume the defaultConvertersWithConvertersFromFeatures is supposed to be a merged array of the default converters and the converters of the features.

The following line just assigns a reference to the global defaultHTMLConverters array: https://github.com/payloadcms/payload/blob/320dcc0a08eea35943d843df114651c0b5c9728e/packages/richtext-lexical/src/field/features/converters/html/field/index.ts#L29 So this loop here is effectively pushing the features html converters into the global defaultHTMLConverters array: https://github.com/payloadcms/payload/blob/320dcc0a08eea35943d843df114651c0b5c9728e/packages/richtext-lexical/src/field/features/converters/html/field/index.ts#L31-L33 This will result in an infinitely growing array of defaultHTMLConverters and steadily increasing request durations whenever the html converters have to be executed.

This problem can easily be fixed by just creating a new array and copying the defaultHTMLConverters with the spread operator like so:

const defaultConvertersWithConvertersFromFeatures = [...defaultHTMLConverters];

To Reproduce

Use a Lexical Richtext field and add a HTMLConverterFeature together with another feature which comes with a html converter, for example a BlockQuoteFeature.

lexicalEditor({
  features: [
    BlockQuoteFeature(), // Comes with a html converter
    HTMLConverterFeature(),
  ],
}),

Then observe the runtime of your collection requests. Each request will take longer because for every request the consolidateHTMLConverters function will be executed, which will add the html converter of the BlockQuoteFeature to the defaultHTMLConverters.

Payload Version

2.8.2

Adapters and Plugins

Lexical Richtext