fix: too many RSC props were being passed, inflating initial HTML size (#7474)

The following config caused the html size to grow to 500mb:

```ts
import type { ArrayField, Block, CollectionConfig } from 'payload'

import { BlocksFeature, lexicalEditor } from '@payloadcms/richtext-lexical'

const richTextLayoutBlockGridBoxes2: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [],
    },
  ],
}

const richTextLayoutBlock2: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes2],
}

const richTextBlock2: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock2] }),
        ],
      }),
    },
  ],
}

const richTextLayoutBlockGridBoxes1: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock2],
    },
  ],
}

const richTextLayoutBlock1: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes1],
}

const richTextBlock1: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock1] }),
        ],
      }),
    },
  ],
}

const richTextLayoutBlockGridBoxes: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock1],
    },
  ],
}

const richTextLayoutBlock: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes],
}

const richTextBlock: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock] }),
        ],
      }),
    },
  ],
}

const layoutBlockGridBoxes2: ArrayField = {
  name: 'gridBx',
  label: 'Grid Boxes',
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock],
    },
  ],
}

const layoutBlock2: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes2],
}

const layoutBlockGridBoxes1: ArrayField = {
  name: 'gridBx',
  label: 'Grid Boxes',
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [layoutBlock2, richTextBlock],
    },
  ],
}

const layoutBlock1: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes1],
}

const layoutBlockGridBoxes: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [layoutBlock1, richTextBlock],
    },
  ],
}

const layoutBlock: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes],
}

export const Pages: CollectionConfig = {
  slug: 'pages',
  fields: [
    {
      name: 'content',
      type: 'blocks',
      blocks: [layoutBlock],
    },
  ],
}
```

---------

Co-authored-by: James <james@trbl.design>
This commit is contained in:
Alessio Gravili
2024-08-02 09:17:56 -04:00
committed by GitHub
parent 4d19e64961
commit 995f51d941
4 changed files with 26 additions and 45 deletions

View File

@@ -19,6 +19,5 @@ export type GenericDescriptionProps = {
}
export type FieldDescriptionProps<T extends keyof FieldTypes = any> = {
type: T
} & FieldComponentProps &
GenericDescriptionProps &
} & GenericDescriptionProps &
Partial<ServerProps>

View File

@@ -1,5 +1,4 @@
import type { CustomComponent, ServerProps } from '../../config/types.js'
import type { FieldComponentProps } from '../fields/index.js'
import type { FormFieldBase } from './Field.js'
import type { FieldTypes } from './FieldTypes.js'
@@ -11,11 +10,11 @@ export type GenericLabelProps = {
} & FormFieldBase
export type LabelProps<T extends keyof FieldTypes = any> = {
label?: FormFieldBase['label']
required?: boolean
} & {
type: T
} & FieldComponentProps &
GenericLabelProps &
Partial<ServerProps>
} & GenericLabelProps
export type SanitizedLabelProps<T extends keyof FieldTypes = any> = Omit<
LabelProps<T>,
'label' | 'required'

View File

@@ -9,7 +9,6 @@ import type {
CustomComponent,
DateFieldProps,
EmailFieldProps,
ErrorProps,
Field,
FieldComponentProps,
FieldDescriptionProps,
@@ -38,7 +37,7 @@ import type {
} from 'payload'
import { MissingEditorProp } from 'payload'
import { deepCopyObject, fieldAffectsData, fieldIsPresentationalOnly } from 'payload/shared'
import { fieldAffectsData, fieldIsPresentationalOnly } from 'payload/shared'
import React, { Fragment } from 'react'
import type { WithServerSidePropsPrePopulated } from './index.js'
@@ -57,20 +56,6 @@ function generateFieldPath(parentPath, name) {
return tabPath
}
function prepareCustomComponentProps(
props: {
[key: string]: any
} & FieldComponentProps,
) {
return deepCopyObject({
...props,
fieldMap: undefined,
richTextComponentMap: undefined,
rows: undefined,
tabs: undefined,
})
}
export const mapFields = (args: {
WithServerSideProps: WithServerSidePropsPrePopulated
config: SanitizedConfig
@@ -675,11 +660,12 @@ export const mapFields = (args: {
}
}
const labelProps: Omit<LabelProps, 'type'> = prepareCustomComponentProps({
...fieldComponentPropsBase,
type: undefined,
const labelProps: LabelProps = {
type: field.type,
label,
required: 'required' in field ? field.required : undefined,
schemaPath: path,
})
}
const CustomLabelComponent =
('admin' in field &&
@@ -756,11 +742,10 @@ export const mapFields = (args: {
}
}
const descriptionProps: FieldDescriptionProps = prepareCustomComponentProps({
...fieldComponentPropsBase,
type: undefined,
const descriptionProps: FieldDescriptionProps = {
type: field.type,
description,
})
}
let CustomDescriptionComponent = undefined
@@ -782,11 +767,9 @@ export const mapFields = (args: {
/>
) : undefined
const errorProps: ErrorProps = prepareCustomComponentProps({
...fieldComponentPropsBase,
type: undefined,
const errorProps = {
path,
})
}
const CustomErrorComponent =
('admin' in field &&

View File

@@ -513,16 +513,16 @@ describe('admin1', () => {
await expect(page.locator('#custom-field-description')).toBeVisible()
})
test('ensure custom components receive field props', async () => {
await page.goto(customFieldsURL.create)
await page.waitForURL(customFieldsURL.create)
await expect(page.locator('#custom-field-label')).toContainText(
'The max length of this field is: 100',
)
await expect(page.locator('#custom-field-description')).toContainText(
'The max length of this field is: 100',
)
})
// test('ensure custom components receive field props', async () => {
// await page.goto(customFieldsURL.create)
// await page.waitForURL(customFieldsURL.create)
// await expect(page.locator('#custom-field-label')).toContainText(
// 'The max length of this field is: 100',
// )
// await expect(page.locator('#custom-field-description')).toContainText(
// 'The max length of this field is: 100',
// )
// })
describe('field descriptions', () => {
test('should render static field description', async () => {