Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: faster page navigation by speeding up createClientConfig, speed up version fetching, speed up lexical init. Up to 100x faster #9457

Merged
merged 26 commits into from
Nov 26, 2024

Conversation

AlessioGr
Copy link
Member

@AlessioGr AlessioGr commented Nov 22, 2024

If you had a lot of fields and collections, createClientConfig would be extremely slow, as it was copying a lot of memory. In my test config with a lot of fields and collections, it took 4 seconds(!!).

And not only that, it also ran between every single page navigation.

This PR significantly speeds up the createClientConfig function. In my test config, its execution speed went from 4 seconds to 50 ms.
Additionally, createClientConfig is now properly cached in both dev & prod. It no longer runs between every single page navigation. Even if you trigger a full page reload, createClientConfig will be cached and not run again. Despite that, HMR remains fully-functional.

This will make payload feel noticeably faster for large configs - especially if it contains a lot of richtext fields, as it was previously deep-copying the relatively large richText editor configs over and over again.

Before - 40 sec navigation speed

CleanShot.2024-11-22.at.15.35.52.mp4

After - 1 sec navigation speed

CleanShot.2024-11-22.at.15.31.47.mp4

Todo

  • Implement ClientSchemaMap and cache it, to remove createClientField call in our form state endpoint
  • Enable schemaMap caching for dev
  • Cache lexical clientField generation, or add it to the parent clientConfig

Lexical changes

Red: old / removed
Green: new

CleanShot 2024-11-22 at 21 07 41@2x

Future plans for a different PR:

While the calculation of the richtext client config / map is now cached and only happens once, we still send the result of it to the client between every single navigation. I would like to only send it to the client once and keep it cached on the client:

CleanShot 2024-11-22 at 21 08 02@2x

Speed up version queries

This PR comes with performance optimizations for fetching versions before a document is loaded. Not only does it use the new select API to limit the fields it queries, it also completely skips a database query if the current document is published.

Speed up lexical init

Removes a bunch of unnecessary deep copying of lexical objects which caused higher memory usage and slower load times. Additionally, the lexical default config sanitization now happens less often.

…emoving deep copying and building client config from the ground up instead
…ly runs once, and does not re-run when refreshing the page or navigating. HMR still works despite caching in dev
… comes back, we should run it in the background
@AlessioGr AlessioGr changed the title perf: faster page navigation by speeding up createClientConfig. Up to 100x faster perf: faster page navigation by speeding up createClientConfig, speed up version fetching. Up to 100x faster Nov 23, 2024
AlessioGr and others added 6 commits November 22, 2024 22:20
…t editor config is properly cached and only sanitized once for all lexical fields, instead of once per lexical field, as previously this was not cached until the sanitization function finished
@AlessioGr AlessioGr changed the title perf: faster page navigation by speeding up createClientConfig, speed up version fetching. Up to 100x faster perf: faster page navigation by speeding up createClientConfig, speed up version fetching, speed up lexical init. Up to 100x faster Nov 25, 2024

import { getClientConfig } from '@payloadcms/ui/utilities/getClientConfig'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This import is wrong. Was it exported from the top level properly from @payloadcms/ui?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, because getClientConfig can only run on the server, we can't export it from the top-level @payloadcms/ui. Thus, I have exported it directly

Copy link

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/@apollo/client@3.10.4 network +1 6.88 MB apollo-bot
npm/@faceless-ui/css-grid@1.2.1 None 0 36.3 kB jacobsfletch
npm/@faceless-ui/modal@2.0.2 None 0 71.1 kB jacobsfletch
npm/@lexical/list@0.14.5 environment 0 133 kB acywatson
npm/@lexical/react@0.14.5 Transitive: environment +17 1.94 MB acywatson
npm/@lexical/rich-text@0.14.5 environment +3 274 kB acywatson
npm/@lexical/utils@0.14.5 environment +2 509 kB acywatson
npm/@next/eslint-plugin-next@13.5.6 filesystem 0 79.8 kB vercel-release-bot
npm/@payloadcms/db-mongodb@3.1.0 environment, filesystem, network Transitive: shell +26 11.9 MB elliotpayload
npm/@payloadcms/next@3.1.0 Transitive: environment, filesystem, network, shell, unsafe +156 169 MB elliotpayload
npm/@payloadcms/payload-cloud@3.1.0 environment, filesystem, network Transitive: shell +212 26.5 MB elliotpayload
npm/@payloadcms/plugin-form-builder@3.0.0-beta.32 None +5 4.27 MB elliotpayload
npm/@payloadcms/richtext-lexical@3.0.0-beta.32 Transitive: environment +14 8.44 MB elliotpayload
npm/@payloadcms/richtext-lexical@3.1.0 environment Transitive: filesystem, network, unsafe +206 174 MB elliotpayload
npm/@types/node@22.8.6 None +1 2.35 MB types
npm/eslint-config-next@15.0.0 unsafe Transitive: environment, eval, filesystem +180 23.3 MB timer, timneutkens, vercel-release-bot
npm/eslint@8.57.1 environment, filesystem Transitive: eval, shell, unsafe +98 10.8 MB eslintbot
npm/graphql@16.9.0 environment 0 1.36 MB benjie
npm/next@15.0.0 environment, filesystem, network, shell, unsafe +13 107 MB vercel-release-bot
npm/payload@3.1.0 environment, eval, filesystem, network, shell, unsafe +85 145 MB elliotpayload
npm/react-dom@19.0.0-rc-65a56d0e-20241020 Transitive: environment +1 6.45 MB react-bot
npm/react@19.0.0-rc-65a56d0e-20241020 environment 0 239 kB react-bot
npm/sharp@0.32.6 environment, filesystem, shell Transitive: network +49 2.06 MB lovell
npm/types-react-dom@19.0.0-rc.1 None 0 17.7 kB eps1lon
npm/types-react@19.0.0-rc.1 None +1 1.63 MB eps1lon
npm/typescript@5.6.3 None 0 22.4 MB typescript-bot

🚮 Removed packages: npm/@aws-sdk/client-cognito-identity@3.687.0, npm/@aws-sdk/client-s3@3.687.0, npm/@aws-sdk/credential-providers@3.687.0, npm/@aws-sdk/lib-storage@3.687.0, npm/@azure/abort-controller@1.1.0, npm/@azure/storage-blob@12.25.0, npm/@babel/cli@7.25.9, npm/@babel/core@7.26.0, npm/@babel/preset-env@7.26.0, npm/@babel/preset-react@7.25.9, npm/@babel/preset-typescript@7.26.0, npm/@clack/prompts@0.7.0, npm/@eslint-react/eslint-plugin@1.16.1, npm/@eslint/js@9.14.0, npm/@google-cloud/storage@7.14.0, npm/@hyrious/esbuild-plugin-commonjs@0.2.4, npm/@jest/globals@29.7.0, npm/@lexical/eslint-plugin@0.20.0, npm/@lexical/headless@0.20.0, npm/@lexical/link@0.20.0, npm/@lexical/list@0.20.0, npm/@lexical/mark@0.20.0, npm/@lexical/react@0.20.0, npm/@lexical/rich-text@0.20.0, npm/@lexical/selection@0.20.0, npm/@lexical/table@0.20.0, npm/@lexical/utils@0.20.0, npm/@libsql/client@0.14.0, npm/@next/bundle-analyzer@15.0.0, npm/@next/env@15.0.3, npm/@playwright/test@1.48.1, npm/@sentry/nextjs@8.37.1, npm/@sentry/node@8.37.1, npm/@sentry/react@7.119.2, npm/@sentry/types@8.37.1, npm/@sindresorhus/slugify@1.1.2, npm/@swc-node/register@1.10.9, npm/@swc/cli@0.4.0, npm/@swc/core@1.7.10, npm/@swc/jest@0.2.36, npm/@types/body-scroll-lock@3.1.2, npm/@types/escape-html@1.0.4, npm/@types/eslint@9.6.1, npm/@types/eslint__js@8.42.3, npm/@types/esprima@4.0.6, npm/@types/find-node-modules@2.1.2, npm/@types/fs-extra@11.0.4, npm/@types/fs-extra@9.0.13, npm/@types/is-hotkey@0.1.10, npm/@types/jest@29.5.12, npm/@types/lodash.get@4.4.9, npm/@types/minimist@1.2.2, npm/@types/minimist@1.2.5, npm/@types/mongoose-aggregate-paginate-v2@1.0.12, npm/@types/node@22.5.4, npm/@types/nodemailer@6.4.14, npm/@types/pg@8.10.2, npm/@types/pluralize@0.0.33, npm/@types/prompts@2.4.9, npm/@types/range-parser@1.2.7, npm/@types/react-datepicker@6.2.0, npm/@types/semver@7.5.8, npm/@types/shelljs@0.8.15, npm/@types/to-snake-case@1.0.0, npm/@types/ws@8.5.13, npm/@typescript-eslint/parser@8.14.0, npm/@vercel/blob@0.22.3, npm/@vercel/postgres@0.9.0, npm/arg@5.0.2, npm/babel-plugin-react-compiler@0.0.0-experimental-24ec0eb-20240918, npm/babel-plugin-transform-remove-imports@1.8.0, npm/changelogen@0.5.7, npm/comment-json@4.2.5, npm/copyfiles@2.4.1, npm/dotenv@16.4.5, npm/drizzle-kit@0.28.0, npm/drizzle-orm@0.36.1, npm/esbuild-sass-plugin@3.3.1, npm/eslint-config-prettier@9.1.0, npm/eslint-plugin-import-x@4.4.2, npm/eslint-plugin-jest-dom@5.4.0, npm/eslint-plugin-jest@28.9.0

View full report↗︎

Copy link

🚨 Potential security issues detected. Learn more about Socket for GitHub ↗︎

To accept the risk, merge this PR and you will not be notified again.

Alert Package NoteSourceCI
Possible typosquat attack npm/types-react-dom@19.0.0-rc.1 ⚠︎

View full report↗︎

Next steps

What is a typosquat?

Package name is similar to other popular packages and may not be the package you want.

Use care when consuming similarly named packages and ensure that you did not intend to consume a different package. Malicious packages often publish using similar names as existing popular packages.

Take a deeper look at the dependency

Take a moment to review the security alert above. Review the linked package source code to understand the potential risk. Ensure the package is not malicious before proceeding. If you're unsure how to proceed, reach out to your security team or ask the Socket team for help at support [AT] socket [DOT] dev.

Remove the package

If you happen to install a dependency that Socket reports as Known Malware you should immediately remove it and select a different dependency. For other alert types, you may may wish to investigate alternative packages or consider if there are other ways to mitigate the specific risk posed by the dependency.

Mark a package as acceptable risk

To ignore an alert, reply with a comment starting with @SocketSecurity ignore followed by a space separated list of ecosystem/package-name@version specifiers. e.g. @SocketSecurity ignore npm/foo@1.0.0 or ignore all packages with @SocketSecurity ignore-all

  • @SocketSecurity ignore npm/types-react-dom@19.0.0-rc.1

@AlessioGr AlessioGr merged commit fd0ff51 into main Nov 26, 2024
55 checks passed
@AlessioGr AlessioGr deleted the perf/clientconfig branch November 26, 2024 21:31
Copy link

🚀 This is included in version v3.2.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants