Optimizing Remix.js Performance: A Cache-Driven Approach
Addressing the performance concerns of my Remix.js website became a priority following an initial Web Vitals analysis, revealing a somewhat sluggish Largest Contentful Paint (LCP) at 5.68 seconds. The culprit was identified as a series of requests sent to my backend powered by Strapi.js. To swiftly tackle this issue, I delved into caching strategies, primarily focusing on HTTP caching.
Implementing HTTP caching involved adding headers to requests, such as:
"Cache-Control": "public, s-maxage=3600"
I configured my server to respond with caching directives like:
responseHeaders.set("Cache-Control", "public, max-age=3600");
Leveraging popular CDNs like Cloudflare or Cloudfront, these headers facilitated efficient page caching for up to a day. This resulted in faster page retrieval, akin to serving content from a proximate server, thereby significantly reducing load times for HTML and JS.
Extending this caching strategy to client-side fetch requests enhanced browser-level caching. For instance:
const headers = {
"Content-Type": "application/json",
Authorization: `Bearer ${token}`,
"Cache-Control": "public, max-age=3600"
};
This client-side cache control empowered the browser to intelligently manage caching, contributing to an expedited user experience.
However, recognizing that true performance optimization required more than just efficient caching, I explored memory caching. Employing the lru-cache library, I encapsulated my fetch requests within a caching mechanism. This memory cache, acting as a global variable in my Node.js app, stored responses for quick retrieval.
import { LRUCache } from "lru-cache";
const lruCacheOptions = {
max: 500,
ttl: 1000 * 60 * 60 * 24, // 1 day
};
const cache = new LRUCache(lruCacheOptions);
const fetchHandler = async (
url: string,
options?: any,
cacheEnabled = true,
clearCache = false
) => {
// ... (implementation details)
};
This integration resulted in a remarkable improvement in LCP, slashing it to a mere 0.66 seconds in Remix.js. With the cache-enabled flag set to true, subsequent requests were seamlessly served from the cache, ensuring a consistently swift user experience.
In conclusion, these strategic optimizations, encompassing advanced caching techniques and memory caching, not only expedited initial page loads but also fostered a sustained improvement in subsequent interactions. The combination of server-side and client-side caching, along with memory caching, lays a robust foundation for a high-performing Remix.js website.