diff --git a/pages/CoreWebVitals/CLS.mdx b/pages/CoreWebVitals/CLS.mdx index ca16bd4..4774dfc 100644 --- a/pages/CoreWebVitals/CLS.mdx +++ b/pages/CoreWebVitals/CLS.mdx @@ -5,25 +5,23 @@ This script displays the CLS value when the focus of the browser is switched to #### Snippet ```js copy - let cumulativeLayoutShiftScore = 0; - const observer = new PerformanceObserver((list) => { - for (const entry of list.getEntries()) { - if (!entry.hadRecentInput) { - cumulativeLayoutShiftScore += entry.value; - } +let cumulativeLayoutShiftScore = 0; +const observer = new PerformanceObserver((list) => { + for (const entry of list.getEntries()) { + if (!entry.hadRecentInput) { + cumulativeLayoutShiftScore += entry.value; } - }); + } +}); - observer.observe({ type: "layout-shift", buffered: true }); +observer.observe({ type: "layout-shift", buffered: true }); - document.addEventListener("visibilitychange", () => { - if (document.visibilityState === "hidden") { - observer.takeRecords(); - observer.disconnect(); +document.addEventListener("visibilitychange", () => { + if (document.visibilityState === "hidden") { + observer.takeRecords(); + observer.disconnect(); - console.log(`CLS: ${cumulativeLayoutShiftScore}`); - } - }); + console.log(`CLS: ${cumulativeLayoutShiftScore}`); + } +}); ``` - - diff --git a/pages/CoreWebVitals/LCP-Image-Entropy.mdx b/pages/CoreWebVitals/LCP-Image-Entropy.mdx index ffc608f..93a0080 100644 --- a/pages/CoreWebVitals/LCP-Image-Entropy.mdx +++ b/pages/CoreWebVitals/LCP-Image-Entropy.mdx @@ -2,7 +2,7 @@ Context: [Largest Contentful Paint change in Chrome 112 to ignore low-entropy images](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/speed/metrics_changelog/2023_04_lcp.md) -This snippet is based on and with the permission [Stoyan Stefanov](https://twitter.com/stoyanstefanov), read his post [here](https://www.phpied.com/quick-bpp-image-entropy-check/). +This snippet is based on and with the permission of [Stoyan Stefanov](https://twitter.com/stoyanstefanov), read his post [here](https://www.phpied.com/quick-bpp-image-entropy-check/). With the script you can get a list of the BPP of all(1) images loaded on the site. @@ -14,13 +14,13 @@ With the script you can get a list of the BPP of all(1) images loaded on the sit console.table( [...document.images] .filter( - (img) => img.currentSrc != "" && !img.currentSrc.includes("data:image") + (img) => img.currentSrc != "" && !img.currentSrc.includes("data:image"), ) .map((img) => [ img.currentSrc, (performance.getEntriesByName(img.currentSrc)[0]?.encodedBodySize * 8) / (img.width * img.height), ]) - .filter((img) => img[1] !== 0) + .filter((img) => img[1] !== 0), ); ``` diff --git a/pages/CoreWebVitals/LCP-Sub-Parts.mdx b/pages/CoreWebVitals/LCP-Sub-Parts.mdx index 83e3fc8..3912893 100644 --- a/pages/CoreWebVitals/LCP-Sub-Parts.mdx +++ b/pages/CoreWebVitals/LCP-Sub-Parts.mdx @@ -1,37 +1,37 @@ ### Largest Contentful Paint Sub-Parts (LCP) -This script it's part of the [Web Vitals Chrome Extension](https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma) and appear on the [Optimize Largest Contentful Paint](https://web.dev/i18n/en/optimize-lcp/) post. +This script is part of the [Web Vitals Chrome Extension](https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma) and appear on the [Optimize Largest Contentful Paint](https://web.dev/i18n/en/optimize-lcp/) post. -#### Snippet +#### Snippet ```js copy const LCP_SUB_PARTS = [ - 'Time to first byte', - 'Resource load delay', - 'Resource load time', - 'Element render delay', + "Time to first byte", + "Resource load delay", + "Resource load time", + "Element render delay", ]; new PerformanceObserver((list) => { const lcpEntry = list.getEntries().at(-1); - const navEntry = performance.getEntriesByType('navigation')[0]; + const navEntry = performance.getEntriesByType("navigation")[0]; const lcpResEntry = performance - .getEntriesByType('resource') + .getEntriesByType("resource") .filter((e) => e.name === lcpEntry.url)[0]; const ttfb = navEntry.responseStart; const lcpRequestStart = Math.max( ttfb, - lcpResEntry ? lcpResEntry.requestStart || lcpResEntry.startTime : 0 + lcpResEntry ? lcpResEntry.requestStart || lcpResEntry.startTime : 0, ); const lcpResponseEnd = Math.max( lcpRequestStart, - lcpResEntry ? lcpResEntry.responseEnd : 0 + lcpResEntry ? lcpResEntry.responseEnd : 0, ); const lcpRenderTime = Math.max( lcpResponseEnd, - lcpEntry ? lcpEntry.startTime : 0 + lcpEntry ? lcpEntry.startTime : 0, ); LCP_SUB_PARTS.forEach((part) => performance.clearMeasures(part)); @@ -56,18 +56,16 @@ new PerformanceObserver((list) => { ]; // Log helpful debug information to the console. - console.log('LCP value: ', lcpRenderTime); - console.log('LCP element: ', lcpEntry.element, lcpEntry?.url); + console.log("LCP value: ", lcpRenderTime); + console.log("LCP element: ", lcpEntry.element, lcpEntry?.url); console.table( lcpSubPartMeasures.map((measure) => ({ - 'LCP sub-part': measure.name, - 'Time (ms)': measure.duration, - '% of LCP': `${ + "LCP sub-part": measure.name, + "Time (ms)": measure.duration, + "% of LCP": `${ Math.round((1000 * measure.duration) / lcpRenderTime) / 10 }%`, - })) + })), ); -}).observe({type: 'largest-contentful-paint', buffered: true}); +}).observe({ type: "largest-contentful-paint", buffered: true }); ``` - - diff --git a/pages/CoreWebVitals/LCP.mdx b/pages/CoreWebVitals/LCP.mdx index ffdf783..8cae41d 100644 --- a/pages/CoreWebVitals/LCP.mdx +++ b/pages/CoreWebVitals/LCP.mdx @@ -1,12 +1,12 @@ # Largest Contentful Paint (LCP) -The next scripts show information about the [LCP](https://web.dev/lcp) metric. +The next scripts shows information about the [LCP](https://web.dev/lcp) metric. -> You can use it in the browser console or as snippet in the Chrome DevTools Source tab, take a look to the [Introduction](/introduction/) section. +> You can use it in the browser console or as a snippet in the Chrome DevTools Source tab, take a look at the [Introduction](/introduction/) section. ## Get the LCP element -List the Largest Contentful Paint in the console and add a green dotted line in the LCP element. +List the Largest Contentful Paint in the console and add a green dotted line around the LCP element. #### Snippet @@ -19,7 +19,7 @@ const po = new PerformanceObserver((list) => { entries.forEach((item, i) => { console.dir(item); console.log( - `${i + 1} current LCP item : ${item.element}: ${item.startTime}` + `${i + 1} current LCP item : ${item.element}: ${item.startTime}`, ); item.element ? (item.element.style = "border: 5px dotted lime;") : ""; }); diff --git a/pages/Interaction/Interactions.mdx b/pages/Interaction/Interactions.mdx index 4ce7869..4da80ea 100644 --- a/pages/Interaction/Interactions.mdx +++ b/pages/Interaction/Interactions.mdx @@ -1,26 +1,29 @@ # Interactions -This script it's part of the [Web Vitals Chrome Extension](https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma) and allows you to track all interactions as you click around the page to help improve INP. +This script is part of the [Web Vitals Chrome Extension](https://chrome.google.com/webstore/detail/web-vitals/ahfhijdlegdabablpippeagghigmibma) and allows you to track all interactions as you click around the page to help improve INP. #### Snippet ```js copy -const valueToRating = (score) => score <= 200 ? 'good' : score <= 500 ? 'needs-improvement' : 'poor'; +const valueToRating = (score) => + score <= 200 ? "good" : score <= 500 ? "needs-improvement" : "poor"; -const COLOR_GOOD = '#0CCE6A'; -const COLOR_NEEDS_IMPROVEMENT = '#FFA400'; -const COLOR_POOR = '#FF4E42'; +const COLOR_GOOD = "#0CCE6A"; +const COLOR_NEEDS_IMPROVEMENT = "#FFA400"; +const COLOR_POOR = "#FF4E42"; const RATING_COLORS = { - 'good': COLOR_GOOD, - 'needs-improvement': COLOR_NEEDS_IMPROVEMENT, - 'poor': COLOR_POOR + good: COLOR_GOOD, + "needs-improvement": COLOR_NEEDS_IMPROVEMENT, + poor: COLOR_POOR, }; const observer = new PerformanceObserver((list) => { const interactions = {}; - for (const entry of list.getEntries().filter((entry) => !entry.interactionId)) { + for (const entry of list + .getEntries() + .filter((entry) => !entry.interactionId)) { interactions[entry.interactionId] = interactions[entry.interactionId] || []; interactions[entry.interactionId].push(entry); } @@ -28,48 +31,62 @@ const observer = new PerformanceObserver((list) => { // Will report as a single interaction even if parts are in separate frames. // Consider splitting by animation frame. for (const interaction of Object.values(interactions)) { - const entry = interaction.reduce((prev, curr) => prev.duration >= curr.duration ? prev : curr); + const entry = interaction.reduce((prev, curr) => + prev.duration >= curr.duration ? prev : curr, + ); const value = entry.duration; const rating = valueToRating(value); const formattedValue = `${value.toFixed(0)} ms`; console.groupCollapsed( `Interaction tracking snippet %c${formattedValue} (${rating})`, - `color: ${RATING_COLORS[rating] || 'inherit'}` + `color: ${RATING_COLORS[rating] || "inherit"}`, ); - console.log('Interaction target:', entry.target); + console.log("Interaction target:", entry.target); for (let entry of interaction) { - console.log(`Interaction event type: %c${entry.name}`, 'font-family: monospace'); + console.log( + `Interaction event type: %c${entry.name}`, + "font-family: monospace", + ); // RenderTime is an estimate, because duration is rounded, and may get rounded down. // In rare cases it can be less than processingEnd and that breaks performance.measure(). // Lets make sure its at least 4ms in those cases so you can just barely see it. - const adjustedPresentationTime = Math.max(entry.processingEnd + 4, entry.startTime + entry.duration); - - console.table([{ - subPartString: 'Input delay', - 'Time (ms)': Math.round(entry.processingStart - entry.startTime, 0), - }, - { - subPartString: 'Processing time', - 'Time (ms)': Math.round(entry.processingEnd - entry.processingStart, 0), - }, - { - subPartString: 'Presentation delay', - 'Time (ms)': Math.round(adjustedPresentationTime - entry.processingEnd, 0), - }]); + const adjustedPresentationTime = Math.max( + entry.processingEnd + 4, + entry.startTime + entry.duration, + ); + + console.table([ + { + subPartString: "Input delay", + "Time (ms)": Math.round(entry.processingStart - entry.startTime, 0), + }, + { + subPartString: "Processing time", + "Time (ms)": Math.round( + entry.processingEnd - entry.processingStart, + 0, + ), + }, + { + subPartString: "Presentation delay", + "Time (ms)": Math.round( + adjustedPresentationTime - entry.processingEnd, + 0, + ), + }, + ]); } console.groupEnd(); - } }); observer.observe({ - type: 'event', + type: "event", durationThreshold: 0, // 16 minimum by spec - buffered: true + buffered: true, }); ``` - diff --git a/pages/Interaction/Layout-Shift-Loading-and-Interaction.mdx b/pages/Interaction/Layout-Shift-Loading-and-Interaction.mdx index 9e33dd2..dedb1e1 100644 --- a/pages/Interaction/Layout-Shift-Loading-and-Interaction.mdx +++ b/pages/Interaction/Layout-Shift-Loading-and-Interaction.mdx @@ -1,4 +1,4 @@ -# Layout Shift Loading and Interaction +# Layout Shift Loading and Interaction Print all the CLS metrics during page load and when the user interacts with the page: @@ -9,4 +9,3 @@ new PerformanceObserver((entryList) => { console.log(entryList.getEntries()); }).observe({ type: "layout-shift", buffered: true }); ``` - diff --git a/pages/Interaction/Long-Animation-Frames.mdx b/pages/Interaction/Long-Animation-Frames.mdx index fcfd81b..7a0329f 100644 --- a/pages/Interaction/Long-Animation-Frames.mdx +++ b/pages/Interaction/Long-Animation-Frames.mdx @@ -1,74 +1,109 @@ # Long Animation Frames -_This snippet requires specific features that are either available in Chrome 115+ for origins that are part of [the LoAF Origin Trial](https://developer.chrome.com/origintrials/#/view_trial/3935020174414970881) or require that you enable the **#enable-experimental-web-platform-features** flag in `chrome://flags` (please note that you will need to restart your browser)._ +_This snippet requires specific features that are either available in Chrome 115+ for origins that are part of [the LoAF Origin Trial](https://developer.chrome.com/origintrials/#/view_trial/3935020174414970881) or require that you enable the **#enable-experimental-web-platform-features** flag in `chrome://flags` (please note that you will need to restart your browser)._ -To determine when long animation frames (LoAF) happen, you can use [PerformanceObserver](https://developer.mozilla.org/docs/Web/API/PerformanceObserver) and register to observe entries of type `long-animation-frame`. This snippet from [@noamr](https://github.com/noamr) provides additional informations computed from the LoAF raw data. +To determine when long animation frames (LoAF) happen, you can use [PerformanceObserver](https://developer.mozilla.org/docs/Web/API/PerformanceObserver) and register to observe entries of type `long-animation-frame`. This snippet from [@noamr](https://github.com/noamr) provides additional metrics computed from the LoAF raw data. #### Snippet ```js copy (function init() { - function processAndFilterLoAFs(entries) { - function floorObject(o) { - return Object.fromEntries(Array.from(Object.entries(o)).map(([key, value]) => - [key, typeof value === "number" ? Math.floor(value) : - value])) - } - - function processEntry(entry) { - const startTime = entry.startTime; - const endTime = entry.startTime + entry.duration; - const delay = entry.desiredRenderStart ? Math.max(0, entry.startTime - entry.desiredRenderStart) : 0; - const deferredDuration = Math.max(0, entry.desiredRenderStart - entry.startTime); - const renderDuration = entry.styleAndLayoutStart - entry.renderStart; - const workDuration = entry.renderStart ? entry.renderStart - entry.startTime : entry.duration; - const totalForcedStyleAndLayoutDuration = entry.scripts.reduce((sum, script) => sum + script.forcedStyleAndLayoutDuration, 0); - const styleAndLayoutDuration = entry.styleAndLayoutStart ? endTime - entry.styleAndLayoutStart : 0; - const scripts = entry.scripts.map(script => { - const delay = script.startTime - script.desiredExecutionStart; - const scriptEnd = script.startTime + script.duration; - const compileDuration = script.executionStart - script.startTime; - const execDuration = scriptEnd - script.executionStart; - return floorObject({delay, compileDuration, execDuration, ...script.toJSON()}); - }) - return floorObject({startTime, delay, deferredDuration, renderDuration, workDuration, styleAndLayoutDuration, totalForcedStyleAndLayoutDuration, ...entry.toJSON(), scripts}); - } + function processAndFilterLoAFs(entries) { + function floorObject(o) { + return Object.fromEntries( + Array.from(Object.entries(o)).map(([key, value]) => [ + key, + typeof value === "number" ? Math.floor(value) : value, + ]), + ); + } - return entries.map(processEntry); + function processEntry(entry) { + const startTime = entry.startTime; + const endTime = entry.startTime + entry.duration; + const delay = entry.desiredRenderStart + ? Math.max(0, entry.startTime - entry.desiredRenderStart) + : 0; + const deferredDuration = Math.max( + 0, + entry.desiredRenderStart - entry.startTime, + ); + const renderDuration = entry.styleAndLayoutStart - entry.renderStart; + const workDuration = entry.renderStart + ? entry.renderStart - entry.startTime + : entry.duration; + const totalForcedStyleAndLayoutDuration = entry.scripts.reduce( + (sum, script) => sum + script.forcedStyleAndLayoutDuration, + 0, + ); + const styleAndLayoutDuration = entry.styleAndLayoutStart + ? endTime - entry.styleAndLayoutStart + : 0; + const scripts = entry.scripts.map((script) => { + const delay = script.startTime - script.desiredExecutionStart; + const scriptEnd = script.startTime + script.duration; + const compileDuration = script.executionStart - script.startTime; + const execDuration = scriptEnd - script.executionStart; + return floorObject({ + delay, + compileDuration, + execDuration, + ...script.toJSON(), + }); + }); + return floorObject({ + startTime, + delay, + deferredDuration, + renderDuration, + workDuration, + styleAndLayoutDuration, + totalForcedStyleAndLayoutDuration, + ...entry.toJSON(), + scripts, + }); } - function analyze() { - return loafs.map(loaf => ( - { - blockingDuration: loaf.blockingDuration, - loaf, - scripts: loaf.scripts, events: events.filter(e => overlap(e, loaf)) - })).filter(l => (l.blockingDuration && l.events.length)); - } + return entries.map(processEntry); + } + function analyze() { + return loafs + .map((loaf) => ({ + blockingDuration: loaf.blockingDuration, + loaf, + scripts: loaf.scripts, + events: events.filter((e) => overlap(e, loaf)), + })) + .filter((l) => l.blockingDuration && l.events.length); + } + let loafs = []; + let events = []; + function processLoAFs(entries) { + loafs = [...loafs, ...processAndFilterLoAFs(entries.getEntries())]; + console.log(analyze()); + } - let loafs = []; - let events = []; - function processLoAFs(entries) { - loafs = [...loafs, ...processAndFilterLoAFs(entries.getEntries())]; - console.log(analyze()); - } + function processEvents(entries) { + events = [...events, ...entries.getEntries()]; + console.log(analyze()); + } + new PerformanceObserver(processLoAFs).observe({ + type: "long-animation-frame", + buffered: true, + }); + new PerformanceObserver(processEvents).observe({ + type: "event", + buffered: true, + }); - function processEvents(entries) { - events = [...events, ...entries.getEntries()]; - console.log(analyze()); - } - new PerformanceObserver(processLoAFs).observe( - {type: "long-animation-frame", buffered:true}); - new PerformanceObserver(processEvents).observe( - {type: "event", buffered:true}); - - function overlap(e1, e2) { - return e1.startTime < (e2.startTime + e2.duration) && - e2.startTime < (e1.startTime + e1.duration) - } - window.whynp = analyze; - } -)() + function overlap(e1, e2) { + return ( + e1.startTime < e2.startTime + e2.duration && + e2.startTime < e1.startTime + e1.duration + ); + } + window.whynp = analyze; +})(); ``` diff --git a/pages/Interaction/LongTask.mdx b/pages/Interaction/LongTask.mdx index d8a8c62..017e055 100644 --- a/pages/Interaction/LongTask.mdx +++ b/pages/Interaction/LongTask.mdx @@ -5,19 +5,19 @@ To determine when long tasks happen, you can use [PerformanceObserver](https://d #### Snippet ```js copy -// Count and list all the Long Tasks -// https://webperf-snippets.nucliweb.net try { const po = new PerformanceObserver((list) => { - const numLongTasks = list.getEntries().length + const numLongTasks = list.getEntries().length; for (const entry of list.getEntries()) { console.table(entry.toJSON()); } - console.log(`%cNum. Long Tasks: ${numLongTasks}`,'color: #FF4E42; font-weight: bold') + console.log( + `%cNum. Long Tasks: ${numLongTasks}`, + "color: #FF4E42; font-weight: bold", + ); }); po.observe({ type: "longtask", buffered: true }); } catch (e) { console.error(`The browser doesn't support this API`); } ``` - diff --git a/pages/Loading/Find-Above-The-Fold-Lazy-Loaded-Images.mdx b/pages/Loading/Find-Above-The-Fold-Lazy-Loaded-Images.mdx index 670a3b0..3f5b21c 100644 --- a/pages/Loading/Find-Above-The-Fold-Lazy-Loaded-Images.mdx +++ b/pages/Loading/Find-Above-The-Fold-Lazy-Loaded-Images.mdx @@ -16,9 +16,10 @@ function findATFLazyLoadedImages() { lazyImages = [...lazyImages, tag]; } }); - return lazyImages.length > 0 ? lazyImages : "Good job, the site does not have any lazily loaded images in the viewport."; + return lazyImages.length > 0 + ? lazyImages + : "Good job, the site does not have any lazily loaded images in the viewport."; } console.log(findATFLazyLoadedImages()); ``` - diff --git a/pages/Loading/Find-Images-With-Lazy-and-Fetchpriority.mdx b/pages/Loading/Find-Images-With-Lazy-and-Fetchpriority.mdx index ec66d93..aedaac7 100644 --- a/pages/Loading/Find-Images-With-Lazy-and-Fetchpriority.mdx +++ b/pages/Loading/Find-Images-With-Lazy-and-Fetchpriority.mdx @@ -2,7 +2,7 @@ List all images that have `loading="lazy"` and `fetchpriority=high`. -> In reality you probably wouldn't really want `loading=lazy` and `fetchpriority=high` at the same time. That would mean don't load it initially, but when you start to load it, load it with high priority. Which is kind of contradictory! - [Barry Pollard](https://twitter.com/tunetheweb/status/1714750391890444582) +> In reality you probably wouldn't really want `loading=lazy` and `fetchpriority=high` at the same time. That would mean don't load it initially, but when you start to load it, load it with high priority. Which is kind of contradictory! - [Barry Pollard](https://twitter.com/tunetheweb/status/1714750391890444582) ### Attribution @@ -12,22 +12,30 @@ This snippet code it's based in the [script](https://twitter.com/csswizardry/sta ```js copy const MESSAGES = { - good: `The current rendered code, don't have elements with loading="lazy" fetchpriority="high"`, - bad: "In reality you probably wouldnt really want `loading=lazy` and `fetchpriority=high` at the same time. That would mean don't load it initially, but when you start to load it, load it with high priority. Which is kind of contradictory!" -} -const elementsLazyFetchpriority = document.querySelectorAll("[loading=lazy][fetchpriority=high]") -const numLazyFetchpriority = elementsLazyFetchpriority.length -const hasLazyFetchpriority = numLazyFetchpriority > 0 - + good: `The current rendered code, don't have elements with loading="lazy" fetchpriority="high"`, + bad: "In reality you probably wouldnt really want `loading=lazy` and `fetchpriority=high` at the same time. That would mean don't load it initially, but when you start to load it, load it with high priority. Which is kind of contradictory!", +}; +const elementsLazyFetchpriority = document.querySelectorAll( + "[loading=lazy][fetchpriority=high]", +); +const numLazyFetchpriority = elementsLazyFetchpriority.length; +const hasLazyFetchpriority = numLazyFetchpriority > 0; if (hasLazyFetchpriority) { - console.log(`%c The page has ${numLazyFetchpriority} image(s) with loading="lazy" fetchpriority="high"`, 'background: #222; color: lightcoral; padding: 0.5ch; font-size: 1.28em') - elementsLazyFetchpriority.forEach((el) => console.log(el)) - - console.log(`%c ${MESSAGES.bad}`, 'background: #222; color: lightcoral; padding: 0.5ch; margin-top: 1em') + console.log( + `%c The page has ${numLazyFetchpriority} image(s) with loading="lazy" fetchpriority="high"`, + "background: #222; color: lightcoral; padding: 0.5ch; font-size: 1.28em", + ); + elementsLazyFetchpriority.forEach((el) => console.log(el)); + + console.log( + `%c ${MESSAGES.bad}`, + "background: #222; color: lightcoral; padding: 0.5ch; margin-top: 1em", + ); } else { - console.log(`%c ${MESSAGES.good}`, 'background: #222; color: lightgreen; padding: 0.5ch') + console.log( + `%c ${MESSAGES.good}`, + "background: #222; color: lightgreen; padding: 0.5ch", + ); } - - ``` diff --git a/pages/Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport.mdx b/pages/Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport.mdx index 058948e..c54bbbf 100644 --- a/pages/Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport.mdx +++ b/pages/Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport.mdx @@ -8,7 +8,7 @@ List all images that don't have `loading="lazy"` or `[data-src]` _(lazy loading // Execute it after the page has loaded without any user interaction (Scroll, click, etc) function findImgCanidatesForLazyLoading() { let notLazyImages = document.querySelectorAll( - 'img:not([data-src]):not([loading="lazy"])' + 'img:not([data-src]):not([loading="lazy"])', ); return Array.from(notLazyImages).filter((tag) => !isInViewport(tag)); } @@ -25,7 +25,6 @@ function isInViewport(tag) { console.log( "Consider lazyloading the following images: ", - findImgCanidatesForLazyLoading() + findImgCanidatesForLazyLoading(), ); ``` - diff --git a/pages/Loading/Find-render-blocking-resources.mdx b/pages/Loading/Find-render-blocking-resources.mdx index 543842d..b50c995 100644 --- a/pages/Loading/Find-render-blocking-resources.mdx +++ b/pages/Loading/Find-render-blocking-resources.mdx @@ -7,19 +7,35 @@ List all resources that are blocking rendering. #### Snippet ```js copy -function RenderBlocking({startTime, duration, responseEnd, name, initiatorType}) { - this.startTime = startTime - this.duration = duration - this.responseEnd = responseEnd - this.name = name - this.initiatorType = initiatorType +function RenderBlocking({ + startTime, + duration, + responseEnd, + name, + initiatorType, +}) { + this.startTime = startTime; + this.duration = duration; + this.responseEnd = responseEnd; + this.name = name; + this.initiatorType = initiatorType; } function findRenderBlockingResources() { - return window.performance.getEntriesByType('resource') - .filter(({renderBlockingStatus}) => renderBlockingStatus === 'blocking') - .map(({startTime, duration, responseEnd, name, initiatorType}) => new RenderBlocking({startTime, duration, responseEnd, name, initiatorType})); + return window.performance + .getEntriesByType("resource") + .filter(({ renderBlockingStatus }) => renderBlockingStatus === "blocking") + .map( + ({ startTime, duration, responseEnd, name, initiatorType }) => + new RenderBlocking({ + startTime, + duration, + responseEnd, + name, + initiatorType, + }), + ); } -console.table(findRenderBlockingResources()) +console.table(findRenderBlockingResources()); ``` diff --git a/pages/Loading/First-And-Third-Party-Script-Info.mdx b/pages/Loading/First-And-Third-Party-Script-Info.mdx index ccd3064..44d6458 100644 --- a/pages/Loading/First-And-Third-Party-Script-Info.mdx +++ b/pages/Loading/First-And-Third-Party-Script-Info.mdx @@ -64,4 +64,3 @@ console.groupCollapsed("THIRD PARTY SCRIPTS"); console.table(thirdParty); console.groupEnd(); ``` - diff --git a/pages/Loading/First-And-Third-Party-Script-Timings.mdx b/pages/Loading/First-And-Third-Party-Script-Timings.mdx index f3ab20e..ab5fd70 100644 --- a/pages/Loading/First-And-Third-Party-Script-Timings.mdx +++ b/pages/Loading/First-And-Third-Party-Script-Timings.mdx @@ -39,7 +39,7 @@ function createUniqueLists(firstParty, thirdParty) { const { firstPartyList, thirdPartyList } = createUniqueLists( firstParty, - thirdParty + thirdParty, ); function calculateTimings(party, type) { @@ -109,4 +109,3 @@ timingOptions.forEach((timing) => { console.table(calculateTimings("first", "REQ_START_UNTIL_RES_END")); ``` - diff --git a/pages/Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold.mdx b/pages/Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold.mdx index db6c921..c477dc2 100644 --- a/pages/Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold.mdx +++ b/pages/Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold.mdx @@ -9,7 +9,10 @@ const linkElements = document.querySelectorAll(`link[rel="preload"]`); const arrayLinks = Array.from(linkElements); const preloadedFonts = arrayLinks.filter((link) => link.as === "font"); -console.log("%cFonts Preloaded via Resources Hints", "font-weight: bold; font-size: 1.2em; color: lightcoral"); +console.log( + "%cFonts Preloaded via Resources Hints", + "font-weight: bold; font-size: 1.2em; color: lightcoral", +); preloadedFonts.forEach((font) => console.log(`▸ ${font.href}`)); console.log(""); @@ -18,18 +21,21 @@ const loadedFonts = [ Array.from(document.fonts.values()) .map((font) => font) .filter((font) => font.status === "loaded") - .map((font) => `${font.family} - ${font.weight} - ${font.style}`) + .map((font) => `${font.family} - ${font.weight} - ${font.style}`), ), ]; -console.log("%cFonts and Weights Loaded in the Document", "font-weight: bold; font-size: 1.2em; color: lightcoral"); +console.log( + "%cFonts and Weights Loaded in the Document", + "font-weight: bold; font-size: 1.2em; color: lightcoral", +); loadedFonts.forEach((font) => console.log(`▸ ${font}`)); console.log(""); const childrenSlector = "body * > *:not(script):not(style):not(link):not(source)"; const aboveFoldElements = Array.from( - document.querySelectorAll(childrenSlector) + document.querySelectorAll(childrenSlector), ).filter((elm) => { const rect = elm.getBoundingClientRect(); return ( @@ -47,12 +53,14 @@ const usedFonts = Array.from( (e) => `${getComputedStyle(e).fontFamily} | ${ getComputedStyle(e).fontWeight - } | ${getComputedStyle(e).fontStyle}` - ) - ) + } | ${getComputedStyle(e).fontStyle}`, + ), + ), ); -console.log("%cFonts and Weights Used Above the Fold", "font-weight: bold; font-size: 1.2em; color: lightcoral"); +console.log( + "%cFonts and Weights Used Above the Fold", + "font-weight: bold; font-size: 1.2em; color: lightcoral", +); usedFonts.forEach((font) => console.log(`▸ ${font}`)); ``` - diff --git a/pages/Loading/Get-Your-Head-in-Order.mdx b/pages/Loading/Get-Your-Head-in-Order.mdx index f981bc0..d975e80 100644 --- a/pages/Loading/Get-Your-Head-in-Order.mdx +++ b/pages/Loading/Get-Your-Head-in-Order.mdx @@ -2,35 +2,40 @@ How you order elements in the `
` can have an effect on the (perceived) performance of the page. -This snippet code it's from [capo.js](https://github.com/rviscomi/capo.js) the [Rick Viscomi](https://twitter.com/rviscomi) script +This snippet code is from [capo.js](https://github.com/rviscomi/capo.js) the [Rick Viscomi](https://twitter.com/rviscomi) script #### Snippet ```js copy (() => { -function $parcel$export(e, n, v, s) { - Object.defineProperty(e, n, {get: v, set: s, enumerable: true, configurable: true}); -} -const $eb5be8077a65b10b$var$Hues = { + function $parcel$export(e, n, v, s) { + Object.defineProperty(e, n, { + get: v, + set: s, + enumerable: true, + configurable: true, + }); + } + const $eb5be8077a65b10b$var$Hues = { PINK: 320, - BLUE: 200 -}; -function $eb5be8077a65b10b$export$921514c0345db5eb(hue) { + BLUE: 200, + }; + function $eb5be8077a65b10b$export$921514c0345db5eb(hue) { return [ - `oklch(5% .1 ${hue})`, - `oklch(13% .2 ${hue})`, - `oklch(25% .2 ${hue})`, - `oklch(35% .25 ${hue})`, - `oklch(50% .27 ${hue})`, - `oklch(67% .31 ${hue})`, - `oklch(72% .25 ${hue})`, - `oklch(80% .2 ${hue})`, - `oklch(90% .1 ${hue})`, - `oklch(99% .05 ${hue})`, - "#ccc" + `oklch(5% .1 ${hue})`, + `oklch(13% .2 ${hue})`, + `oklch(25% .2 ${hue})`, + `oklch(35% .25 ${hue})`, + `oklch(50% .27 ${hue})`, + `oklch(67% .31 ${hue})`, + `oklch(72% .25 ${hue})`, + `oklch(80% .2 ${hue})`, + `oklch(90% .1 ${hue})`, + `oklch(99% .05 ${hue})`, + "#ccc", ]; -} -const $eb5be8077a65b10b$export$e6952b12ade67489 = [ + } + const $eb5be8077a65b10b$export$e6952b12ade67489 = [ "#9e0142", "#d53e4f", "#f46d43", @@ -41,299 +46,463 @@ const $eb5be8077a65b10b$export$e6952b12ade67489 = [ "#66c2a5", "#3288bd", "#5e4fa2", - "#cccccc" -]; -const $eb5be8077a65b10b$export$d68d0fda4a10dbc2 = $eb5be8077a65b10b$export$921514c0345db5eb($eb5be8077a65b10b$var$Hues.PINK); -const $eb5be8077a65b10b$export$738c3b9a44c87ecc = $eb5be8077a65b10b$export$921514c0345db5eb($eb5be8077a65b10b$var$Hues.BLUE); -const $eb5be8077a65b10b$export$9a82c28ef488e918 = { + "#cccccc", + ]; + const $eb5be8077a65b10b$export$d68d0fda4a10dbc2 = + $eb5be8077a65b10b$export$921514c0345db5eb($eb5be8077a65b10b$var$Hues.PINK); + const $eb5be8077a65b10b$export$738c3b9a44c87ecc = + $eb5be8077a65b10b$export$921514c0345db5eb($eb5be8077a65b10b$var$Hues.BLUE); + const $eb5be8077a65b10b$export$9a82c28ef488e918 = { DEFAULT: $eb5be8077a65b10b$export$e6952b12ade67489, PINK: $eb5be8077a65b10b$export$d68d0fda4a10dbc2, - BLUE: $eb5be8077a65b10b$export$738c3b9a44c87ecc -}; -function $eb5be8077a65b10b$export$18c940335d915715(elementColor) { + BLUE: $eb5be8077a65b10b$export$738c3b9a44c87ecc, + }; + function $eb5be8077a65b10b$export$18c940335d915715(elementColor) { let invalidColor = "#cccccc"; if (elementColor == invalidColor) invalidColor = "red"; return `repeating-linear-gradient(45deg, ${elementColor}, ${elementColor} 3px, ${invalidColor} 3px, ${invalidColor} 6px)`; -} - + } -var $d410929ede0a2ee4$exports = {}; + var $d410929ede0a2ee4$exports = {}; -$parcel$export($d410929ede0a2ee4$exports, "IO", () => $d410929ede0a2ee4$export$8f8422ac5947a789); + $parcel$export( + $d410929ede0a2ee4$exports, + "IO", + () => $d410929ede0a2ee4$export$8f8422ac5947a789, + ); -class $d410929ede0a2ee4$export$8f8422ac5947a789 { - constructor(document1, options, output = window.console){ - this.document = document1; - this.options = options; - this.console = output; - this.isStaticHead = false; - this.head = null; + class $d410929ede0a2ee4$export$8f8422ac5947a789 { + constructor(document1, options, output = window.console) { + this.document = document1; + this.options = options; + this.console = output; + this.isStaticHead = false; + this.head = null; } async init() { - if (this.head) return; - if (this.options.prefersDynamicAssessment()) { - this.head = this.document.querySelector("head"); - return; - } - try { - let html = await this.getStaticHTML(); - html = html.replace(/(\<\/?)(head)/ig, "$1static-head"); - const staticDoc = this.document.implementation.createHTMLDocument("New Document"); - staticDoc.documentElement.innerHTML = html; - this.head = staticDoc.querySelector("static-head"); - if (this.head) this.isStaticHead = true; - else this.head = this.document.head; - } catch (e) { - this.console.error(`${this.options.loggingPrefix}An exception occurred while getting the static :`, e); - this.head = this.document.head; - } - if (!this.isStaticHead) this.console.warn(`${this.options.loggingPrefix}Unable to parse the static (server-rendered) . Falling back to document.head`, this.head); + if (this.head) return; + if (this.options.prefersDynamicAssessment()) { + this.head = this.document.querySelector("head"); + return; + } + try { + let html = await this.getStaticHTML(); + html = html.replace(/(\<\/?)(head)/gi, "$1static-head"); + const staticDoc = + this.document.implementation.createHTMLDocument("New Document"); + staticDoc.documentElement.innerHTML = html; + this.head = staticDoc.querySelector("static-head"); + if (this.head) this.isStaticHead = true; + else this.head = this.document.head; + } catch (e) { + this.console.error( + `${this.options.loggingPrefix}An exception occurred while getting the static :`, + e, + ); + this.head = this.document.head; + } + if (!this.isStaticHead) + this.console.warn( + `${this.options.loggingPrefix}Unable to parse the static (server-rendered) . Falling back to document.head`, + this.head, + ); } async getStaticHTML() { - const url = this.document.location.href; - const response = await fetch(url); - return await response.text(); + const url = this.document.location.href; + const response = await fetch(url); + return await response.text(); } getHead() { - return this.head; + return this.head; } stringifyElement(element) { - return element.getAttributeNames().reduce((id, attr)=>{ - return id += `[${CSS.escape(attr)}=${JSON.stringify(element.getAttribute(attr))}]`; - }, element.nodeName); + return element.getAttributeNames().reduce((id, attr) => { + return (id += `[${CSS.escape(attr)}=${JSON.stringify( + element.getAttribute(attr), + )}]`); + }, element.nodeName); } getLoggableElement(element) { - if (!this.isStaticHead) return element; - const selector = this.stringifyElement(element); - const candidates = Array.from(this.document.head.querySelectorAll(selector)); - if (candidates.length == 0) return element; - if (candidates.length == 1) return candidates[0]; - // The way the static elements are parsed makes their innerHTML different. - // Recreate the element in DOM and compare its innerHTML with those of the candidates. - // This ensures a consistent parsing and positive string matches. - const candidateWrapper = this.document.createElement("div"); - const elementWrapper = this.document.createElement("div"); - elementWrapper.innerHTML = element.innerHTML; - const candidate = candidates.find((c)=>{ - candidateWrapper.innerHTML = c.innerHTML; - return candidateWrapper.innerHTML == elementWrapper.innerHTML; - }); - if (candidate) return candidate; - return element; + if (!this.isStaticHead) return element; + const selector = this.stringifyElement(element); + const candidates = Array.from( + this.document.head.querySelectorAll(selector), + ); + if (candidates.length == 0) return element; + if (candidates.length == 1) return candidates[0]; + // The way the static elements are parsed makes their innerHTML different. + // Recreate the element in DOM and compare its innerHTML with those of the candidates. + // This ensures a consistent parsing and positive string matches. + const candidateWrapper = this.document.createElement("div"); + const elementWrapper = this.document.createElement("div"); + elementWrapper.innerHTML = element.innerHTML; + const candidate = candidates.find((c) => { + candidateWrapper.innerHTML = c.innerHTML; + return candidateWrapper.innerHTML == elementWrapper.innerHTML; + }); + if (candidate) return candidate; + return element; } // Note: AI-generated function. createElementFromSelector(selector) { - // Extract the tag name from the selector - const tagName = selector.match(/^[A-Za-z]+/)[0]; - if (!tagName) return; - // Create the new element - const element = document.createElement(tagName); - // Extract the attribute key-value pairs from the selector - const attributes = selector.match(/\[([A-Za-z-]+)="([^"]+)"\]/g) || []; - // Set the attributes on the new element - attributes.forEach((attribute)=>{ - const [key, value] = attribute.replace("[", "").replace("]", "").split("="); - element.setAttribute(key, value.slice(1, -1)); - }); - return element; - } - logElementFromSelector({ weight: weight, selector: selector, innerHTML: innerHTML, isValid: isValid, customValidations: customValidations = {} }) { - weight = +weight; - const viz = this.getElementVisualization(weight); - let element = this.createElementFromSelector(selector); - element.innerHTML = innerHTML; - element = this.getLoggableElement(element); - this.logElement({ - viz: viz, - weight: weight, - element: element, - isValid: isValid, - customValidations: customValidations - }); - } - logElement({ viz: viz, weight: weight, element: element, isValid: isValid, customValidations: customValidations, omitPrefix: omitPrefix = false }) { - if (!omitPrefix) viz.visual = `${this.options.loggingPrefix}${viz.visual}`; - let loggingLevel = "log"; - const args = [ - viz.visual, - viz.style, - weight + 1, - element - ]; - if (!this.options.isValidationEnabled()) { - this.console[loggingLevel](...args); - return; - } - const { payload: payload, warnings: warnings } = customValidations; - if (payload) args.push(payload); - if (warnings?.length) { - // Element-specific warnings. - loggingLevel = "warn"; - warnings.forEach((warning)=>args.push(`❌ ${warning}`)); - } else if (!isValid && (this.options.prefersDynamicAssessment() || this.isStaticHead)) { - // General warnings. - loggingLevel = "warn"; - args.push(`❌ invalid element (${element.tagName})`); - } + // Extract the tag name from the selector + const tagName = selector.match(/^[A-Za-z]+/)[0]; + if (!tagName) return; + // Create the new element + const element = document.createElement(tagName); + // Extract the attribute key-value pairs from the selector + const attributes = selector.match(/\[([A-Za-z-]+)="([^"]+)"\]/g) || []; + // Set the attributes on the new element + attributes.forEach((attribute) => { + const [key, value] = attribute + .replace("[", "") + .replace("]", "") + .split("="); + element.setAttribute(key, value.slice(1, -1)); + }); + return element; + } + logElementFromSelector({ + weight: weight, + selector: selector, + innerHTML: innerHTML, + isValid: isValid, + customValidations: customValidations = {}, + }) { + weight = +weight; + const viz = this.getElementVisualization(weight); + let element = this.createElementFromSelector(selector); + element.innerHTML = innerHTML; + element = this.getLoggableElement(element); + this.logElement({ + viz: viz, + weight: weight, + element: element, + isValid: isValid, + customValidations: customValidations, + }); + } + logElement({ + viz: viz, + weight: weight, + element: element, + isValid: isValid, + customValidations: customValidations, + omitPrefix: omitPrefix = false, + }) { + if (!omitPrefix) + viz.visual = `${this.options.loggingPrefix}${viz.visual}`; + let loggingLevel = "log"; + const args = [viz.visual, viz.style, weight + 1, element]; + if (!this.options.isValidationEnabled()) { this.console[loggingLevel](...args); + return; + } + const { payload: payload, warnings: warnings } = customValidations; + if (payload) args.push(payload); + if (warnings?.length) { + // Element-specific warnings. + loggingLevel = "warn"; + warnings.forEach((warning) => args.push(`❌ ${warning}`)); + } else if ( + !isValid && + (this.options.prefersDynamicAssessment() || this.isStaticHead) + ) { + // General warnings. + loggingLevel = "warn"; + args.push(`❌ invalid element (${element.tagName})`); + } + this.console[loggingLevel](...args); } logValidationWarnings(warnings) { - if (!this.options.isValidationEnabled()) return; - warnings.forEach(({ warning: warning, elements: elements = [], element: element })=>{ - elements = elements.map(this.getLoggableElement.bind(this)); - this.console.warn(`${this.options.loggingPrefix}${warning}`, ...elements, element || ""); - }); + if (!this.options.isValidationEnabled()) return; + warnings.forEach( + ({ warning: warning, elements: elements = [], element: element }) => { + elements = elements.map(this.getLoggableElement.bind(this)); + this.console.warn( + `${this.options.loggingPrefix}${warning}`, + ...elements, + element || "", + ); + }, + ); } getColor(weight) { - return this.options.palette[10 - weight]; + return this.options.palette[10 - weight]; } getHeadVisualization(elements) { - let visual = ""; - const styles = []; - elements.forEach(({ weight: weight, isValid: isValid })=>{ - visual += "%c "; - const color = this.getColor(weight); - let style = `padding: 5px; margin: 0 -1px; `; - if (isValid) style += `background-color: ${color};`; - else style += `background-image: ${(0, $eb5be8077a65b10b$export$18c940335d915715)(color)}`; - styles.push(style); - }); - return { - visual: visual, - styles: styles - }; + let visual = ""; + const styles = []; + elements.forEach(({ weight: weight, isValid: isValid }) => { + visual += "%c "; + const color = this.getColor(weight); + let style = `padding: 5px; margin: 0 -1px; `; + if (isValid) style += `background-color: ${color};`; + else + style += `background-image: ${(0, + $eb5be8077a65b10b$export$18c940335d915715)(color)}`; + styles.push(style); + }); + return { + visual: visual, + styles: styles, + }; } getElementVisualization(weight) { - const visual = `%c${new Array(weight + 1).fill("█").join("")}`; - const color = this.getColor(weight); - const style = `color: ${color}`; - return { - visual: visual, - style: style - }; + const visual = `%c${new Array(weight + 1).fill("█").join("")}`; + const color = this.getColor(weight); + const style = `color: ${color}`; + return { + visual: visual, + style: style, + }; } visualizeHead(groupName, headElement, headWeights) { - const headViz = this.getHeadVisualization(headWeights); - this.console.groupCollapsed(`${this.options.loggingPrefix}${groupName} %chead%c order\n${headViz.visual}`, "font-family: monospace", "font-family: inherit", ...headViz.styles); - headWeights.forEach(({ weight: weight, element: element, isValid: isValid, customValidations: customValidations })=>{ - const viz = this.getElementVisualization(weight); - this.logElement({ - viz: viz, - weight: weight, - element: element, - isValid: isValid, - customValidations: customValidations, - omitPrefix: true - }); - }); - this.console.log(`${groupName} %chead%c element`, "font-family: monospace", "font-family: inherit", headElement); - this.console.groupEnd(); - } -} - + const headViz = this.getHeadVisualization(headWeights); + this.console.groupCollapsed( + `${this.options.loggingPrefix}${groupName} %chead%c order\n${headViz.visual}`, + "font-family: monospace", + "font-family: inherit", + ...headViz.styles, + ); + headWeights.forEach( + ({ + weight: weight, + element: element, + isValid: isValid, + customValidations: customValidations, + }) => { + const viz = this.getElementVisualization(weight); + this.logElement({ + viz: viz, + weight: weight, + element: element, + isValid: isValid, + customValidations: customValidations, + omitPrefix: true, + }); + }, + ); + this.console.log( + `${groupName} %chead%c element`, + "font-family: monospace", + "font-family: inherit", + headElement, + ); + this.console.groupEnd(); + } + } -var $5b739339de321a37$exports = {}; + var $5b739339de321a37$exports = {}; -$parcel$export($5b739339de321a37$exports, "Options", () => $5b739339de321a37$export$c019608e5b5bb4cb); + $parcel$export( + $5b739339de321a37$exports, + "Options", + () => $5b739339de321a37$export$c019608e5b5bb4cb, + ); -class $5b739339de321a37$export$c019608e5b5bb4cb { - constructor({ preferredAssessmentMode: preferredAssessmentMode = $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.STATIC, validation: validation = true, palette: palette = $eb5be8077a65b10b$export$e6952b12ade67489, loggingPrefix: loggingPrefix = "Capo: " } = {}){ - this.setPreferredAssessmentMode(preferredAssessmentMode); - this.setValidation(validation); - this.setPalette(palette); - this.setLoggingPrefix(loggingPrefix); + class $5b739339de321a37$export$c019608e5b5bb4cb { + constructor({ + preferredAssessmentMode: + preferredAssessmentMode = $5b739339de321a37$export$c019608e5b5bb4cb + .AssessmentMode.STATIC, + validation: validation = true, + palette: palette = $eb5be8077a65b10b$export$e6952b12ade67489, + loggingPrefix: loggingPrefix = "Capo: ", + } = {}) { + this.setPreferredAssessmentMode(preferredAssessmentMode); + this.setValidation(validation); + this.setPalette(palette); + this.setLoggingPrefix(loggingPrefix); } static get AssessmentMode() { - return { - STATIC: "static", - DYNAMIC: "dynamic" - }; + return { + STATIC: "static", + DYNAMIC: "dynamic", + }; } static get Palettes() { - return $eb5be8077a65b10b$export$9a82c28ef488e918; + return $eb5be8077a65b10b$export$9a82c28ef488e918; } prefersStaticAssessment() { - return this.preferredAssessmentMode === $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.STATIC; + return ( + this.preferredAssessmentMode === + $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.STATIC + ); } prefersDynamicAssessment() { - return this.preferredAssessmentMode === $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.DYNAMIC; + return ( + this.preferredAssessmentMode === + $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.DYNAMIC + ); } isValidationEnabled() { - return this.validation; + return this.validation; } setPreferredAssessmentMode(preferredAssessmentMode) { - if (!this.isValidAssessmentMode(preferredAssessmentMode)) throw new Error(`Invalid option: preferred assessment mode, expected AssessmentMode.STATIC or AssessmentMode.DYNAMIC, got "${preferredAssessmentMode}".`); - this.preferredAssessmentMode = preferredAssessmentMode; + if (!this.isValidAssessmentMode(preferredAssessmentMode)) + throw new Error( + `Invalid option: preferred assessment mode, expected AssessmentMode.STATIC or AssessmentMode.DYNAMIC, got "${preferredAssessmentMode}".`, + ); + this.preferredAssessmentMode = preferredAssessmentMode; } setPreferredAssessmentModeToStatic(prefersStatic) { - let mode = $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.STATIC; - if (!prefersStatic) mode = $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.DYNAMIC; - this.setPreferredAssessmentMode(mode); + let mode = + $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.STATIC; + if (!prefersStatic) + mode = $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode.DYNAMIC; + this.setPreferredAssessmentMode(mode); } setValidation(validation) { - if (!this.isValidValidation(validation)) throw new Error(`Invalid option: validation, expected boolean, got "${validation}".`); - this.validation = validation; + if (!this.isValidValidation(validation)) + throw new Error( + `Invalid option: validation, expected boolean, got "${validation}".`, + ); + this.validation = validation; } setPalette(palette) { - if (!this.isValidPalette(palette)) throw new Error(`Invalid option: palette, expected [${Object.keys($eb5be8077a65b10b$export$9a82c28ef488e918).join("|")}] or an array of colors, got "${palette}".`); - if (typeof palette === "string") { - this.palette = $eb5be8077a65b10b$export$9a82c28ef488e918[palette]; - return; - } - this.palette = palette; + if (!this.isValidPalette(palette)) + throw new Error( + `Invalid option: palette, expected [${Object.keys( + $eb5be8077a65b10b$export$9a82c28ef488e918, + ).join("|")}] or an array of colors, got "${palette}".`, + ); + if (typeof palette === "string") { + this.palette = $eb5be8077a65b10b$export$9a82c28ef488e918[palette]; + return; + } + this.palette = palette; } setLoggingPrefix(loggingPrefix) { - if (!this.isValidLoggingPrefix(loggingPrefix)) throw new Error(`Invalid option: logging prefix, expected string, got "${loggingPrefix}".`); - this.loggingPrefix = loggingPrefix; + if (!this.isValidLoggingPrefix(loggingPrefix)) + throw new Error( + `Invalid option: logging prefix, expected string, got "${loggingPrefix}".`, + ); + this.loggingPrefix = loggingPrefix; } isValidAssessmentMode(assessmentMode) { - return Object.values($5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode).includes(assessmentMode); + return Object.values( + $5b739339de321a37$export$c019608e5b5bb4cb.AssessmentMode, + ).includes(assessmentMode); } isValidValidation(validation) { - return typeof validation === "boolean"; + return typeof validation === "boolean"; } isValidPalette(palette) { - if (typeof palette === "string") return Object.keys($eb5be8077a65b10b$export$9a82c28ef488e918).includes(palette); - if (!Array.isArray(palette)) return false; - return palette.length === 11 && palette.every((color)=>typeof color === "string"); + if (typeof palette === "string") + return Object.keys($eb5be8077a65b10b$export$9a82c28ef488e918).includes( + palette, + ); + if (!Array.isArray(palette)) return false; + return ( + palette.length === 11 && + palette.every((color) => typeof color === "string") + ); } isValidLoggingPrefix(loggingPrefix) { - return typeof loggingPrefix === "string"; + return typeof loggingPrefix === "string"; } isPreferredPalette(palette) { - return JSON.stringify(this.palette) == JSON.stringify(palette); + return JSON.stringify(this.palette) == JSON.stringify(palette); } valueOf() { - return { - preferredAssessmentMode: this.preferredAssessmentMode, - validation: this.validation, - palette: this.palette, - loggingPrefix: this.loggingPrefix - }; - } -} + return { + preferredAssessmentMode: this.preferredAssessmentMode, + validation: this.validation, + palette: this.palette, + loggingPrefix: this.loggingPrefix, + }; + } + } + var $9c3989fcb9437829$exports = {}; -var $9c3989fcb9437829$exports = {}; - -$parcel$export($9c3989fcb9437829$exports, "ElementWeights", () => $9c3989fcb9437829$export$881088883fcab450); -$parcel$export($9c3989fcb9437829$exports, "ElementDetectors", () => $9c3989fcb9437829$export$6ade8bb3620eb74b); -$parcel$export($9c3989fcb9437829$exports, "isMeta", () => $9c3989fcb9437829$export$daeb0db0c224decd); -$parcel$export($9c3989fcb9437829$exports, "isTitle", () => $9c3989fcb9437829$export$e55aad21605f020a); -$parcel$export($9c3989fcb9437829$exports, "isPreconnect", () => $9c3989fcb9437829$export$a3316bd0a640eb8b); -$parcel$export($9c3989fcb9437829$exports, "isAsyncScript", () => $9c3989fcb9437829$export$20e2051ffd813ee3); -$parcel$export($9c3989fcb9437829$exports, "isImportStyles", () => $9c3989fcb9437829$export$be443fc6335656f0); -$parcel$export($9c3989fcb9437829$exports, "isSyncScript", () => $9c3989fcb9437829$export$65983fc0a5543400); -$parcel$export($9c3989fcb9437829$exports, "isSyncStyles", () => $9c3989fcb9437829$export$9d6cdbffb13bee21); -$parcel$export($9c3989fcb9437829$exports, "isPreload", () => $9c3989fcb9437829$export$226ad5ba23be83f0); -$parcel$export($9c3989fcb9437829$exports, "isDeferScript", () => $9c3989fcb9437829$export$3d269f86e8bd1d24); -$parcel$export($9c3989fcb9437829$exports, "isPrefetchPrerender", () => $9c3989fcb9437829$export$4d2ed086e1fec499); -$parcel$export($9c3989fcb9437829$exports, "META_HTTP_EQUIV_KEYWORDS", () => $9c3989fcb9437829$export$b7417cf4a2235f73); -$parcel$export($9c3989fcb9437829$exports, "isOriginTrial", () => $9c3989fcb9437829$export$38a04d482ec50f88); -$parcel$export($9c3989fcb9437829$exports, "isMetaCSP", () => $9c3989fcb9437829$export$14b1a2f64a600585); -$parcel$export($9c3989fcb9437829$exports, "getWeight", () => $9c3989fcb9437829$export$de32fe5d64aee40c); -$parcel$export($9c3989fcb9437829$exports, "getHeadWeights", () => $9c3989fcb9437829$export$5cc4a311ddbe699c); -const $9c3989fcb9437829$export$881088883fcab450 = { + $parcel$export( + $9c3989fcb9437829$exports, + "ElementWeights", + () => $9c3989fcb9437829$export$881088883fcab450, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "ElementDetectors", + () => $9c3989fcb9437829$export$6ade8bb3620eb74b, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isMeta", + () => $9c3989fcb9437829$export$daeb0db0c224decd, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isTitle", + () => $9c3989fcb9437829$export$e55aad21605f020a, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isPreconnect", + () => $9c3989fcb9437829$export$a3316bd0a640eb8b, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isAsyncScript", + () => $9c3989fcb9437829$export$20e2051ffd813ee3, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isImportStyles", + () => $9c3989fcb9437829$export$be443fc6335656f0, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isSyncScript", + () => $9c3989fcb9437829$export$65983fc0a5543400, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isSyncStyles", + () => $9c3989fcb9437829$export$9d6cdbffb13bee21, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isPreload", + () => $9c3989fcb9437829$export$226ad5ba23be83f0, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isDeferScript", + () => $9c3989fcb9437829$export$3d269f86e8bd1d24, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isPrefetchPrerender", + () => $9c3989fcb9437829$export$4d2ed086e1fec499, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "META_HTTP_EQUIV_KEYWORDS", + () => $9c3989fcb9437829$export$b7417cf4a2235f73, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isOriginTrial", + () => $9c3989fcb9437829$export$38a04d482ec50f88, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "isMetaCSP", + () => $9c3989fcb9437829$export$14b1a2f64a600585, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "getWeight", + () => $9c3989fcb9437829$export$de32fe5d64aee40c, + ); + $parcel$export( + $9c3989fcb9437829$exports, + "getHeadWeights", + () => $9c3989fcb9437829$export$5cc4a311ddbe699c, + ); + const $9c3989fcb9437829$export$881088883fcab450 = { META: 10, TITLE: 9, PRECONNECT: 8, @@ -344,9 +513,9 @@ const $9c3989fcb9437829$export$881088883fcab450 = { PRELOAD: 3, DEFER_SCRIPT: 2, PREFETCH_PRERENDER: 1, - OTHER: 0 -}; -const $9c3989fcb9437829$export$6ade8bb3620eb74b = { + OTHER: 0, + }; + const $9c3989fcb9437829$export$6ade8bb3620eb74b = { META: $9c3989fcb9437829$export$daeb0db0c224decd, TITLE: $9c3989fcb9437829$export$e55aad21605f020a, PRECONNECT: $9c3989fcb9437829$export$a3316bd0a640eb8b, @@ -356,33 +525,37 @@ const $9c3989fcb9437829$export$6ade8bb3620eb74b = { SYNC_STYLES: $9c3989fcb9437829$export$9d6cdbffb13bee21, PRELOAD: $9c3989fcb9437829$export$226ad5ba23be83f0, DEFER_SCRIPT: $9c3989fcb9437829$export$3d269f86e8bd1d24, - PREFETCH_PRERENDER: $9c3989fcb9437829$export$4d2ed086e1fec499 -}; -const $9c3989fcb9437829$export$b7417cf4a2235f73 = [ + PREFETCH_PRERENDER: $9c3989fcb9437829$export$4d2ed086e1fec499, + }; + const $9c3989fcb9437829$export$b7417cf4a2235f73 = [ "accept-ch", "content-security-policy", "content-type", "default-style", "delegate-ch", "origin-trial", - "x-dns-prefetch-control" -]; -function $9c3989fcb9437829$export$daeb0db0c224decd(element) { - const httpEquivSelector = $9c3989fcb9437829$export$b7417cf4a2235f73.map((keyword)=>{ + "x-dns-prefetch-control", + ]; + function $9c3989fcb9437829$export$daeb0db0c224decd(element) { + const httpEquivSelector = $9c3989fcb9437829$export$b7417cf4a2235f73 + .map((keyword) => { return `[http-equiv="${keyword}" i]`; - }).join(", "); - return element.matches(`meta:is([charset], ${httpEquivSelector}, [name=viewport]), base`); -} -function $9c3989fcb9437829$export$e55aad21605f020a(element) { + }) + .join(", "); + return element.matches( + `meta:is([charset], ${httpEquivSelector}, [name=viewport]), base`, + ); + } + function $9c3989fcb9437829$export$e55aad21605f020a(element) { return element.matches("title"); -} -function $9c3989fcb9437829$export$a3316bd0a640eb8b(element) { + } + function $9c3989fcb9437829$export$a3316bd0a640eb8b(element) { return element.matches("link[rel=preconnect]"); -} -function $9c3989fcb9437829$export$20e2051ffd813ee3(element) { + } + function $9c3989fcb9437829$export$20e2051ffd813ee3(element) { return element.matches("script[src][async]"); -} -function $9c3989fcb9437829$export$be443fc6335656f0(element) { + } + function $9c3989fcb9437829$export$be443fc6335656f0(element) { const importRe = /@import/; if (element.matches("style")) return importRe.test(element.textContent); /* TODO: Support external stylesheets. @@ -391,55 +564,89 @@ function $9c3989fcb9437829$export$be443fc6335656f0(element) { response = response.text(); return importRe.test(response); } */ return false; -} -function $9c3989fcb9437829$export$65983fc0a5543400(element) { - return element.matches("script:not([src][defer],[src][type=module],[src][async],[type*=json])"); -} -function $9c3989fcb9437829$export$9d6cdbffb13bee21(element) { + } + function $9c3989fcb9437829$export$65983fc0a5543400(element) { + return element.matches( + "script:not([src][defer],[src][type=module],[src][async],[type*=json])", + ); + } + function $9c3989fcb9437829$export$9d6cdbffb13bee21(element) { return element.matches("link[rel=stylesheet],style"); -} -function $9c3989fcb9437829$export$226ad5ba23be83f0(element) { + } + function $9c3989fcb9437829$export$226ad5ba23be83f0(element) { return element.matches("link:is([rel=preload], [rel=modulepreload])"); -} -function $9c3989fcb9437829$export$3d269f86e8bd1d24(element) { - return element.matches("script[src][defer], script:not([src][async])[src][type=module]"); -} -function $9c3989fcb9437829$export$4d2ed086e1fec499(element) { - return element.matches("link:is([rel=prefetch], [rel=dns-prefetch], [rel=prerender])"); -} -function $9c3989fcb9437829$export$38a04d482ec50f88(element) { + } + function $9c3989fcb9437829$export$3d269f86e8bd1d24(element) { + return element.matches( + "script[src][defer], script:not([src][async])[src][type=module]", + ); + } + function $9c3989fcb9437829$export$4d2ed086e1fec499(element) { + return element.matches( + "link:is([rel=prefetch], [rel=dns-prefetch], [rel=prerender])", + ); + } + function $9c3989fcb9437829$export$38a04d482ec50f88(element) { return element.matches('meta[http-equiv="origin-trial"i]'); -} -function $9c3989fcb9437829$export$14b1a2f64a600585(element) { - return element.matches('meta[http-equiv="Content-Security-Policy" i], meta[http-equiv="Content-Security-Policy-Report-Only" i]'); -} -function $9c3989fcb9437829$export$de32fe5d64aee40c(element) { - for (let [id, detector] of Object.entries($9c3989fcb9437829$export$6ade8bb3620eb74b)){ - if (detector(element)) return $9c3989fcb9437829$export$881088883fcab450[id]; + } + function $9c3989fcb9437829$export$14b1a2f64a600585(element) { + return element.matches( + 'meta[http-equiv="Content-Security-Policy" i], meta[http-equiv="Content-Security-Policy-Report-Only" i]', + ); + } + function $9c3989fcb9437829$export$de32fe5d64aee40c(element) { + for (let [id, detector] of Object.entries( + $9c3989fcb9437829$export$6ade8bb3620eb74b, + )) { + if (detector(element)) + return $9c3989fcb9437829$export$881088883fcab450[id]; } return $9c3989fcb9437829$export$881088883fcab450.OTHER; -} -function $9c3989fcb9437829$export$5cc4a311ddbe699c(head) { + } + function $9c3989fcb9437829$export$5cc4a311ddbe699c(head) { const headChildren = Array.from(head.children); - return headChildren.map((element)=>{ - return { - element: element, - weight: $9c3989fcb9437829$export$de32fe5d64aee40c(element) - }; + return headChildren.map((element) => { + return { + element: element, + weight: $9c3989fcb9437829$export$de32fe5d64aee40c(element), + }; }); -} - + } -var $580f7ed6bc170ae8$exports = {}; + var $580f7ed6bc170ae8$exports = {}; -$parcel$export($580f7ed6bc170ae8$exports, "VALID_HEAD_ELEMENTS", () => $580f7ed6bc170ae8$export$79e124b7caef7aa9); -$parcel$export($580f7ed6bc170ae8$exports, "PRELOAD_SELECTOR", () => $580f7ed6bc170ae8$export$5540ac2a18901364); -$parcel$export($580f7ed6bc170ae8$exports, "isValidElement", () => $580f7ed6bc170ae8$export$a8257692ac88316c); -$parcel$export($580f7ed6bc170ae8$exports, "hasValidationWarning", () => $580f7ed6bc170ae8$export$eeefd08c3a6f8db7); -$parcel$export($580f7ed6bc170ae8$exports, "getValidationWarnings", () => $580f7ed6bc170ae8$export$b01ab94d0cd042a0); -$parcel$export($580f7ed6bc170ae8$exports, "getCustomValidations", () => $580f7ed6bc170ae8$export$6c93e2175c028eeb); + $parcel$export( + $580f7ed6bc170ae8$exports, + "VALID_HEAD_ELEMENTS", + () => $580f7ed6bc170ae8$export$79e124b7caef7aa9, + ); + $parcel$export( + $580f7ed6bc170ae8$exports, + "PRELOAD_SELECTOR", + () => $580f7ed6bc170ae8$export$5540ac2a18901364, + ); + $parcel$export( + $580f7ed6bc170ae8$exports, + "isValidElement", + () => $580f7ed6bc170ae8$export$a8257692ac88316c, + ); + $parcel$export( + $580f7ed6bc170ae8$exports, + "hasValidationWarning", + () => $580f7ed6bc170ae8$export$eeefd08c3a6f8db7, + ); + $parcel$export( + $580f7ed6bc170ae8$exports, + "getValidationWarnings", + () => $580f7ed6bc170ae8$export$b01ab94d0cd042a0, + ); + $parcel$export( + $580f7ed6bc170ae8$exports, + "getCustomValidations", + () => $580f7ed6bc170ae8$export$6c93e2175c028eeb, + ); -const $580f7ed6bc170ae8$export$79e124b7caef7aa9 = new Set([ + const $580f7ed6bc170ae8$export$79e124b7caef7aa9 = new Set([ "base", "link", "meta", @@ -447,17 +654,27 @@ const $580f7ed6bc170ae8$export$79e124b7caef7aa9 = new Set([ "script", "style", "template", - "title" -]); -const $580f7ed6bc170ae8$export$5540ac2a18901364 = 'link:is([rel="preload" i], [rel="modulepreload" i])'; -function $580f7ed6bc170ae8$export$a8257692ac88316c(element) { - return $580f7ed6bc170ae8$export$79e124b7caef7aa9.has(element.tagName.toLowerCase()); -} -function $580f7ed6bc170ae8$export$eeefd08c3a6f8db7(element) { + "title", + ]); + const $580f7ed6bc170ae8$export$5540ac2a18901364 = + 'link:is([rel="preload" i], [rel="modulepreload" i])'; + function $580f7ed6bc170ae8$export$a8257692ac88316c(element) { + return $580f7ed6bc170ae8$export$79e124b7caef7aa9.has( + element.tagName.toLowerCase(), + ); + } + function $580f7ed6bc170ae8$export$eeefd08c3a6f8db7(element) { // Element itself is not valid. if (!$580f7ed6bc170ae8$export$a8257692ac88316c(element)) return true; // Children are not valid. - if (element.matches(`:has(:not(${Array.from($580f7ed6bc170ae8$export$79e124b7caef7aa9).join(", ")}))`)) return true; + if ( + element.matches( + `:has(:not(${Array.from($580f7ed6bc170ae8$export$79e124b7caef7aa9).join( + ", ", + )}))`, + ) + ) + return true; //