From db9e223c738345e08c19756593fbbbd677c9f285 Mon Sep 17 00:00:00 2001 From: Barry Pollard Date: Thu, 8 Feb 2024 14:02:28 +0000 Subject: [PATCH] Misc perf improvements (#3570) * Misc perf improvements * Add LoAF * Spacing * Remove debug --- src/static/css/almanac.css | 10 +++ src/static/js/almanac.js | 6 +- src/static/js/send-web-vitals.js | 96 +++++++++++++++++++++++----- src/static/js/webmentions.js | 2 +- src/templates/base/base.html | 21 +++++- src/templates/base/base_chapter.html | 2 +- src/templates/base/contributors.html | 4 +- 7 files changed, 116 insertions(+), 25 deletions(-) diff --git a/src/static/css/almanac.css b/src/static/css/almanac.css index 23277d74be4..be5f5c3b3e6 100644 --- a/src/static/css/almanac.css +++ b/src/static/css/almanac.css @@ -966,6 +966,16 @@ p.copyright a { display: none !important; } +.novisibility-until-js { + visibility: hidden; +} + +@media (scripting: none) { + .novisibility-until-js { + display: none; + } +} + .nav-dropdown-btn.js-enable, .nav-dropdown-btn.js-enable:hover { opacity: 0.5; diff --git a/src/static/js/almanac.js b/src/static/js/almanac.js index 6bc9f54cd15..9e47cf736a0 100644 --- a/src/static/js/almanac.js +++ b/src/static/js/almanac.js @@ -476,7 +476,7 @@ function setDiscussionCount() { return; } document.querySelectorAll('.num-comments').forEach(el => { - el.innerText = comments; + el.textContent = comments; }); if (comments === 1) { @@ -625,7 +625,7 @@ function toggleDescription(event) { description.hidden = !description.hidden; event_button.setAttribute('aria-expanded', event_button.getAttribute('aria-expanded') == 'true' ? 'false' : 'true'); - event_button.innerHTML = event_button.getAttribute('aria-expanded') == 'true' ? event_button.getAttribute('data-hide-text') : event_button.getAttribute('data-show-text'); + event_button.textContent = event_button.getAttribute('aria-expanded') == 'true' ? event_button.getAttribute('data-hide-text') : event_button.getAttribute('data-show-text'); } @@ -635,7 +635,7 @@ function addShowDescription() { for (var index = 0; index < all_desc_buttons.length; ++index) { var desc_button = all_desc_buttons[index]; desc_button.addEventListener('click', toggleDescription); - desc_button.hidden = false; + desc_button.classList.remove('novisibility-until-js'); var description = document.querySelector('#' + desc_button.getAttribute('aria-controls')); if (description) { description.classList.remove('visually-hidden'); diff --git a/src/static/js/send-web-vitals.js b/src/static/js/send-web-vitals.js index cd39a80254d..85708847e71 100644 --- a/src/static/js/send-web-vitals.js +++ b/src/static/js/send-web-vitals.js @@ -1,4 +1,68 @@ function sendWebVitals() { + function getLoafAttribution(attribution) { + if (!attribution) { + return {}; + } + + const entry = attribution.eventEntry; + + if (!entry) { + return {}; + } + + if (!PerformanceObserver.supportedEntryTypes.includes('long-animation-frame')) { + return {}; + } + + let loafAttribution = { + debug_loaf_script_total_duration: 0 + }; + + const longAnimationFrames = performance.getEntriesByType('long-animation-frame'); + longAnimationFrames.filter(loaf => { + // LoAFs that intersect with the event. + return entry.startTime < (loaf.startTime + loaf.duration) && loaf.startTime < (entry.startTime + entry.duration); + }).forEach(loaf => { + loaf.scripts.forEach(script => { + const totalDuration = script.startTime + script.duration - script.desiredExecutionStart; + if (totalDuration > loafAttribution.debug_loaf_script_total_duration) { + loafAttribution = { + // Stats for the LoAF entry itself. + debug_loaf_entry_start_time: loaf.startTime, + debug_loaf_entry_end_time: loaf.startTime + loaf.duration, + debug_loaf_entry_work_duration: loaf.renderStart ? loaf.renderStart - loaf.startTime : loaf.duration, + debug_loaf_entry_render_duration: loaf.renderStart ? loaf.startTime + loaf.duration - loaf.renderStart : 0, + debug_loaf_entry_total_forced_style_and_layout_duration: loaf.scripts.reduce((sum, script) => sum + script.forcedStyleAndLayoutDuration, 0), + debug_loaf_entry_pre_layout_duration: loaf.styleAndLayoutStart ? loaf.styleAndLayoutStart - loaf.renderStart : 0, + debug_loaf_entry_style_and_layout_duration: loaf.styleAndLayoutStart ? loaf.startTime + loaf.duration - loaf.styleAndLayoutStart : 0, + + // Stats for the longest script in the LoAF entry. + debug_loaf_script_total_duration: totalDuration, + debug_loaf_script_compile_duration: script.executionStart - script.startTime, + debug_loaf_script_exec_duration: script.startTime + script.duration - script.executionStart, + debug_loaf_script_invoker: script.invoker, + debug_loaf_script_type: script.invokerType, + debug_loaf_script_source_url: script.sourceURL, + debug_loaf_script_source_function_name: script.sourceFunctionName, + debug_loaf_script_source_char_position: script.sourceCharPosition, + + // LoAF metadata. + debug_loaf_meta_length: longAnimationFrames.length, + } + } + }); + }); + + if (!loafAttribution.debug_loaf_script_total_duration) { + return {}; + } + + // The LoAF script with the single longest total duration. + return Object.fromEntries(Object.entries(loafAttribution).map(([k, v]) => { + // Convert all floats to ints. + return [k, typeof v == 'number' ? Math.floor(v) : v]; + })); + } function sendWebVitalsGAEvents({name, delta, id, attribution, navigationType}) { @@ -22,11 +86,13 @@ function sendWebVitals() { break; case 'FID': case 'INP': + const loafAttribution = getLoafAttribution(attribution); overrides = { debug_event: attribution.eventType, debug_time: Math.round(attribution.eventTime), debug_load_state: attribution.loadState, debug_target: attribution.eventTarget || '(not set)', + ...loafAttribution }; if (!attribution.eventEntry) { break; @@ -79,22 +145,20 @@ function sendWebVitals() { prefersColorScheme = 'not supported'; } - gtag('event', name, Object.assign( - { - event_category: 'Web Vitals', - value: Math.round(name === 'CLS' ? delta * 1000 : delta), - event_label: id, - non_interaction: true, - - //GA4 - effective_type: effectiveType, - data_saver: dataSaver, - device_memory: deviceMemory, - prefers_reduced_motion: prefersReducedMotion, - prefers_color_scheme: prefersColorScheme, - navigation_type: navigationType, - }, overrides) - ); + const params = Object.assign({ + event_category: 'Web Vitals', + value: Math.round(name === 'CLS' ? delta * 1000 : delta), + event_label: id, + non_interaction: true, + effective_type: effectiveType, + data_saver: dataSaver, + device_memory: deviceMemory, + prefers_reduced_motion: prefersReducedMotion, + prefers_color_scheme: prefersColorScheme, + navigation_type: navigationType, + }, overrides); + + gtag('event', name, params); } diff --git a/src/static/js/webmentions.js b/src/static/js/webmentions.js index 369f6dab50b..b27b987bbeb 100644 --- a/src/static/js/webmentions.js +++ b/src/static/js/webmentions.js @@ -235,7 +235,7 @@ function renderWebmentions(webmentions) { // Show count of reactions (except if 0) if (webmentions.length > 0) { - document.querySelectorAll('.num-reactions').forEach(t => t.innerText = webmentions.length); + document.querySelectorAll('.num-reactions').forEach(t => t.textContent = webmentions.length); document.querySelectorAll('.reactions-label').forEach(t => setReactionsLabel(webmentions.length, t)); document.querySelector('.webmentions-cta').classList.remove('hidden'); } diff --git a/src/templates/base/base.html b/src/templates/base/base.html index c37790f341b..35d02efaddb 100644 --- a/src/templates/base/base.html +++ b/src/templates/base/base.html @@ -808,8 +808,8 @@ {% if not ebook %}{{ figure_dropdown(metadata, chapter_config, id, sheets_gid, sql_file, image) }}{% endif %} - -
{{ description|safe }}
+ + {%- elif content != "" %}
{{ content|safe }}
@@ -910,4 +910,21 @@ {% endif %} + + {% endblock %} diff --git a/src/templates/base/base_chapter.html b/src/templates/base/base_chapter.html index 18de6378d51..0d460d42164 100644 --- a/src/templates/base/base_chapter.html +++ b/src/templates/base/base_chapter.html @@ -181,7 +181,7 @@

// Set date format to page's language locale to avoid incorrect date translation. dateFormat = new Intl.DateTimeFormat("{{ lang }}", options) } - publishedDateElement.innerHTML = dateFormat.format(publishedDate); + publishedDateElement.textContent = dateFormat.format(publishedDate); } else { console.log("Could not format date"); diff --git a/src/templates/base/contributors.html b/src/templates/base/contributors.html index bda6ce364fa..3f2f09233ac 100644 --- a/src/templates/base/contributors.html +++ b/src/templates/base/contributors.html @@ -483,8 +483,8 @@

} var filteredCount = getFilteredContributorCount(); - counter.innerText = filteredCount; - if ( counter.innerText === totalContributors.innerText ) { + counter.textContent = filteredCount; + if ( counter.textContent === totalContributors.textContent ) { totalText.classList.add('hidden') if (totalTextNonFiltered) totalTextNonFiltered.classList.remove('hidden') } else {