Hello Wappler Community,
We recently optimized our Mobile Lighthouse Score from a shaky ~80 to a stable >85 points (Desktop is 99). Since many developers struggle with LCP (Largest Contentful Paint) and Render-Blocking resources, I wanted to share our technical approach using Wappler (NodeJS/EJS).
1. Strategy: Server-Side Rendering (SSR) & Backend Assembly
Instead of loading an empty shell and fetching content client-side via dmx-serverconnect (AJAX), we assemble the HTML completely in the backend.
-
Logic: Modules (Header, Content, Footer) are retrieved as prepared HTML strings from the database or generated server-side.
-
Benefit: The browser receives the finished source code immediately via EJS (
<%= content %>). Google and users see content instantly without waiting for JSON requests.
2. The "Fake Hero" Trick (LCP Gamechanger)
Despite SSR, the browser still waited for the initialization of dmxAppConnect.js and dmxSwiper.js before rendering the main slider (~2-3s Render Delay).
-
Solution: We inject a static "Fake" image server-side at the exact same position.
-
CSS Strategy:
/* Fake Hero (visible immediately, z-index 1) */
#fake-hero { display: block; position: absolute; z-index: 1; }
/* Real Swiper (hidden until fully loaded) */
#swiper2:not(.swiper-initialized) {
opacity: 0 !important;
visibility: hidden !important; /* Crucial so Lighthouse ignores it! */
}
/* Swapping (Real Swiper covers Fake Hero) */
#swiper2.swiper-initialized {
opacity: 1 !important;
visibility: visible !important;
z-index: 10;
}
- Result: The LCP element is visible in < 200ms.
3. Intelligent Resource Management
-
Preload: The first hero image is dynamically preloaded in the Head using
rel="preload"andfetchpriority="high"(matching the specificimagesrcset). -
JS Defer: We use
deferfor all Wappler scripts to avoid render blocking, but we prioritize the download ofdmxAppConnect.jsvia<link rel="preload" as="script">. -
Cleanup: Removed jQuery and Moment.js. Moved non-critical CSS (Datepicker, Validator, etc.) to the very end of the Body.
4. Stability & Accessibility (Score 99)
-
CLS (0.0): Containers have fixed
aspect-ratiovalues in CSS (and specific media queries) so the layout doesn't shift at all during loading. -
Validation: Eliminated nested links (
<a>inside<a>). Instead, we use Bootstrap's.stretched-linkclass on the image to make the whole card clickable. -
Aria: All image-based links receive server-side generated attributes like
aria-label="<%= title %> view"for screen readers.
Conclusion: The combination of server-side assembly and the Fake-Hero Pattern made the biggest difference. The page feels "instant" now.
Happy optimizing! ![]()
