-
Notifications
You must be signed in to change notification settings - Fork 110
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
Add ability to prime URL metrics #1850
base: trunk
Are you sure you want to change the base?
Conversation
…ing between parent and iframe
…ints logic to dedicated functions
… generating a new UUID
… visibility hidden
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## trunk #1850 +/- ##
==========================================
- Coverage 71.21% 67.95% -3.26%
==========================================
Files 86 88 +2
Lines 7000 7346 +346
==========================================
+ Hits 4985 4992 +7
- Misses 2015 2354 +339
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
'prime_url_metrics_verification_token', | ||
odPrimeUrlMetricsVerificationToken | ||
); | ||
} |
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.
Authentication for REST API
-
WP Nonce Limitation: The default WordPress (WP) nonce does not function correctly when generated for the parent page and then passed to an iframe for REST API requests.
-
Custom Token Authentication: To address this, I have added a custom token-based authentication mechanism. This generates a time-limited token used to authenticate REST API requests made via the iframe.
In #1835 PR, WP nonces are introduced for REST API requests for logged-in users. This may allow us to eliminate the custom token authentication if URL metrics are collected exclusively from logged-in users.
}; | ||
|
||
// Load the iframe | ||
iframe.src = task.url; |
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.
Currently if the IFRAME
shares the same origin as the parent, then it allows it to access the parent session. This ensures that the user session in the page loaded within the iframe (which is a frontend page) matches the logged-in user of the WordPress dashboard.
But if the WordPress admin dashboard and the frontend have different origins, WP nonces won’t work for REST API authentication because the iframe will not recognize the logged-in session. As the different origin does not allow iframe to access parents session. For context I am talking about the REST nonce introduced in #1835.
iframe.style.transform = 'scale(0.05)'; | ||
iframe.style.transformOrigin = '0 0'; | ||
iframe.style.pointerEvents = 'none'; | ||
iframe.style.opacity = '0.000001'; |
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.
As the detect.js
requires the iframe to be visible in the viewport to resolve the onLCP promise. Traditional methods like moving the iframe off-screen using translate
, setting visibility: hidden
, or opacity: 0
cause the promise to hang.
performance/plugins/optimization-detective/detect.js
Lines 496 to 503 in 6ca5c4b
// Obtain at least one LCP candidate. More may be reported before the page finishes loading. | |
await new Promise( ( resolve ) => { | |
onLCP( | |
( /** @type LCPMetric */ metric ) => { | |
lcpMetricCandidates.push( metric ); | |
resolve(); | |
}, | |
{ |
I am using a workaround using the following CSS to keep the iframe minimally visible and functional:
position: fixed;
top: 0px;
left: 0px;
transform: scale(0.05);
transform-origin: 0px 0px;
pointer-events: none;
opacity: 1e-6;
z-index: -9999;
'OD_PRIME_URL_METRICS_REQUEST_SUCCESS', | ||
'*' | ||
); | ||
resolve(); |
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.
Parent and IFRAME
communication is handled via postMessage. A message is sent to the parent, and the promise resolves immediately.
If the promise isn't resolved immediately, navigating to a new URL causes the code following the promise to never execute. This is because changing the iframe.src
does not trigger events like pagehide
, pageswap
, or visibilitychange
.
performance/plugins/optimization-detective/detect.js
Lines 568 to 569 in 6ca5c4b
// Wait for the page to be hidden. | |
await new Promise( ( resolve ) => { |
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 wonder. Do we even need to post a message here? As soon as the iframe
is destroyed won't it automatically cause the URL Metric to be sent, right?
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 problem is we need to signal the parent that we can move to next URL or breakpoint using postMessage
as the load
event can't be used. Check this comment for detailed explanation #1850 (comment) .
Will it makes sense to send the postMessage
after the navigator.sendBeacon
then?
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.
Yes, I think it makes sense to send the message after the beacon is sent, definitely.
Just to not leave you hanging: I'm probably not going to be able to review this in depth and provide feedback for a couple more weeks. I'm preparing for travel to WordCamp Asia this weekend and I'll be giving a talk about Optimization Detective, so I need to focus on preparing for that. |
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 If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.
To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
@b1ink0 Thanks for the PR, this looks really promising, and I think it's going to be a super powerful feature. I'll take a closer look next week. One early thought: I wonder whether we should make this feature conditionally available based on a check on how much content the site has. For most sites, this feature is probably great, but we may want to use caution for sites that have e.g. 1000s of posts. We could make the condition filterable so that sites can still opt in, but I think a safeguard like this would be useful. Regarding the milestone, I think we should target this for a future release of Optimization Detective, such as 1.1.0. We're already in 1.0.0-beta, so it wouldn't be right to add an entirely new feature to 1.0.0 now. |
@b1ink0 Sorry for the delay with reviewing. It's probably going to be another week before I'll get a chance. In the meantime, I have another area you can explore here related to this. Right now there are two methods for priming URL Metrics:
There is another use case which I mentioned in #1311 (comment):
In order to facilitate this, I think there should be a new REST API endpoint in the
This endpoint need not be public. It could require authentication. With this information in hand, it should be possible to construct a script with Puppeteer which loops over all URLs needing URL Metrics with each of the viewport sizes in order to keep URL Metrics fresh across an entire site without requiring any frontend anonymous writes. This could be part of some daily system cron on the server (not wp-cron). As an alternative to the REST API endpoint, this data could be exposed instead via a new WP-CLI command for piping into a Puppeteer script. Similarly with the iframe on the admin screen for priming URL Metrics, the Puppeteer browser session would probably need to be logged-in as a user who can With this in place, we could eliminate the short-circuiting currently being done when the REST API is not available, introduced in #1762. If the user is an administrator, the REST API must be available. So Conversely, if there are URL Metrics collected for the current response and the user is not authenticated and yet the REST API is not available, then in this case we can go ahead and optimize the page but we can prevent any of the detection logic from being served. The ability to prime URL Metrics as you're exploring here will likely be critical to Optimization Detective to being feasible for deployment on high traffic and high profile sites. |
Oh, and the Puppeteer browser will need to have the same ability as the iframe'ed page to determine whether the page is "done" loading (i.e. URL Metric has been constructed and has been forcibly submitted). When this signal is received, the Puppeteer browser can move on to load the next URL or the same URL in the next viewport. |
Something else that comes to mind: the URL Priming process could be sped up by skipping URLs for viewports which already have a fresh URL Metric in the group. This could be something else which is facilitated by #1919. In particular, the integration could hook into the |
@westonruter As an alternative, I considered including a Puppeteer script project within the Optimization Detective plugin’s directory, along with its I would like to know if you have any other idea for this? |
Yes, I think this is the way to go. We can include a subdirectory in the plugin which contains the Puppeteer script. Instead of a site owner doing npx @wordpress/performance-od-url-metric-collector So yeah, I think the user would invoke node which would then do system calls to WP-CLI rather than calling WP-CLI which would do system calls to node. This is because WP-CLI is a dependency here for the Puppeteer script, not the other way around, I think. |
@westonruter Puppeteer_CLI_DEMO.mp4If this approach is correct, should I add these changes to current PR #1850? Another important thing to note is that I had to bypass the following check in performance/plugins/optimization-detective/detect.js Lines 477 to 482 in a3b0d7c
|
@b1ink0 yes, that is looking good! In regards to the idle callback, have you looked at using Nevertheless, that may not be right either. Seems like this is a known issue with Puppeteer and Aside: We may want to have Optimization Detective fire a custom event when it has gotten to the point where it is waiting for |
I tested both approaches: Regarding other methods I explored, we could replace Additionally, should the Puppeteer CLI code be added to the current PR, or should it be part of a separate PR after this one is merged into trunk? |
@b1ink0 If it makes it easier for you to prototype this, I think it's fine to add it to this PR. We can always remove parts of the PR prior to review, and then immediately revert the removals in subsequent PRs. |
Summary
Fixes #1311
Relevant technical choices
This PR introduces a new mechanism for priming URL metrics across the site. It uses a newly added submenu page in the Tools menu and automatically primes URL metrics when a post is saved in the block editor.
TODOS:
Demos
Settings page:
UI.mp4
Saving post in Block Editor:
Block.Editor.mp4