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 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:+page.svelte#script
javascriptconst 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:
+page.svelte#onMount
javascriptonMount(() => { return page.subscribe((page) => { const pageParam = page.url.searchParams.get('page') || '1'; currentPage = Math.max(parseInt(pageParam), 1); // Utilize data.posts[currentPage] for rendering. }); });
Team Lead's Insight!
This is where my team lead @TorstenDittmann provided 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 new territory for me). After a few back-and-forth messages, I finally understood what he meant 🚀!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 source -
+page.ts#load
javascriptexport 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 anOOM
on tests!No worries, we can do a quick fix like this -
javascriptif (blogPosts.length === 0) { error(404, 'Not Found'); }
Insight 2
Well the above fixed the
OOM
, but now I had thisPage 0 and Page 14 Not Found Errors
.
So interestingly, if you define aURL
in the component, it's supposed to exist and I definitely did not know that.I had these in my pagination anchor tags -
+page.svelte#nav-anchor-tags
javascript<a data-sveltekit-noscroll class="flex navigation-button" href="/blog/{data.currentPage - 1}" 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}" class:navigation-button-active={!isFirstPage} > Next <span class="web-icon-chevron-right" style="font-size: 20px" /> </a>
This meant (for
Svelte
) that the pages0
&14
must exist. A simple hot-fix was to check if theURL
s were in range, useif/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 and let me know your thoughts!