From 9c83872a4e7022cd58aedd1cf51bae25f48ee98b Mon Sep 17 00:00:00 2001 From: David Taylor Date: Mon, 30 Dec 2024 11:31:08 +0000 Subject: [PATCH] PERF: Refactor and optimize splash screen implementation (#30373) - Remove JS - Remove "Loading..." text. This has been been broken for a while due to some conflicting discourse-ai CSS. Also, animating the `content:` property like this requires the browser to repaint/reflow, which cannot be done while JS is executing. - Replace animated SVG with divs animated via CSS. When JS is executing, browsers pause animations of transform properties inside SVGs. This limitation does not exist on regular CSS animations. So with this change, the animation continues smoothly even you run an infinite loop in JS. To ensure the splash screen remains "contentful" for LCP purposes, an SVG background-image is used There is no change to the visual look of the animation --- app/assets/javascripts/discourse/app/app.js | 3 +- .../discourse/scripts/splash-screen.js | 66 ----- app/helpers/splash_screen_helper.rb | 23 -- app/views/common/_discourse_splash.html.erb | 254 +++++------------- 4 files changed, 73 insertions(+), 273 deletions(-) delete mode 100644 app/assets/javascripts/discourse/scripts/splash-screen.js delete mode 100644 app/helpers/splash_screen_helper.rb diff --git a/app/assets/javascripts/discourse/app/app.js b/app/assets/javascripts/discourse/app/app.js index 8691468e336..44ee3a702d4 100644 --- a/app/assets/javascripts/discourse/app/app.js +++ b/app/assets/javascripts/discourse/app/app.js @@ -56,8 +56,7 @@ class Discourse extends Application { ready() { performance.mark("discourse-ready"); - const event = new CustomEvent("discourse-ready"); - document.dispatchEvent(event); + document.querySelector("#d-splash")?.remove(); } } diff --git a/app/assets/javascripts/discourse/scripts/splash-screen.js b/app/assets/javascripts/discourse/scripts/splash-screen.js deleted file mode 100644 index a8a56af7eee..00000000000 --- a/app/assets/javascripts/discourse/scripts/splash-screen.js +++ /dev/null @@ -1,66 +0,0 @@ -// This script is inlined in `_discourse_splash.html.erb -const DELAY_TARGET = 2000; -const POLLING_INTERVAL = 50; - -const splashSvgTemplate = document.querySelector(".splash-svg-template"); -const splashTemplateClone = splashSvgTemplate.content.cloneNode(true); -const svgElement = splashTemplateClone.querySelector("svg"); - -const svgString = new XMLSerializer().serializeToString(svgElement); -const encodedSvg = btoa(svgString); - -const splashWrapper = document.querySelector("#d-splash"); -const splashImage = - splashWrapper && splashWrapper.querySelector(".preloader-image"); - -if (splashImage) { - splashImage.src = `data:image/svg+xml;base64,${encodedSvg}`; - - const connectStart = performance.timing.connectStart || 0; - const targetTime = connectStart + DELAY_TARGET; - - let splashInterval; - let discourseReady; - - const swapSplash = () => { - splashWrapper && - splashWrapper.style.setProperty("--animation-state", "running"); - svgElement && svgElement.style.setProperty("--animation-state", "running"); - - const newSvgString = new XMLSerializer().serializeToString(svgElement); - const newEncodedSvg = btoa(newSvgString); - - splashImage.src = `data:image/svg+xml;base64,${newEncodedSvg}`; - - performance.mark("discourse-splash-visible"); - - clearSplashInterval(); - }; - - const clearSplashInterval = () => { - clearInterval(splashInterval); - splashInterval = null; - }; - - (() => { - splashInterval = setInterval(() => { - if (discourseReady) { - clearSplashInterval(); - } - - if (Date.now() > targetTime) { - swapSplash(); - } - }, POLLING_INTERVAL); - })(); - - document.addEventListener( - "discourse-ready", - () => { - discourseReady = true; - splashWrapper && splashWrapper.remove(); - performance.mark("discourse-splash-removed"); - }, - { once: true } - ); -} diff --git a/app/helpers/splash_screen_helper.rb b/app/helpers/splash_screen_helper.rb deleted file mode 100644 index edbc598cc25..00000000000 --- a/app/helpers/splash_screen_helper.rb +++ /dev/null @@ -1,23 +0,0 @@ -# frozen_string_literal: true - -module SplashScreenHelper - def self.raw_js - if Rails.env.development? - load_js - else - @loaded_js ||= load_js - end.html_safe - end - - private - - def self.load_js - File.read("#{Rails.root}/app/assets/javascripts/discourse/dist/assets/splash-screen.js").sub( - "//# sourceMappingURL=splash-screen.map", - "", - ) - rescue Errno::ENOENT - Rails.logger.error("Unable to load splash screen JS") if Rails.env.production? - "console.log('Unable to load splash screen JS')" - end -end diff --git a/app/views/common/_discourse_splash.html.erb b/app/views/common/_discourse_splash.html.erb index e5e378ded98..45d23f53434 100644 --- a/app/views/common/_discourse_splash.html.erb +++ b/app/views/common/_discourse_splash.html.erb @@ -1,114 +1,4 @@ -<%- unless customization_disabled? %>
- - - <%=SiteSetting.title%> - -
-
<%= I18n.t("js.preloader_text") %>
+
+
+
+
+
+
+ - -
-<%- end %>