---
title: 'Appwrite Blog x Pagination'
excerpt: "My experience implementing pagination on Appwrite's blog page."
date: 2024-09-08
categories: appwrite, web
featureImage: '/images/appwrite-blog-pagination.webp'

prev:
  text: 'Chrome Shortcuts'
  link: '/blog/chrome-shortcuts'

next:
  text: 'JS: Async/Await'
  link: '/blog/js-async-await'
---

A few weeks after I started working at `Appwrite`, I was assigned a task that I was very happy
to take upon! Matter of fact, I was the
one who created this [feature request](https://github.com/appwrite/website/issues/1038) on the website repo because it
really affected the blog page's humongous load.

---

### Challenges & Learnings

- #### Initial Approach

  My first strategy was to segment the blog posts into batches of `12`, navigated through a query parameter (`?page=2`).
  Here's how I initially set up the logic:

  ::: details `+page.svelte#script`
   ```javascript
   const POSTS_PER_PAGE = 12;
   const pages = chunkArray(data.posts, POSTS_PER_PAGE);
   
   function chunkArray(array: Array<any>, chunkSize: number) {
       const chunks = [];
       for (let i = 0; i < array.length; i += chunkSize) {
           chunks.push(array.slice(i, i + chunkSize));
       }
       return chunks;
   }
   
   // using this for viewing.
   $: blogPosts = (index: number) => {
       return pages[index] ?? pages[0];
   };
   ```
  :::

- #### Updated Approach

  Next up, I realized this wasn't the best way and could be significantly improved on the server side. So I changed the
  logic to return the chunked pages and then handle its navigation on the client side. My base logic was still something
  like this:

  ::: details `+page.svelte#onMount`
   ```javascript
   onMount(() => {
       return page.subscribe((page) => {
           const pageParam = page.url.searchParams.get('page') || '1';
           currentPage = Math.max(parseInt(pageParam), 1);
           // Utilize data.posts[currentPage] for rendering.
       });
   });
   ```
  :::

- #### Lead's Insight!

  This is where my lead [@TorstenDittmann](https://github.com/TorstenDittmann) provided a crucial feedback -
  > **We should do server side pagination via URLs 👍🏻**
  >
  > **This will be more efficient.**

  Initially, I was a bit puzzled about how to further enhance the server-side logic? (In my defense, `Svelte` was a new
  territory for me). After a few back-and-forth messages, I finally understood what he meant :rocket:!

- #### The final improvements

  The concept of `pre-rendering` pages seemed like a much better solution, with faster navigation without reloading
  content! For instance, accessing `/blog`, `/blog/2`, `/blog/3`, etc. as pre-rendered HTML pages.

---

### Key Learnings from Svelte

- #### Insight 1

  So, I had this piece of logic in my implementation -

  ::: details `+page.ts#load`

  ```javascript
  export const load = async ({ params }) => {
      const currentPage = parseInt(params.page || '1', 10);
  
      if (params.page === '1') {
          redirect(302, '/blog');
      }
  
      const { posts, authors } = getAllBlogEntriesWithAuthors();
      const totalPages = Math.ceil(posts.length / BLOG_POSTS_PER_PAGE);
  
      const pageNavigationChunks = generatePageNavigation(currentPage, totalPages);
  
      const endIndex = currentPage * BLOG_POSTS_PER_PAGE;
      const startIndex = (currentPage - 1) * BLOG_POSTS_PER_PAGE;
      const blogPosts = posts.slice(startIndex, endIndex);
  
      return {
          authors,
          totalPages,
          currentPage,
          posts: blogPosts,
          navigation: pageNavigationChunks,
          featured: posts.find(post => post.featured)
      };
  };
  ```

  :::
  Notice anything? Hmm, neither did I at first. Identifying the issue proved challenging!

  ---

  **The issue: The build process went into an infinite loop in order to build the pages because we did not specify what
  to do if the page wasn't available.**

  This meant that if the end page was `13`, the build process kept on creating pages till infinity and that caused an
  `OOM` on tests!

  No worries, we can do a quick fix like this -

  ```javascript
  if (blogPosts.length === 0) {
      error(404, 'Not Found');
  }
  ```

- #### Insight 2

  Well the above fixed the `OOM`, but now I had this **`Page 0 and Page 14 Not Found Errors`**.\
  So interestingly, if you define a `URL` in the component, it's supposed to exist and I definitely did not know that.

  I had these in my pagination anchor tags -

  ::: details `+page.svelte#nav-anchor-tags`
  ```javascript
  <a 
    data-sveltekit-noscroll
    class="flex navigation-button"
    href="/blog/{data.currentPage - 1}" // [!code focus]
    class:navigation-button-active={!isFirstPage}
  >
    <span class="web-icon-chevron-left" style="font-size: 20px" />
    Previous
  </a>
  
  
  <a 
    data-sveltekit-noscroll
    class="flex navigation-button"
    href="/blog/{data.currentPage + 1}" // [!code focus]
    class:navigation-button-active={!isFirstPage}
  >
    Next
    <span class="web-icon-chevron-right" style="font-size: 20px" />
  </a>
  ``` 
  :::

  This meant (as per `Svelte`) that the pages `0` & `14` must exist. A simple hot-fix was to check if the `URL`s were in
  range, use `if/else` on anchor tags visibility!

---

The refinements not only improved site performance but also deepened my understanding of `Svelte`'s capabilities.

* PR for reference - https://github.com/appwrite/website/pull/1152
* Check out the live implementation at [Appwrite's Blog](https://appwrite.io/blog) and let me know your thoughts!