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

Core data: properly forward entity resolvers #61013

Open
wants to merge 4 commits into
base: trunk
Choose a base branch
from

Conversation

ellatrix
Copy link
Member

@ellatrix ellatrix commented Apr 23, 2024

What?

Currently the dynamically entity resolver "shortcuts" are not really properly forwarded: is the core package these will be seen as separate resolvers altogether with and will be cached separately.

Why?

For example: getSite() and getEntityRecord( 'root', 'site' ) should be equivalent, but they will each trigger a separate REST request.

How?

We should avoid creating new resolvers for these shortcuts and instead rely on createRegistrySelector, so that the underlying resolver is called instead of a wrapper resolver.

Edit: it seems like this breaks resolveSelect: when trying to resolve a normal selector, it will just return the initial value without awaiting the result. Not sure how we can fix that. Maybe declare aliases and let the data package handle aliasing instead?

Testing Instructions

Load a page in the site editor, and you'll see two GET requests to the /v2/settings endpoint in the network tab. With this PR, there should only be one.

Testing Instructions for Keyboard

Screenshots or screencast

@ellatrix ellatrix added [Type] Bug An existing feature does not function as intended [Package] Core data /packages/core-data labels Apr 23, 2024
@ellatrix ellatrix requested a review from nerrad as a code owner April 23, 2024 20:19
Copy link

github-actions bot commented Apr 23, 2024

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: ellatrix <[email protected]>
Co-authored-by: Mamaduka <[email protected]>
Co-authored-by: youknowriad <[email protected]>
Co-authored-by: jsnajdr <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@ellatrix ellatrix requested a review from jsnajdr April 23, 2024 20:20
@ellatrix ellatrix added [Type] Performance Related to performance efforts and removed [Type] Bug An existing feature does not function as intended labels Apr 23, 2024
Copy link

github-actions bot commented Apr 23, 2024

Size Change: -398 B (0%)

Total Size: 1.74 MB

Filename Size Change
build/block-editor/index.min.js 256 kB -130 B (0%)
build/block-editor/style-rtl.css 15.5 kB -131 B (-1%)
build/block-editor/style.css 15.5 kB -136 B (-1%)
build/block-library/index.min.js 219 kB -26 B (0%)
build/blocks/index.min.js 51.7 kB +25 B (0%)
build/core-data/index.min.js 72.5 kB -12 B (0%)
build/edit-site/index.min.js 224 kB +12 B (0%)
ℹ️ View Unchanged
Filename Size
build/a11y/index.min.js 955 B
build/annotations/index.min.js 2.27 kB
build/api-fetch/index.min.js 2.32 kB
build/autop/index.min.js 2.1 kB
build/blob/index.min.js 578 B
build/block-directory/index.min.js 7.26 kB
build/block-directory/style-rtl.css 1.03 kB
build/block-directory/style.css 1.03 kB
build/block-editor/content-rtl.css 4.53 kB
build/block-editor/content.css 4.53 kB
build/block-editor/default-editor-styles-rtl.css 395 B
build/block-editor/default-editor-styles.css 395 B
build/block-library/blocks/archives/editor-rtl.css 61 B
build/block-library/blocks/archives/editor.css 60 B
build/block-library/blocks/archives/style-rtl.css 90 B
build/block-library/blocks/archives/style.css 90 B
build/block-library/blocks/audio/editor-rtl.css 150 B
build/block-library/blocks/audio/editor.css 150 B
build/block-library/blocks/audio/style-rtl.css 122 B
build/block-library/blocks/audio/style.css 122 B
build/block-library/blocks/audio/theme-rtl.css 133 B
build/block-library/blocks/audio/theme.css 133 B
build/block-library/blocks/avatar/editor-rtl.css 116 B
build/block-library/blocks/avatar/editor.css 116 B
build/block-library/blocks/avatar/style-rtl.css 104 B
build/block-library/blocks/avatar/style.css 104 B
build/block-library/blocks/block/editor-rtl.css 305 B
build/block-library/blocks/block/editor.css 305 B
build/block-library/blocks/button/editor-rtl.css 415 B
build/block-library/blocks/button/editor.css 414 B
build/block-library/blocks/button/style-rtl.css 627 B
build/block-library/blocks/button/style.css 626 B
build/block-library/blocks/buttons/editor-rtl.css 337 B
build/block-library/blocks/buttons/editor.css 337 B
build/block-library/blocks/buttons/style-rtl.css 332 B
build/block-library/blocks/buttons/style.css 332 B
build/block-library/blocks/calendar/style-rtl.css 239 B
build/block-library/blocks/calendar/style.css 239 B
build/block-library/blocks/categories/editor-rtl.css 113 B
build/block-library/blocks/categories/editor.css 112 B
build/block-library/blocks/categories/style-rtl.css 124 B
build/block-library/blocks/categories/style.css 124 B
build/block-library/blocks/code/editor-rtl.css 53 B
build/block-library/blocks/code/editor.css 53 B
build/block-library/blocks/code/style-rtl.css 121 B
build/block-library/blocks/code/style.css 121 B
build/block-library/blocks/code/theme-rtl.css 124 B
build/block-library/blocks/code/theme.css 124 B
build/block-library/blocks/columns/editor-rtl.css 108 B
build/block-library/blocks/columns/editor.css 108 B
build/block-library/blocks/columns/style-rtl.css 421 B
build/block-library/blocks/columns/style.css 421 B
build/block-library/blocks/comment-author-avatar/editor-rtl.css 125 B
build/block-library/blocks/comment-author-avatar/editor.css 125 B
build/block-library/blocks/comment-content/style-rtl.css 92 B
build/block-library/blocks/comment-content/style.css 92 B
build/block-library/blocks/comment-template/style-rtl.css 199 B
build/block-library/blocks/comment-template/style.css 198 B
build/block-library/blocks/comments-pagination-numbers/editor-rtl.css 123 B
build/block-library/blocks/comments-pagination-numbers/editor.css 121 B
build/block-library/blocks/comments-pagination/editor-rtl.css 222 B
build/block-library/blocks/comments-pagination/editor.css 209 B
build/block-library/blocks/comments-pagination/style-rtl.css 235 B
build/block-library/blocks/comments-pagination/style.css 231 B
build/block-library/blocks/comments-title/editor-rtl.css 75 B
build/block-library/blocks/comments-title/editor.css 75 B
build/block-library/blocks/comments/editor-rtl.css 840 B
build/block-library/blocks/comments/editor.css 839 B
build/block-library/blocks/comments/style-rtl.css 637 B
build/block-library/blocks/comments/style.css 636 B
build/block-library/blocks/cover/editor-rtl.css 671 B
build/block-library/blocks/cover/editor.css 674 B
build/block-library/blocks/cover/style-rtl.css 1.7 kB
build/block-library/blocks/cover/style.css 1.69 kB
build/block-library/blocks/details/editor-rtl.css 65 B
build/block-library/blocks/details/editor.css 65 B
build/block-library/blocks/details/style-rtl.css 86 B
build/block-library/blocks/details/style.css 86 B
build/block-library/blocks/embed/editor-rtl.css 322 B
build/block-library/blocks/embed/editor.css 322 B
build/block-library/blocks/embed/style-rtl.css 410 B
build/block-library/blocks/embed/style.css 410 B
build/block-library/blocks/embed/theme-rtl.css 133 B
build/block-library/blocks/embed/theme.css 133 B
build/block-library/blocks/file/editor-rtl.css 326 B
build/block-library/blocks/file/editor.css 327 B
build/block-library/blocks/file/style-rtl.css 280 B
build/block-library/blocks/file/style.css 281 B
build/block-library/blocks/file/view.min.js 324 B
build/block-library/blocks/footnotes/style-rtl.css 201 B
build/block-library/blocks/footnotes/style.css 199 B
build/block-library/blocks/form-input/editor-rtl.css 227 B
build/block-library/blocks/form-input/editor.css 227 B
build/block-library/blocks/form-input/style-rtl.css 343 B
build/block-library/blocks/form-input/style.css 343 B
build/block-library/blocks/form-submission-notification/editor-rtl.css 340 B
build/block-library/blocks/form-submission-notification/editor.css 340 B
build/block-library/blocks/form-submit-button/style-rtl.css 69 B
build/block-library/blocks/form-submit-button/style.css 69 B
build/block-library/blocks/form/view.min.js 471 B
build/block-library/blocks/freeform/editor-rtl.css 2.61 kB
build/block-library/blocks/freeform/editor.css 2.61 kB
build/block-library/blocks/gallery/editor-rtl.css 956 B
build/block-library/blocks/gallery/editor.css 960 B
build/block-library/blocks/gallery/style-rtl.css 1.72 kB
build/block-library/blocks/gallery/style.css 1.72 kB
build/block-library/blocks/gallery/theme-rtl.css 108 B
build/block-library/blocks/gallery/theme.css 108 B
build/block-library/blocks/group/editor-rtl.css 647 B
build/block-library/blocks/group/editor.css 647 B
build/block-library/blocks/group/style-rtl.css 103 B
build/block-library/blocks/group/style.css 103 B
build/block-library/blocks/group/theme-rtl.css 78 B
build/block-library/blocks/group/theme.css 78 B
build/block-library/blocks/heading/style-rtl.css 189 B
build/block-library/blocks/heading/style.css 189 B
build/block-library/blocks/html/editor-rtl.css 336 B
build/block-library/blocks/html/editor.css 337 B
build/block-library/blocks/image/editor-rtl.css 878 B
build/block-library/blocks/image/editor.css 878 B
build/block-library/blocks/image/style-rtl.css 1.6 kB
build/block-library/blocks/image/style.css 1.59 kB
build/block-library/blocks/image/theme-rtl.css 133 B
build/block-library/blocks/image/theme.css 133 B
build/block-library/blocks/image/view.min.js 1.54 kB
build/block-library/blocks/latest-comments/style-rtl.css 357 B
build/block-library/blocks/latest-comments/style.css 357 B
build/block-library/blocks/latest-posts/editor-rtl.css 213 B
build/block-library/blocks/latest-posts/editor.css 212 B
build/block-library/blocks/latest-posts/style-rtl.css 478 B
build/block-library/blocks/latest-posts/style.css 478 B
build/block-library/blocks/list/style-rtl.css 88 B
build/block-library/blocks/list/style.css 88 B
build/block-library/blocks/media-text/editor-rtl.css 306 B
build/block-library/blocks/media-text/editor.css 305 B
build/block-library/blocks/media-text/style-rtl.css 505 B
build/block-library/blocks/media-text/style.css 503 B
build/block-library/blocks/more/editor-rtl.css 431 B
build/block-library/blocks/more/editor.css 431 B
build/block-library/blocks/navigation-link/editor-rtl.css 668 B
build/block-library/blocks/navigation-link/editor.css 669 B
build/block-library/blocks/navigation-link/style-rtl.css 259 B
build/block-library/blocks/navigation-link/style.css 257 B
build/block-library/blocks/navigation-submenu/editor-rtl.css 296 B
build/block-library/blocks/navigation-submenu/editor.css 295 B
build/block-library/blocks/navigation/editor-rtl.css 2.26 kB
build/block-library/blocks/navigation/editor.css 2.26 kB
build/block-library/blocks/navigation/style-rtl.css 2.26 kB
build/block-library/blocks/navigation/style.css 2.25 kB
build/block-library/blocks/navigation/view.min.js 1.03 kB
build/block-library/blocks/nextpage/editor-rtl.css 395 B
build/block-library/blocks/nextpage/editor.css 395 B
build/block-library/blocks/page-list/editor-rtl.css 377 B
build/block-library/blocks/page-list/editor.css 377 B
build/block-library/blocks/page-list/style-rtl.css 175 B
build/block-library/blocks/page-list/style.css 175 B
build/block-library/blocks/paragraph/editor-rtl.css 235 B
build/block-library/blocks/paragraph/editor.css 235 B
build/block-library/blocks/paragraph/style-rtl.css 335 B
build/block-library/blocks/paragraph/style.css 335 B
build/block-library/blocks/post-author/style-rtl.css 175 B
build/block-library/blocks/post-author/style.css 176 B
build/block-library/blocks/post-comments-form/editor-rtl.css 96 B
build/block-library/blocks/post-comments-form/editor.css 96 B
build/block-library/blocks/post-comments-form/style-rtl.css 508 B
build/block-library/blocks/post-comments-form/style.css 508 B
build/block-library/blocks/post-content/editor-rtl.css 74 B
build/block-library/blocks/post-content/editor.css 74 B
build/block-library/blocks/post-date/style-rtl.css 61 B
build/block-library/blocks/post-date/style.css 61 B
build/block-library/blocks/post-excerpt/editor-rtl.css 71 B
build/block-library/blocks/post-excerpt/editor.css 71 B
build/block-library/blocks/post-excerpt/style-rtl.css 141 B
build/block-library/blocks/post-excerpt/style.css 141 B
build/block-library/blocks/post-featured-image/editor-rtl.css 729 B
build/block-library/blocks/post-featured-image/editor.css 727 B
build/block-library/blocks/post-featured-image/style-rtl.css 342 B
build/block-library/blocks/post-featured-image/style.css 342 B
build/block-library/blocks/post-navigation-link/style-rtl.css 215 B
build/block-library/blocks/post-navigation-link/style.css 214 B
build/block-library/blocks/post-template/editor-rtl.css 99 B
build/block-library/blocks/post-template/editor.css 98 B
build/block-library/blocks/post-template/style-rtl.css 409 B
build/block-library/blocks/post-template/style.css 408 B
build/block-library/blocks/post-terms/style-rtl.css 96 B
build/block-library/blocks/post-terms/style.css 96 B
build/block-library/blocks/post-time-to-read/style-rtl.css 69 B
build/block-library/blocks/post-time-to-read/style.css 69 B
build/block-library/blocks/post-title/style-rtl.css 100 B
build/block-library/blocks/post-title/style.css 100 B
build/block-library/blocks/preformatted/style-rtl.css 125 B
build/block-library/blocks/preformatted/style.css 125 B
build/block-library/blocks/pullquote/editor-rtl.css 135 B
build/block-library/blocks/pullquote/editor.css 135 B
build/block-library/blocks/pullquote/style-rtl.css 354 B
build/block-library/blocks/pullquote/style.css 353 B
build/block-library/blocks/pullquote/theme-rtl.css 174 B
build/block-library/blocks/pullquote/theme.css 174 B
build/block-library/blocks/query-pagination-numbers/editor-rtl.css 122 B
build/block-library/blocks/query-pagination-numbers/editor.css 121 B
build/block-library/blocks/query-pagination/editor-rtl.css 221 B
build/block-library/blocks/query-pagination/editor.css 211 B
build/block-library/blocks/query-pagination/style-rtl.css 288 B
build/block-library/blocks/query-pagination/style.css 284 B
build/block-library/blocks/query-title/style-rtl.css 63 B
build/block-library/blocks/query-title/style.css 63 B
build/block-library/blocks/query/editor-rtl.css 486 B
build/block-library/blocks/query/editor.css 486 B
build/block-library/blocks/query/view.min.js 958 B
build/block-library/blocks/quote/style-rtl.css 237 B
build/block-library/blocks/quote/style.css 237 B
build/block-library/blocks/quote/theme-rtl.css 233 B
build/block-library/blocks/quote/theme.css 235 B
build/block-library/blocks/read-more/style-rtl.css 140 B
build/block-library/blocks/read-more/style.css 140 B
build/block-library/blocks/rss/editor-rtl.css 149 B
build/block-library/blocks/rss/editor.css 149 B
build/block-library/blocks/rss/style-rtl.css 289 B
build/block-library/blocks/rss/style.css 288 B
build/block-library/blocks/search/editor-rtl.css 184 B
build/block-library/blocks/search/editor.css 184 B
build/block-library/blocks/search/style-rtl.css 690 B
build/block-library/blocks/search/style.css 689 B
build/block-library/blocks/search/theme-rtl.css 114 B
build/block-library/blocks/search/theme.css 114 B
build/block-library/blocks/search/view.min.js 478 B
build/block-library/blocks/separator/editor-rtl.css 146 B
build/block-library/blocks/separator/editor.css 146 B
build/block-library/blocks/separator/style-rtl.css 239 B
build/block-library/blocks/separator/style.css 239 B
build/block-library/blocks/separator/theme-rtl.css 194 B
build/block-library/blocks/separator/theme.css 194 B
build/block-library/blocks/shortcode/editor-rtl.css 323 B
build/block-library/blocks/shortcode/editor.css 323 B
build/block-library/blocks/site-logo/editor-rtl.css 801 B
build/block-library/blocks/site-logo/editor.css 801 B
build/block-library/blocks/site-logo/style-rtl.css 204 B
build/block-library/blocks/site-logo/style.css 204 B
build/block-library/blocks/site-tagline/editor-rtl.css 86 B
build/block-library/blocks/site-tagline/editor.css 86 B
build/block-library/blocks/site-title/editor-rtl.css 116 B
build/block-library/blocks/site-title/editor.css 116 B
build/block-library/blocks/site-title/style-rtl.css 57 B
build/block-library/blocks/site-title/style.css 57 B
build/block-library/blocks/social-link/editor-rtl.css 184 B
build/block-library/blocks/social-link/editor.css 184 B
build/block-library/blocks/social-links/editor-rtl.css 676 B
build/block-library/blocks/social-links/editor.css 675 B
build/block-library/blocks/social-links/style-rtl.css 1.48 kB
build/block-library/blocks/social-links/style.css 1.48 kB
build/block-library/blocks/spacer/editor-rtl.css 350 B
build/block-library/blocks/spacer/editor.css 350 B
build/block-library/blocks/spacer/style-rtl.css 48 B
build/block-library/blocks/spacer/style.css 48 B
build/block-library/blocks/table/editor-rtl.css 395 B
build/block-library/blocks/table/editor.css 395 B
build/block-library/blocks/table/style-rtl.css 639 B
build/block-library/blocks/table/style.css 639 B
build/block-library/blocks/table/theme-rtl.css 152 B
build/block-library/blocks/table/theme.css 152 B
build/block-library/blocks/tag-cloud/style-rtl.css 251 B
build/block-library/blocks/tag-cloud/style.css 253 B
build/block-library/blocks/template-part/editor-rtl.css 431 B
build/block-library/blocks/template-part/editor.css 431 B
build/block-library/blocks/template-part/theme-rtl.css 107 B
build/block-library/blocks/template-part/theme.css 107 B
build/block-library/blocks/term-description/style-rtl.css 111 B
build/block-library/blocks/term-description/style.css 111 B
build/block-library/blocks/text-columns/editor-rtl.css 95 B
build/block-library/blocks/text-columns/editor.css 95 B
build/block-library/blocks/text-columns/style-rtl.css 166 B
build/block-library/blocks/text-columns/style.css 166 B
build/block-library/blocks/verse/style-rtl.css 99 B
build/block-library/blocks/verse/style.css 99 B
build/block-library/blocks/video/editor-rtl.css 552 B
build/block-library/blocks/video/editor.css 555 B
build/block-library/blocks/video/style-rtl.css 185 B
build/block-library/blocks/video/style.css 185 B
build/block-library/blocks/video/theme-rtl.css 133 B
build/block-library/blocks/video/theme.css 133 B
build/block-library/classic-rtl.css 179 B
build/block-library/classic.css 179 B
build/block-library/common-rtl.css 1.11 kB
build/block-library/common.css 1.11 kB
build/block-library/editor-elements-rtl.css 75 B
build/block-library/editor-elements.css 75 B
build/block-library/editor-rtl.css 12.4 kB
build/block-library/editor.css 12.4 kB
build/block-library/elements-rtl.css 54 B
build/block-library/elements.css 54 B
build/block-library/reset-rtl.css 472 B
build/block-library/reset.css 472 B
build/block-library/style-rtl.css 14.8 kB
build/block-library/style.css 14.8 kB
build/block-library/theme-rtl.css 707 B
build/block-library/theme.css 713 B
build/block-serialization-default-parser/index.min.js 1.12 kB
build/block-serialization-spec-parser/index.min.js 2.87 kB
build/commands/index.min.js 15.2 kB
build/commands/style-rtl.css 953 B
build/commands/style.css 951 B
build/components/index.min.js 220 kB
build/components/style-rtl.css 12 kB
build/components/style.css 12 kB
build/compose/index.min.js 12.7 kB
build/core-commands/index.min.js 2.77 kB
build/customize-widgets/index.min.js 11 kB
build/customize-widgets/style-rtl.css 1.36 kB
build/customize-widgets/style.css 1.36 kB
build/data-controls/index.min.js 640 B
build/data/index.min.js 9 kB
build/date/index.min.js 17.9 kB
build/deprecated/index.min.js 451 B
build/dom-ready/index.min.js 324 B
build/dom/index.min.js 4.65 kB
build/edit-post/classic-rtl.css 578 B
build/edit-post/classic.css 578 B
build/edit-post/index.min.js 16.9 kB
build/edit-post/style-rtl.css 4.24 kB
build/edit-post/style.css 4.23 kB
build/edit-site/style-rtl.css 13.9 kB
build/edit-site/style.css 14 kB
build/edit-widgets/index.min.js 17.6 kB
build/edit-widgets/style-rtl.css 4.16 kB
build/edit-widgets/style.css 4.16 kB
build/editor/index.min.js 78.9 kB
build/editor/style-rtl.css 6.94 kB
build/editor/style.css 6.95 kB
build/element/index.min.js 4.83 kB
build/escape-html/index.min.js 537 B
build/format-library/index.min.js 8.07 kB
build/format-library/style-rtl.css 493 B
build/format-library/style.css 492 B
build/hooks/index.min.js 1.55 kB
build/html-entities/index.min.js 448 B
build/i18n/index.min.js 3.58 kB
build/interactivity/debug.min.js 16.2 kB
build/interactivity/file.min.js 447 B
build/interactivity/image.min.js 1.67 kB
build/interactivity/index.min.js 13 kB
build/interactivity/navigation.min.js 1.17 kB
build/interactivity/query.min.js 740 B
build/interactivity/router.min.js 2.79 kB
build/interactivity/search.min.js 618 B
build/is-shallow-equal/index.min.js 527 B
build/keyboard-shortcuts/index.min.js 1.3 kB
build/keycodes/index.min.js 1.46 kB
build/list-reusable-blocks/index.min.js 2.11 kB
build/list-reusable-blocks/style-rtl.css 851 B
build/list-reusable-blocks/style.css 851 B
build/media-utils/index.min.js 2.92 kB
build/modules/importmap-polyfill.min.js 12.2 kB
build/notices/index.min.js 948 B
build/nux/index.min.js 1.57 kB
build/nux/style-rtl.css 748 B
build/nux/style.css 744 B
build/patterns/index.min.js 6.47 kB
build/patterns/style-rtl.css 595 B
build/patterns/style.css 595 B
build/plugins/index.min.js 1.8 kB
build/preferences-persistence/index.min.js 2.06 kB
build/preferences/index.min.js 2.85 kB
build/preferences/style-rtl.css 710 B
build/preferences/style.css 712 B
build/primitives/index.min.js 975 B
build/priority-queue/index.min.js 1.52 kB
build/private-apis/index.min.js 1 kB
build/react-i18n/index.min.js 623 B
build/react-refresh-entry/index.min.js 9.47 kB
build/react-refresh-runtime/index.min.js 6.78 kB
build/redux-routine/index.min.js 2.7 kB
build/reusable-blocks/index.min.js 2.73 kB
build/reusable-blocks/style-rtl.css 256 B
build/reusable-blocks/style.css 256 B
build/rich-text/index.min.js 10 kB
build/router/index.min.js 1.88 kB
build/server-side-render/index.min.js 1.96 kB
build/shortcode/index.min.js 1.39 kB
build/style-engine/index.min.js 2.03 kB
build/token-list/index.min.js 582 B
build/url/index.min.js 3.74 kB
build/vendors/inert-polyfill.min.js 2.48 kB
build/vendors/react-dom.min.js 41.7 kB
build/vendors/react.min.js 4.02 kB
build/viewport/index.min.js 957 B
build/warning/index.min.js 249 B
build/widgets/index.min.js 7.23 kB
build/widgets/style-rtl.css 1.17 kB
build/widgets/style.css 1.17 kB
build/wordcount/index.min.js 1.02 kB

compressed-size-action

Copy link
Member

@Mamaduka Mamaduka left a comment

Choose a reason for hiding this comment

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

It works as expected, and I noticed that it also removes an extra OPTIONS request 🎉

The meta selectors for shortcuts, like hasFinishedResolution( 'getMedia' ), should work as before, correct?

@ellatrix
Copy link
Member Author

@Mamaduka I don't think that will work, because getMedia is no longer a resolver, it points to another resolver that will still resolve and subscribe the useSelect to it, but stuff like resolveSelect won't work.

Copy link
Contributor

@youknowriad youknowriad left a comment

Choose a reason for hiding this comment

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

Makes a lot of sense.

@youknowriad
Copy link
Contributor

The meta selectors for shortcuts, like hasFinishedResolution( 'getMedia' ), should work as before, correct?

Oh, that's a good point, so this could be seen as a breaking change, maybe there's a way to shim that somehow.

@Mamaduka
Copy link
Member

I just noticed that the Inserter > Media > Images tab hangs in a loading state on this branch due to an error in the coreMediaFetch method.

I believe this was the reason for the e2e test failure in the first run - https://github.com/WordPress/gutenberg/actions/runs/8806701315/attempts/1?pr=61013.

@ellatrix
Copy link
Member Author

@Mamaduka Yes that's because resolveSelect is broken for getMediaItems :)

@Mamaduka
Copy link
Member

Okay, so both meta-selectors and resolveSelect won't work for shortcuts.

Yeah, this seems like a breaking change, and I'm also wondering if we can shim the previous behavior.

Copy link
Member

@jsnajdr jsnajdr left a comment

Choose a reason for hiding this comment

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

👍

result[ getMethodName( kind, name ) ] = createRegistrySelector(
( select ) => ( state, key, query ) =>
select( STORE_NAME ).getEntityRecord( kind, name, key, query )
);
Copy link
Member

Choose a reason for hiding this comment

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

Here createRegistrySelector is not used to select from another store, but to select from the same store, we just want to call the selectors that are already bound to the store, with all the resolver-calling wrappers, instead of the unbound raw functions.

That's fine, but I think we should eventually come up with some new API for this.

Copy link
Member Author

Choose a reason for hiding this comment

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

What do you have in mind? I was thinking of creating something to pass aliases for selector/resolvers when creating the store, and handle them in the store

Copy link
Member

Choose a reason for hiding this comment

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

I don't have anything specific in mind yet. But the idea behind createRegistrySelector is that you can select across multiple stores and create one return value. But here we're not doing any cross-store work at all, we're still perfectly encapsulated inside one store. All I want to say is that using createRegistrySelector this way feels odd 🙂

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep, we do the same thing to trigger resolvers from other normal selectors in the same store. A better solution is needed there too.

@jsnajdr jsnajdr self-requested a review April 24, 2024 11:42
@jsnajdr
Copy link
Member

jsnajdr commented Apr 24, 2024

Some loud thinking about the breaking change: before this PR, the resolver for getSite() selector was pointing to the resolver for getEntityRecord( 'root', 'site' ). The resolver.fulfill function that does the actual REST fetching etc was shared, but each selector had its separate machinery for recording the resolution state etc. -- it's the code in fullfillResolver where calling the actual resolver.fulfill is just one line out of 50.

After this PR, getSite is mere alias for getEntityRecord( 'root', 'site' ). It has no resolver on its own. But that means that the meta-selectors can't ask for resolution state for getSite, because that doesn't exist.

What if we did this:

resolvers[ getMethodName( kind, name ) ] = {
  fulfill: ( key, query ) => resolvers.getEntityRecord( kind, name, key, query ),
  forward: ( args ) => [ 'getEntityRecord', [ kind, name, args.key, args.query ] ],
}

The function of forward would be that it's stored somewhere in a map mapping selectorNames to forward functions, and then a call like:

metadataSelectors.hasStartedResolution( metadata, selectorName, args )

would check if there is a "forwarder" in the map for selectorName and if there is, it would call it to get the "real" selectorName and args.

For example, hasStartedResolution( 'getSite', [] ) would lead to calling forward( [] ) and it returns [ 'getEntityRecord', [ 'root', 'site', undefined, undefined ] ]. Then it will return the (shared) resolution state.

What do you think? Is it too overengineered? But it works, doesn't it?

@youknowriad
Copy link
Contributor

@jsnajdr with the change you suggest, there's also no need to use registry selectors if I'm not wrong.

@ellatrix
Copy link
Member Author

@jsnajdr That's closer to what I meant with creating aliasing. This would also eliminate the duplication in this code. By knowing how to forward, we also know how to fulfill.

resolvers[ getMethodName( kind, name ) ] = {
  fulfill: ( key, query ) => resolvers.getEntityRecord( kind, name, key, query ),
  forward: ( args ) => [ 'getEntityRecord', [ kind, name, args.key, args.query ] ],
}

@jsnajdr
Copy link
Member

jsnajdr commented Apr 24, 2024

with the change you suggest, there's also no need to use registry selectors if I'm not wrong.

Yes, the existing code would be kept without changes, there would still be the entityResolvers object. We'd just add the forward functions to declare that the selectors should share the resolution state.

Alternatively, we could have a forwardResolver function:

resolvers[ getMethodName( kind, name ) ] = forwardResolver( ( key, query ) => [ 'getEntityRecord', [ kind, name, key, query ] ] );

It's not a different solution, just a syntactic sugar over the one from my previous comment. The forwardResolver argument can be used to construct both the fulfill and forward functions:

function forwardResolver( forward ) {
  return {
    fulfill: ( ...args ) => {
      const [ selectorName, selectorArgs ] = forward( ...args );
      return resolvers[ selectorName ]( ...selectorArgs );
    },
    forward,
  };
}

@jsnajdr
Copy link
Member

jsnajdr commented Apr 24, 2024

By knowing how to forward, we also know how to fulfill.

Exactly! The forward function is all you need to construct the fulfill function automatically.

@Mamaduka
Copy link
Member

Note: We already have the forwardResolver function - https://github.com/WordPress/gutenberg/blob/trunk/packages/core-data/src/utils/forward-resolver.js

@jsnajdr
Copy link
Member

jsnajdr commented Apr 24, 2024

Note: We already have the forwardResolver function

Interesting! And it seems it has none of the problems because it uses resolveSelect. There will be two versions of the resolution state, yes, but if getSite used forwardResolver, the REST request would be issued only once. Because if getEntityRecord( 'root', 'site' ) is already resolved, it will just return the resolved value. And if it's not resolved, there will be one resolver call (and one REST request) and then both selectors get resolved at once.

@ellatrix
Copy link
Member Author

We already have the forwardResolver function

Saw that, but that only works if args are the same, no?

@ellatrix
Copy link
Member Author

Ah, let me try that approach

@youknowriad
Copy link
Contributor

We could update it to provide extra static args or just use a similar technique to define the resolvers of the aliases without necessarily using the function.

@ellatrix
Copy link
Member Author

Yeah, trying it

@ellatrix
Copy link
Member Author

Nice, much simpler and works

@youknowriad
Copy link
Contributor

Cool :)

@Mamaduka
Copy link
Member

Mamaduka commented Apr 24, 2024

Nice! Works like a charm.

Here's a simple plugin I've used for manual testing the resolution states. Works better with emulated network.

Code

const {createElement: el, useState} = wp.element;
const {useSelect} = wp.data;
const registerPlugin = wp.plugins.registerPlugin;
const PluginDocumentSettingPanel = wp.editPost.PluginDocumentSettingPanel;
const {SelectControl} = wp.components;

function TestDataShortcutResolution() {
    const [currentImageId,setCurrentImageId] = useState(0);
    const images = useSelect((select)=>select('core').getMediaItems({ _fields: 'id,title' }), []);
    const { image, status } = useSelect( ( select ) => {
        if ( currentImageId === 0 ) {
            return { image: undefined, status: 'idle' };
        }

        const { getMedia, getResolutionState } = select( 'core' );
        console.log( currentImageId );
        return {
            image: getMedia( currentImageId ),
            ...( getResolutionState( 'getMedia', [ currentImageId ] ) ?? {} ),
        }
    }, [ currentImageId ] );

    const options = (images ?? []).map(image=>({
        value: image.id,
        label: image.title.rendered
    }))

    if ( options.length === 0 ) {
        return null;
    }

    options.push( { value: 0, label: 'No Selection' } );

    return el(PluginDocumentSettingPanel, {
        className: 'test-data-shortcut-resolution',
        title: 'Data Shortcut Resolution',
        name: 'test-data-shortcut-resolution'
    }, el(SelectControl, {
        label: 'Select Image',
        options,
        value: currentImageId,
        help: `Resolution status: ${ status }`,
        onChange: (id)=>setCurrentImageId(parseInt(id)),
        __next40pxDefaultSize: true,
        __nextHasNoMarginBottom: true,
    })
    );
}

registerPlugin('test-insertion-point', {
    render: TestDataShortcutResolution,
});

@ellatrix
Copy link
Member Author

Added a comment to explain why it works. Would appreciate a new ✅ with this new approach 🙂

@youknowriad
Copy link
Contributor

@ellatrix
Copy link
Member Author

Ok, there's still a slight back compat concern: for example invalidateResolutionForStoreSelector( 'getMedia' ) will no longer work because we're not also invalidating the underlying resolver. Let's see if I can forward that.

See 7e81589.

@ellatrix
Copy link
Member Author

I guess we could map invalidateResolutionForStoreSelector to a new invalidateResolution action with the correct args set? Honestly not sure if this would make it all too complex.

@ellatrix
Copy link
Member Author

ellatrix commented Apr 24, 2024

So I was playing with this. The problem is that the first action will not work as you can either only invalidate an entire resolution by selector, or with an exact args match?

entityActions.invalidateResolutionForStoreSelector =
	( selectorName ) =>
	async ( { dispatch } ) => {
		let isPlural = false;
		const config = entitiesConfig.find(
			( entity ) =>
				getMethodName( entity.kind, entity.name ) === selectorName
		);
		if ( ! config ) {
			const pluralConfig = entitiesConfig.find(
				( entity ) =>
					getMethodName( entity.kind, entity.plural ) === selectorName
			);
			if ( pluralConfig ) {
				isPlural = true;
			}
		}
		dispatch( {
			type: 'INVALIDATE_RESOLUTION_FOR_STORE_SELECTOR',
			selectorName: isPlural ? 'getEntityRecords' : 'getEntityRecord',
			args: [ config.kind, config.name ],
		} );
	};

entityActions.invalidateResolution =
	( selectorName, args ) =>
	async ( { dispatch } ) => {
		let isPlural = false;
		const config = entitiesConfig.find(
			( entity ) =>
				getMethodName( entity.kind, entity.name ) === selectorName
		);
		if ( ! config ) {
			const pluralConfig = entitiesConfig.find(
				( entity ) =>
					getMethodName( entity.kind, entity.plural ) === selectorName
			);
			if ( pluralConfig ) {
				isPlural = true;
			}
		}
		dispatch( {
			type: 'INVALIDATE_RESOLUTION',
			selectorName: isPlural ? 'getEntityRecords' : 'getEntityRecord',
			args: [ config.kind, config.name, ...args ],
		} );
	};

@youknowriad
Copy link
Contributor

It should be possible to define the shouldInvalidate action for the proxy resolvers :) and check that the action corresponds to the "invalidate resolution" action of the forwarded resolver.

In fact, we should probably do the same for the existing forwardResolver helper.

@ellatrix
Copy link
Member Author

I've tried that above, and mentioned there: I don't think it's possible to invalidate with partial arguments?

@youknowriad
Copy link
Contributor

@ellatrix I'm not sure I understand the code above, what is entityActions and where is shouldInvalidate defined?

@youknowriad
Copy link
Contributor

youknowriad commented Apr 25, 2024

What I'm saying is that you should do:

getEntityRecord.shouldInvalidate = ( action, kind, name, key = '', query ) => {
        // Here it should catch all the actions that correspond to invalidating the aliases.
        // so something like the following but in a generic way (looping through the entities)
        return action.type = "INVALIDATE_RESOLUTION" && selector.name === 'getMedia' and && kind === "root" && name === "media" && key = selector.args[0] && query === selector.args[1]
};

In other words when invalidating getMedia, we should invalidate all the forwarded calls too (so they're re-run as well).

@jsnajdr
Copy link
Member

jsnajdr commented Apr 25, 2024

I don't think it's possible to invalidate with partial arguments?

It's not currently possible, but should be implementable by extending the INVALIDATE_RESOLUTION action. Newly it would support "wildcard" args:

invalidateResolution( 'getEntityRecord', [ 'postType', 'post', match.anything() ] );

or even

invalidateResolution( 'getEntityRecord', [ 'postType', 'post', match( value => value.startsWith( 'prefix:' ) ) ] );

Very similar to Jest matchers 🙂

However, seeing the troubles with invalidateResolution, maybe we should, after all, implement the full native forwarding/aliasing with the forward function? The goal is to make the getSite() and getEntityRecord( 'root', 'site' ) truly indistinguishable.

With the resolveSelect solution, there is still a method to tell them apart. Assume you called getEntityRecord( 'root', 'site' ), and it has fully resolved. Then calling the selector again returns the resolved value, and hasFinishedResolution( 'getEntityRecord', [ 'root', 'site' ] ) will return true.

Now let's call getSite(). It will immediately return the resolved value, because getSite() is implemented as getEntityRecord( 'root', 'site' ). But what about the resolution state? hasFinishedResolution( 'getSite' ) will return false because getSite has its own resolution state and that hasn't resolved yet! It will become true only in the next promise tick, after the resolveSelect in getSite's resolver finishes.

Property implemented forwarding would create a real alias, where all operations on getSite -- reading, resolution state, invalidating -- would be identical to doing the same op on getEntityRecord( 'root', 'site' ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Package] Core data /packages/core-data [Type] Performance Related to performance efforts
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants