-
Notifications
You must be signed in to change notification settings - Fork 9.5k
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: add type checking to page functions #11958
Conversation
@@ -1112,7 +1112,6 @@ class Driver { | |||
async cacheNatives() { | |||
await this.evaluateScriptOnNewDocument(` | |||
window.__nativePromise = Promise; | |||
window.__nativeError = Error; |
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.
AFAICT this hasn't been used since #5509
if (!err || typeof err === 'string') { | ||
err = new Error(err); | ||
} |
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 research for what can end up in here was so long ago that I didn't want to break anything, so this is just a cleaned up version of what already existed. Also added tests to make sure all the cases are handled.
// FIXME COMPAT: This hack isn't neccessary as of Chrome 62.0.3176.0 | ||
// https://bugs.chromium.org/p/chromium/issues/detail?id=742530#c7 |
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.
fix shipped to stable Chrome in 2017
if (element instanceof ShadowRoot) { | ||
element = element.host; | ||
} |
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 catch block below relies on element
not being a ShadowRoot
anymore, so this needs to be outside of the try block. From the PR that added it, it seems like the concern was the clone
throwing, not this step anyways
/** @type {Element} */ | ||
// @ts-expect-error - clone will be same type as element - see https://github.com/microsoft/TypeScript/issues/283 | ||
const clone = element.cloneNode(); |
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.
clone
is an Element
since element
is an Element
, but the tsc dom types don't reflect this. When the mentioned issue (microsoft/TypeScript#283) is fixed (a fix was tried last year but backed out when it broke some stuff), this @ts-expect-error
will start erroring and can be removed
@@ -288,24 +292,26 @@ function getNodePath(node) { | |||
while (prevNode = node.previousSibling) { | |||
node = prevNode; | |||
// skip empty text nodes | |||
if (node.nodeType === Node.TEXT_NODE && node.nodeValue.trim().length === 0) continue; | |||
if (node.nodeType === Node.TEXT_NODE && (node.nodeValue || '').trim().length === 0) continue; |
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.
nodeValue
technically can be null*, so, fine
*(though this code shouldn't ever end up on a node where it is)
@@ -316,28 +322,28 @@ function getNodePath(node) { | |||
* - nodePath: 0,HTML,1,BODY,1,DIV,a,#document-fragment,0,SECTION,0,IMG | |||
* - nodeSelector: section > img | |||
*/ | |||
function getNodeSelector(node) { | |||
function getNodeSelector(element) { |
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.
we require this to be an Element
(in the existing type, but also because we access classList
and parentElement
), so changed the param name, but it seemed like too much to rename the function to getElementSelector
...
@@ -354,7 +360,7 @@ function getNodeSelector(node) { | |||
function isPositionFixed(element) { | |||
/** | |||
* @param {HTMLElement} element | |||
* @param {string} attr | |||
* @param {'overflowY'|'position'} attr |
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 was just easier since CSSStyleDeclaration
doesn't have a string index, and CSSStyleDeclaration[keyof CSSStyleDeclaration]
includes numbers and null. getStyleAttrValue
is an inner convenience function, and it's unlikely to ever see any more values here (but more could always be added, of course) so this seems fine
// html and body content is too broad to be useful, since they contain all page content | ||
if (tagName !== 'html' && tagName !== 'body') { | ||
const nodeLabel = node.innerText || node.getAttribute('alt') || node.getAttribute('aria-label'); | ||
const nodeLabel = element instanceof HTMLElement && element.innerText || |
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.
innerText
is only on HTMLElement
(though innerHTML
is on Element 🤷)
}; | ||
window.requestIdleCallback.toString = () => { | ||
return 'function requestIdleCallback() { [native code] }'; | ||
}; | ||
} | ||
|
||
/** | ||
* @param {HTMLElement} element | ||
* @param {Element|ShadowRoot} element |
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.
made the HTMLElement
-> Element
change for two reasons:
- if
element
is aShadowRoot
,element.host
is anElement
not anHTMLElement
, so would really have needed a second test below to make sure it was still anHTMLElement
- buuut, there doesn't appear to be any reason to limit
getNodeDetails
toHTMLElement
...it seems reasonable for a gatherer to want to getnodeDetails
of an SVG element, for instance
There aren't any significant effects from this change, just some type ones (like __lighthouseNodesDontTouchOrAllVarianceGoesAway
becomes a Map<Element, string>
)
const maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); | ||
canvas = gl = undefined; // Cleanup for GC |
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 didn't understand why this was necessary at the time because I thought escape analysis is the same either way and the memory leak potential is in the side-effects of creating a webgl canvas creating a reference (in which case canvas = gl = undefined
does nothing to help that, right?), but supposedly there was still a reason for this.
Given how fresh it is though, maybe @paulirish can clarify where #11847 (comment) ended up from his perspective :)
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 started from this offhand comment, not a detected problem #11847 (comment)
But yeah, they're references to DOM objects. Unsetting the locals isn't going to affect their lifecycle after the function is done.
/** Used by FullPageScreenshot gatherer. */ | ||
__lighthouseNodesDontTouchOrAllVarianceGoesAway: Map<HTMLElement, string>; | ||
__lighthouseNodesDontTouchOrAllVarianceGoesAway: Map<Element, string>; |
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.
hey wait a second how did this name end up staying like this 😆 I thought we had like 3 👎 comments
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.
hey wait a second how did this name end up staying like this 😆 I thought we had like 3 👎 comments
ha, yes, I would have also preferred a different name there :)
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.
lol I only recall @brendankenny downvoting. seems I snuck some personality in the code without any approval, sry.
to be clear this is referencing React's __SECRET_DOM_DO_NOT_USE_OR_YOU_WILL_BE_FIRED. but it's also a tounge-in-cheek response to some user expectations (the classic "I ran LH twice and got 91 and 92, which is it?!" that Patrick likes to reference)
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.
Haha I loved the concept I just didn't understand why it was backwards!! I'm so onboard for __lighthouseNodesDontTouchOrAllVarianceGoesThroughTheRoof
:)
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 suppose I'm hoping someone finds it and suggests removing it to fix our variance problem..
The file was actually in pretty good shape, and only needed three
// @ts-expect-error
s, two of which could be worked around instead (but which approach to take is arguable) and the other error will hopefully be fixed in future tsc updates.This should give a lot more confidence when making changes to e.g.
nodeDetails
and the like in the future.