Andy Jarrett // Code. Develop. Create.

Adding localStorage to the Alpine.js RSS Reader

Developer debugging

The purpose of the blog post is to explain why I am adding localStorage to my simple app at github.com/andyj/alpine.js-rss-reader. If you haven't see it already, this is carrying on from my previous post

Why Use Local Storage?

Faster Development: Highlight that local storage helps reduce the need to constantly fetch data from the server, which speeds up the development process since the results are instantly available from the cache.

Reduced Server Load: Explain that using local storage reduces the number of requests made to the server, which can be particularly important if there are API rate limits or if the server is slow.

There isn't many changes, so its a quick walk through of the key parts of the code where we add local storage functionality:

1. Introducing Cache Keys

const cacheKey = 'rssFeedCache';
const cacheExpiryKey = 'rssFeedCacheExpiry';

These keys will store the fetched RSS feed and its expiry time in local storage.

2. Checking for Cached Data

const cachedData = localStorage.getItem(cacheKey);
const cacheExpiry = localStorage.getItem(cacheExpiryKey);
const now = new Date().getTime();

Before making a new request, the code checks if there’s valid cached data to use.

3. Using Cached Data if Valid

if (cachedData && cacheExpiry && now < cacheExpiry) {
  this.feedItems = JSON.parse(cachedData);
  this.loading = false;
  console.info("Results from cache");
}

If the cache is still valid, the feed is loaded from local storage, saving the need for a server request.

4. Fetching and Caching New Data

const response = await fetch(feedUrl);
const data = await response.json();
const parser = new DOMParser();
const xml = parser.parseFromString(data.contents, 'text/xml');
const items = xml.querySelectorAll('item');
this.feedItems = Array.from(items).map(item => ({
  link: item.querySelector('link').textContent,
  pubDate: item.querySelector('pubDate').textContent,
  description: item.querySelector('description').textContent
}));

localStorage.setItem(cacheKey, JSON.stringify(this.feedItems));
localStorage.setItem(cacheExpiryKey, now + 5 * 60 * 1000); // Cache expiry set to 5 minutes
console.info("New results stored in cache");

If there’s no valid cache, the code fetches new data, updates the feed items, and caches the results for future use.

Putting it all together

function rssFeed() {
return {
  feedItems: [],
  loading: true,
  error: null,

  async fetchFeed() {
    const feedUrl = `https://api.allorigins.win/get?url=${encodeURIComponent('https://bsky.app/profile/did:plc:bd3g6lum2orsqnolbu4urvxj/rss')}`;
    const cacheKey = 'rssFeedCache';
    const cacheExpiryKey = 'rssFeedCacheExpiry';

    // Check if cached data is available and valid
    const cachedData = localStorage.getItem(cacheKey);
    const cacheExpiry = localStorage.getItem(cacheExpiryKey);
    const now = new Date().getTime();

    if (cachedData && cacheExpiry && now < cacheExpiry) {
      // Use cached data
      this.feedItems = JSON.parse(cachedData);
      this.loading = false;
      console.info("Results from cache");
    } else {
      try {
        const response = await fetch(feedUrl);
        const data = await response.json();
        const parser = new DOMParser();
        const xml = parser.parseFromString(data.contents, 'text/xml');
        const items = xml.querySelectorAll('item');
        this.feedItems = Array.from(items).map(item => ({
          link: item.querySelector('link').textContent,
          pubDate: item.querySelector('pubDate').textContent,
          description: item.querySelector('description').textContent
        }));

        // Store the new data in local storage
        localStorage.setItem(cacheKey, JSON.stringify(this.feedItems));
        localStorage.setItem(cacheExpiryKey, now + 5 * 60 * 1000); // Set cache expiry to 5 minutes from now
        console.info("New results stored in cache");
      } catch (error) {
        this.error = 'Failed to load the feed. Please try again later.';
        console.error(error.message);
      } finally {
        this.loading = false;
      }
    }
  },

  formatDate(dateString) {
    const options = { year: 'numeric', month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric', timeZoneName: 'short' };
    const date = new Date(dateString);
    return date.toLocaleDateString(undefined, options);
  }
};
}
  • Clearing Cache: You can manually clear the cache using localStorage.removeItem('rssFeedCache') if the cached data becomes stale or corrupted.
  • Optimising Cache Duration: You may want to experiment with the cache duration (now + 5 * 60 * 1000) depending on how frequently the RSS feed updates.

I’m here, learning and working away. If you liked this content and want to keep me going, consider buying me a coffee. Your support keeps this site running and the coffee brewing! ☕️