📦 esbuild Bundle Analysis for payloadThis analysis was generated byesbuild-bundle-analyzer. 🤖 | Meta File | Out File | Size (raw) | Note |
|---|
| packages/next/meta_index.json | esbuild/index.js | 950.94 KB | ✅ No change | | packages/payload/meta_index.json | esbuild/index.js | 1.32 MB | ✅ No change | | packages/payload/meta_shared.json | esbuild/exports/shared.js | 168.55 KB | ✅ No change | | packages/richtext-lexical/meta_client.json | esbuild/exports/client_optimized/index.js | 277.34 KB | ✅ -4.44 KB (-1.6%) | | packages/ui/meta_client.json | esbuild/exports/client_optimized/index.js | 1.18 MB | ⚠️ +222 B (+0.0%) | | packages/ui/meta_shared.json | esbuild/exports/shared_optimized/index.js | 16.32 KB | ✅ No change |
Largest pathsThese visualization shows top 20 largest paths in the bundle.Meta file: packages/next/meta_index.json, Out file: esbuild/index.js| Path | Size |
|---|
| ../../node_modules | ${{\color{Goldenrod}{ ████████████████████▌ }}}$ 82.3%, 779.13 KB | | dist/views/Version | ${{\color{Goldenrod}{ █▎ }}}$ 5.4%, 51.27 KB | | dist/views/Dashboard | ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 17.16 KB | | dist/views/Document | ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 16.59 KB | | dist/views/List | ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 11.38 KB | | dist/views/Root | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 9.03 KB | | dist/views/Versions | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 6.16 KB | | dist/views/API | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 6.08 KB | | dist/elements/Nav | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.96 KB | | dist/views/Account | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 5.54 KB | | dist/elements/DocumentHeader | ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.81 KB | | dist/views/Login | ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 4.40 KB | | dist/views/ForgotPassword | ${{\color{Goldenrod}{ }}}$ 0.3%, 3.09 KB | | dist/layouts/Root | ${{\color{Goldenrod}{ }}}$ 0.3%, 2.91 KB | | dist/views/CreateFirstUser | ${{\color{Goldenrod}{ }}}$ 0.3%, 2.81 KB | | dist/templates/Default | ${{\color{Goldenrod}{ }}}$ 0.3%, 2.63 KB | | dist/views/BrowseByFolder | ${{\color{Goldenrod}{ }}}$ 0.3%, 2.61 KB | | dist/views/CollectionFolders | ${{\color{Goldenrod}{ }}}$ 0.3%, 2.44 KB | | dist/views/ResetPassword | ${{\color{Goldenrod}{ }}}$ 0.3%, 2.40 KB | | dist/views/Logout | ${{\color{Goldenrod}{ }}}$ 0.2%, 1.94 KB | | (other) | ${{\color{Goldenrod}{ ████▍ }}}$ 17.7%, 167.13 KB |
Meta file: packages/payload/meta_index.json, Out file: esbuild/index.js| Path | Size |
|---|
| ../../node_modules | ${{\color{Goldenrod}{ ████████████████▉ }}}$ 67.7%, 887.23 KB | | dist/fields/hooks | ${{\color{Goldenrod}{ ▊ }}}$ 3.3%, 43.59 KB | | dist/collections/operations | ${{\color{Goldenrod}{ ▊ }}}$ 3.0%, 39.77 KB | | dist/versions/migrations | ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 18.50 KB | | dist/auth/operations | ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 15.74 KB | | dist/globals/operations | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 13.17 KB | | dist/fields/config | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.84 KB | | dist/queues/operations | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 12.80 KB | | dist/utilities/configToJSONSchema.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 12.21 KB | | dist/fields/validations.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 10.54 KB | | dist/bin/generateImportMap | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.77 KB | | dist/collections/config | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 8.35 KB | | dist/index.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.69 KB | | dist/uploads/fetchAPI-multipart | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.67 KB | | dist/database/migrations | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.54 KB | | dist/config/orderable | ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.83 KB | | dist/collections/endpoints | ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 6.22 KB | | dist/config/sanitize.js | ${{\color{Goldenrod}{ }}}$ 0.4%, 5.58 KB | | dist/auth/strategies | ${{\color{Goldenrod}{ }}}$ 0.4%, 5.50 KB | | dist/auth/endpoints | ${{\color{Goldenrod}{ }}}$ 0.4%, 5.42 KB | | (other) | ${{\color{Goldenrod}{ ████████ }}}$ 32.3%, 422.44 KB |
Meta file: packages/payload/meta_shared.json, Out file: esbuild/exports/shared.js| Path | Size |
|---|
| ../../node_modules | ${{\color{Goldenrod}{ ███████████████████▎ }}}$ 77.1%, 127.13 KB | | dist/fields/validations.js | ${{\color{Goldenrod}{ █▌ }}}$ 6.4%, 10.54 KB | | dist/config/orderable | ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 3.13 KB | | dist/fields/baseFields | ${{\color{Goldenrod}{ ▍ }}}$ 1.7%, 2.79 KB | | dist/utilities/deepCopyObject.js | ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 2.54 KB | | dist/auth/cookies.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 1.55 KB | | dist/utilities/flattenTopLevelFields.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 1.42 KB | | dist/fields/config | ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 1.28 KB | | dist/utilities/getVersionsConfig.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 1.04 KB | | dist/utilities/flattenAllFields.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 943 B | | dist/folders/utils | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 916 B | | dist/utilities/unflatten.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.5%, 779 B | | dist/utilities/sanitizeUserDataForEmail.js | ${{\color{Goldenrod}{ }}}$ 0.4%, 713 B | | dist/utilities/getFieldPermissions.js | ${{\color{Goldenrod}{ }}}$ 0.4%, 651 B | | dist/collections/config | ${{\color{Goldenrod}{ }}}$ 0.3%, 570 B | | dist/bin/generateImportMap | ${{\color{Goldenrod}{ }}}$ 0.3%, 561 B | | dist/auth/sessions.js | ${{\color{Goldenrod}{ }}}$ 0.3%, 525 B | | dist/fields/getFieldPaths.js | ${{\color{Goldenrod}{ }}}$ 0.3%, 485 B | | dist/utilities/getSafeRedirect.js | ${{\color{Goldenrod}{ }}}$ 0.3%, 423 B | | dist/utilities/deepMerge.js | ${{\color{Goldenrod}{ }}}$ 0.3%, 413 B | | (other) | ${{\color{Goldenrod}{ █████▋ }}}$ 22.9%, 37.78 KB |
Meta file: packages/richtext-lexical/meta_client.json, Out file: esbuild/exports/client_optimized/index.js| Path | Size |
|---|
| dist/lexical/plugins | ${{\color{Goldenrod}{ ██▉ }}}$ 11.7%, 32.00 KB | | dist/features/blocks | ${{\color{Goldenrod}{ ██▊ }}}$ 11.0%, 30.17 KB | | dist/lexical/ui | ${{\color{Goldenrod}{ ██▏ }}}$ 8.9%, 24.36 KB | | dist/features/experimental_table | ${{\color{Goldenrod}{ ██▏ }}}$ 8.6%, 23.70 KB | | dist/packages/@lexical | ${{\color{Goldenrod}{ █▋ }}}$ 6.9%, 18.99 KB | | dist/features/link | ${{\color{Goldenrod}{ █▋ }}}$ 6.7%, 18.38 KB | | dist/features/toolbars | ${{\color{Goldenrod}{ █▋ }}}$ 6.5%, 17.75 KB | | dist/features/upload | ${{\color{Goldenrod}{ █▎ }}}$ 5.1%, 14.00 KB | | dist/features/textState | ${{\color{Goldenrod}{ █ }}}$ 4.0%, 11.08 KB | | dist/features/relationship | ${{\color{Goldenrod}{ ▊ }}}$ 3.3%, 9.03 KB | | dist/lexical/utils | ${{\color{Goldenrod}{ ▊ }}}$ 3.1%, 8.49 KB | | dist/features/debug | ${{\color{Goldenrod}{ ▋ }}}$ 2.7%, 7.39 KB | | dist/features/converters | ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 7.05 KB | | dist/utilities/fieldsDrawer | ${{\color{Goldenrod}{ ▌ }}}$ 2.3%, 6.38 KB | | dist/lexical/config | ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 5.08 KB | | dist/features/lists | ${{\color{Goldenrod}{ ▍ }}}$ 1.8%, 5.00 KB | | dist/lexical/LexicalEditor.js | ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 3.47 KB | | dist/features/format | ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 3.46 KB | | dist/lexical/theme | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 2.62 KB | | dist/features/indent | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 2.50 KB | | (other) | ${{\color{Goldenrod}{ ██████████████████████ }}}$ 88.3%, 242.06 KB |
Meta file: packages/ui/meta_client.json, Out file: esbuild/exports/client_optimized/index.js| Path | Size |
|---|
| ../../node_modules | ${{\color{Goldenrod}{ ████████████▍ }}}$ 49.5%, 578.95 KB | | dist/elements/FolderView | ${{\color{Goldenrod}{ ▋ }}}$ 2.5%, 29.37 KB | | dist/elements/BulkUpload | ${{\color{Goldenrod}{ ▌ }}}$ 2.4%, 27.63 KB | | dist/elements/WhereBuilder | ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 17.27 KB | | dist/views/Edit | ${{\color{Goldenrod}{ ▎ }}}$ 1.4%, 16.74 KB | | dist/fields/Relationship | ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.78 KB | | dist/elements/Table | ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.77 KB | | dist/forms/Form | ${{\color{Goldenrod}{ ▎ }}}$ 1.3%, 15.31 KB | | dist/fields/Upload | ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 14.24 KB | | dist/fields/Blocks | ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 13.69 KB | | dist/elements/QueryPresets | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 10.36 KB | | dist/elements/PublishButton | ${{\color{Goldenrod}{ ▏ }}}$ 0.8%, 9.06 KB | | dist/providers/Folders | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.47 KB | | dist/elements/LivePreview | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 8.38 KB | | dist/elements/ListHeader | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.99 KB | | dist/elements/HTMLDiff | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.82 KB | | dist/fields/Array | ${{\color{Goldenrod}{ ▏ }}}$ 0.7%, 7.73 KB | | dist/views/CollectionFolder | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.50 KB | | dist/views/List | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.35 KB | | dist/elements/ReactSelect | ${{\color{Goldenrod}{ ▏ }}}$ 0.6%, 7.34 KB | | (other) | ${{\color{Goldenrod}{ ████████████▋ }}}$ 50.5%, 590.47 KB |
Meta file: packages/ui/meta_shared.json, Out file: esbuild/exports/shared_optimized/index.js| Path | Size |
|---|
| dist/graphics/Logo | ${{\color{Goldenrod}{ █████ }}}$ 20.0%, 3.12 KB | | ../../node_modules | ${{\color{Goldenrod}{ ████▎ }}}$ 17.0%, 2.65 KB | | dist/graphics/Icon | ${{\color{Goldenrod}{ ██▍ }}}$ 9.8%, 1.52 KB | | dist/utilities/formatDocTitle | ${{\color{Goldenrod}{ ██▏ }}}$ 8.5%, 1.32 KB | | dist/providers/TableColumns | ${{\color{Goldenrod}{ █▍ }}}$ 5.5%, 862 B | | dist/utilities/groupNavItems.js | ${{\color{Goldenrod}{ █▎ }}}$ 5.2%, 814 B | | dist/utilities/getGlobalData.js | ${{\color{Goldenrod}{ █▏ }}}$ 4.9%, 762 B | | dist/utilities/api.js | ${{\color{Goldenrod}{ █▏ }}}$ 4.8%, 756 B | | dist/elements/Translation | ${{\color{Goldenrod}{ ▊ }}}$ 3.2%, 493 B | | dist/utilities/handleTakeOver.js | ${{\color{Goldenrod}{ ▋ }}}$ 2.8%, 440 B | | dist/utilities/traverseForLocalizedFields.js | ${{\color{Goldenrod}{ ▋ }}}$ 2.6%, 399 B | | dist/elements/withMergedProps | ${{\color{Goldenrod}{ ▌ }}}$ 2.2%, 339 B | | dist/utilities/getVisibleEntities.js | ${{\color{Goldenrod}{ ▌ }}}$ 2.1%, 329 B | | dist/utilities/getNavGroups.js | ${{\color{Goldenrod}{ ▍ }}}$ 1.9%, 301 B | | dist/elements/WithServerSideProps | ${{\color{Goldenrod}{ ▍ }}}$ 1.5%, 232 B | | dist/utilities/handleGoBack.js | ${{\color{Goldenrod}{ ▎ }}}$ 1.2%, 180 B | | dist/fields/mergeFieldStyles.js | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 159 B | | dist/utilities/handleBackToDashboard.js | ${{\color{Goldenrod}{ ▎ }}}$ 1.0%, 152 B | | dist/forms/Form | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 147 B | | dist/utilities/abortAndIgnore.js | ${{\color{Goldenrod}{ ▏ }}}$ 0.9%, 146 B | | (other) | ${{\color{Goldenrod}{ ████████████████████ }}}$ 80.0%, 12.51 KB |
DetailsNext to the size is how much the size has increased or decreased compared with the base branch of this PR. - ‼️: Size increased by 20% or more. Special attention should be given to this.
- ⚠️: Size increased in acceptable range (lower than 20%).
- ✅: No change or even downsized.
- 🗑️: The out file is deleted: not found in base branch.
- 🆕: The out file is newly found: will be added to base branch.
|
Fixes#10942
Before
Lexical nodes with nested fields (blocks, inline blocks, links, uploads) were fully isolated from the parent document's form system. Each node type managed its own form lifecycle: block and inline block components rendered their own
<Form>component directly on the page, with their owninitialStatebuilt via a dedicatedbuildInitialStateutility, their own state reducer, and their ownonChangehooks to sync field changes back into the Lexical node viaeditor.update(). Links and uploads did the same when their editing drawers opened.This meant every node with sub-fields was effectively a mini-document with its own form context and submission flow that we had to handle manually - completely separate from the parent document form. From the perspective of Payload's form system, these fields didn't exist:
useAllFormFields(),useFormFields(), and other form hooks couldn't see them. They were buried inside the rich text field's serialized JSON value.After
Nested Lexical fields now live in the parent document's form state, just like array fields, standard blocks, and top-level fields. A lexical block's text field sits at
lexicalField.{nodeId}.fieldNamein the same flatFormStatemap. The node ID is the bridge between the freeform Lexical JSON tree and the flat form state - it's the one stable identifier every node with sub-fields already has. Drawers read from and write to the parent form state directly; thedataprop onFieldsDrawerhas been removed entirely.Why
Consistency and simplicity. Nested Lexical fields are Payload fields - they're defined with the same field config, validated the same way, stored the same way. There was no reason for them to be invisible to the rest of the form system. This change makes them first-class fields, which means any component, plugin, or custom hook can read and write Lexical sub-fields using standard form hooks. It also simplifies the client-side architecture: node components no longer need to manage their own state lifecycle,.
How
A new
buildFormStatemethod on theRichTextAdapterinterface lets the Lexical adapter hook into the existing form state pipeline. During server-side form state construction, the adapter walks the serialized Lexical tree, finds nodes with sub-fields via feature-providedgetSubFieldsDataandgetSchemaPathfunctions, and calls the standarditerateFieldsutility to populate form state entries under{richTextPath}.{nodeId}.*. This works similarly to howgenerateSchemaMapalready works for the schema map - just now for form state.On save, a
beforeChangehook merges flat form state values back into the Lexical JSON tree before persistence, using the samegetSubFieldsDatamap. Any feature that registers sub-fields automatically participates in both directions.On the client, node components no longer receive full field data objects from
decorate(). They receive only structural identifiers (blockType,id,relationTo,value) and read user-editable field data from the parent form state via standard hooks.getFields()andgetData()have been renamed togetStaleFields()andgetStaleData(), as form state is the source of truth and the editor state for the node fields will be stale until the form state is synced back, which happens in the beforeChange hook.Links are a special case: as an
ElementNode, Lexical renders their DOM from internal node data. A targeted sync writes field values back to the link node viaeditor.update()on drawer submit, keeping rendering current.