-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
Improve the initial loading of the site editor #36044
Conversation
if ( typeof options.path === 'string' ) { | ||
let rawPath = options.path; | ||
if ( ! rawPath && options.url ) { | ||
rawPath = getQueryArg( options.url, 'rest_route' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the active global styles endpoint, we rely on url
because the URL is actually returned in another endpoint. This is the best way I've found to allow using the preloaded data in this case. Let me know if there's a better approach.
@@ -23,7 +23,7 @@ export const defaultEntities = [ | |||
label: __( 'Base' ), | |||
name: '__unstableBase', | |||
kind: 'root', | |||
baseURL: '', | |||
baseURL: '/', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the /
is preloaded.
@@ -136,6 +136,14 @@ export const defaultEntities = [ | |||
plural: 'globalStylesVariations', // should be different than name | |||
getTitle: ( record ) => record?.title?.rendered || record?.title, | |||
}, | |||
{ | |||
label: __( 'Themes' ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This adds the "themes" entity allowing us to rely on the redux cache and avoid multiple /wp/v2/themes
requests.
getEntityRecord, | ||
'getEntityRecord' | ||
); | ||
export const getRawEntityRecord = forwardResolver( 'getEntityRecord' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The difference between the two approaches is that there are actually "two caches" for resolvers: the one that is in the state which ifNotResolved relied on but that one ignores the temporary cache used to track resolvers that are set to be triggered after a setTimeout
call (see
resolversCache.isRunning( selectorName, args ) || |
ifNotResolved
there's a change of running the same resolver twice if we call the same selector twice no the same tick, one with getEntityRecord
and one time with getRawEntityRecord
. (This was actually happening in the site editor)
return cache[ selectorName ] && cache[ selectorName ].get( args ); | ||
return ( | ||
cache[ selectorName ] && | ||
cache[ selectorName ].get( trimUndefinedValues( args ) ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed that 1, 2, undefined
and 1, 2
args were being considered as different args while they are equivalent for us. We had a use-case in the site editor where this caused the same resolver to run twice.
const isReady = | ||
settings?.siteUrl && | ||
templateType !== undefined && | ||
entityId !== undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ensures we only mount everything once. EntityProvider
was remounting everything when the entity id changes.
@@ -176,107 +177,113 @@ function Editor( { initialSettings, onError } ) { | |||
}; | |||
|
|||
return ( | |||
<ShortcutProvider> | |||
<> | |||
<URLQueryController /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally this should be a hook and not a component.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll extract this into a separate issue, so we don't forget.
|
||
return context; | ||
} | ||
|
||
export function GlobalStylesProvider( { children } ) { | ||
const context = useGlobalStylesContext(); | ||
if ( ! context.isReady ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While the user styles endpoint and all is preloaded now, you can still notice a change in the UI/colors... on initial load if we don't wait for the "mergedConfig" to be ready. I guess it's because all the resolvers are async and that there are a lot of them running on initial load.
? { | ||
search: searchQuery, | ||
} | ||
: undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This ensures we hit the cache and avoid search=
in the query string.
@@ -44,9 +44,7 @@ export default function TemplatesMenu() { | |||
const { templates, showOnFront } = useSelect( ( select ) => { | |||
const { getEntityRecords, getEditedEntityRecord } = select( coreStore ); | |||
return { | |||
templates: getEntityRecords( 'postType', 'wp_template', { | |||
per_page: -1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
per_page is not supported in the wp_template
and wp_template_part
post types.
@jasmussen the difference is more important when the sidebar is open (global styles) |
Well, that's a lot of test failures 😬 |
getEntityRecord, | ||
'getEntityRecord' | ||
); | ||
export const getRawEntityRecord = forwardResolver( 'getEntityRecord' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great idea. The forwardResolver
name says much more clearly what it does than ifNotResolved
.
Size Change: +116 B (0%) Total Size: 1.08 MB
ℹ️ View Unchanged
|
@@ -89,7 +89,7 @@ const EmbedEdit = ( props ) => { | |||
return { | |||
preview: validPreview ? embedPreview : undefined, | |||
fetching: isRequestingEmbedPreview( attributesUrl ), | |||
themeSupportsResponsive: getThemeSupports()[ | |||
themeSupportsResponsive: getThemeSupports()?.[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Theme supports can be undefined
before it's resolved. I was able to reproduce it locally by adding an embed block and then reloading the page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess on the previous implementation, we were always returning an empty object. Should we maybe update the selector to return an empty object (backward compat)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it matches the expected selector/resolver behavior now. Other places in core use loadash.get
, so there's no need to update.
Should we maybe update the selector to return an empty object (backward compat)
I will leave that up to you 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I updated the selector because we don't know how third-party users could be using it.
Great work on this PR, @youknowriad 🥇 I see API requests reduced from 30+ to 20, and loading time is improved ~300ms for me locally. |
Maybe performance tests need to be modified (at least on this branch) to help monitor results? It's a lot quicker to run through some hypotheses when we can measure it. There doesn't look like there's much change currently. For reviewers we can visually confirm what the performance suite is doing by running the following:
|
The main goal of this PR was not necessarily to improve the performance numbers, but more the perceived performance. In trunk, there's a lot of steps you can notice visually when the page is being loaded (especially related to global styles), this PR removes the number of steps and preloads more REST API requests. The result is that the server response is slower (expected as we do preload more API requests) but the time to show the first block is a bit better maybe. |
I think this should be ready. |
dad9d2b
to
2e6eddc
Compare
When you load the site editor, there are a number of subtle issues at play:
This PR tries to improve the situation in different places, it doesn't solve everything but it's a step (or multiple) forward.