17 May 2024

From Nuxt 2 to Nuxt 3: Enhancing Performance and Flexibility

It was overdue! With Nuxt 4 peeking around the corner, my personal website had been using Nuxt 2 and Node 14 for far too long. I didn't even have Nuxt Bridge layer. Publishing experience was super painful as I constantly had to update my dev environment before even running the site locally. The upgrade felt like a big chunk of work - thanks to huge number of modules and plugins I had accumulated over time in this project. Below, I’ll take you through how my old website was built before I undertook the revamp over the past few weeks.

Blog Landing Page

While I have kept the diagrams landing page same as before, I have separated blog posts written on this website from the blog posts published else where on Publications page. I have stripped down all the transitions and images from the blog landing page. Now, blog landing page feels as quiet as a PDF! It’s super minimalistic and refreshing.

Diagrams Landing Page

Diagrams landing page previously used three packages for it to function the way it did, such as, vue-infinite-loading and vue-masonry-css plugins for loading images on scroll in masonry grid, while it used vue-lazyload for lazy loading images to improve page performance. This time around, I went ahead and wrote my own implementation of infinite loading images on scroll and masonry calculations of image grid that changes when viewport re-sizes - making both vue-infinite-loading and vue-masonry-css redundant.

Since the diagrams landing page is image-heavy, it pays a high performance price. Previously, I was using vue-lazyload for lazy loading images. However, in my new blog, I have introduced @nuxt/image module for all the images on my blog - even for those not on the diagrams landing page.

@nuxt/image provides plenty of CDN providers out of the box, however, all of my images are served from AWS S3 bucket. So I wrote my custom provider.

 <NuxtImg :src="post.image.src"
          loading="lazy"
          provider="s3"
          :alt="post.image.alt" 
  />

Sitemap and RSS Feed

Previously, I used @nuxtjs/sitemap to add sitemap that is powered by contents stored using Nuxt Content module. In the new version of the site, Nuxt content module provided this sitemap example where we can code up our own sitemap using sitemap package. This method uses Nitro server route coupled with serverQueryContent that provides us access to all the documents within /content directory that we can loop through and write required data to the sitemap.

// server/routes/sitemap.xml.ts
import { serverQueryContent } from '#content/server'
import { SitemapStream, streamToPromise } from 'sitemap'

export default defineEventHandler(async (event) => {
  // Fetch all documents
  const docs = await serverQueryContent(event).find()
 // ...
  for (const doc of docs) {
    sitemap.write({
      url: doc._path,
      changefreq: 'monthly'
    })
  }
  sitemap.end()
  return streamToPromise(sitemap)
})

This gave me an idea to write my own RSS feed page as well since it shares pretty much the same contents. For this purpose, I used feed package, and created new Nitro server routes that would create feed.xml for my site.

// server/routes/feed.xml.ts
  import { Feed } from "feed";

// ...
  const feed = new Feed({ /* ... */})

  for (const doc of docs) {
    if (doc.Sitemap === true) {
      feed.addItem({
        title: doc.Name,
        id: `https://krutiepatel.com/${doc._path}`,
        link: `https://krutiepatel.com/${doc._path}`,
        description: doc.description
        // ...
      });
    }
  }
  // ...

Home page

Home page remains the same as before with major upgrade to the single card that sits in the center of the page with all the links of the website. Home page card design is inspired from my little cards UI project going on the Codepen. Footer still serves as a way to navigate the rest of the site when user is not on the home page.

New Home-page DesignNew Home-page Design

Plugins & Modules Roundup

Here's the final roundup of all the packages I used in my old website compared to the new one - trimming it down from 18 to just 7! I have reduced quite bit of packages this time, while introduced some new, essential ones for the first time. This streamlined approach not only makes my site cleaner and more efficient but also more tailored to my specific needs.

#Old WebsiteNew Website
#Old WebsiteNew Website
1@nuxt/content@nuxt/content
2nuxt-windicss@nuxtjs/tailwindcss
3@nuxtjs/google-gtagnuxt-gtag
4aosaos
5@nuxtjs/markdownitVue Components support in Content module
6vue-lazyload@nuxt/image Lazy Load
7@nuxtjs/feedCustom wrote it using Nitro server routes and feed
8@nuxtjs/sitemapCustom wrote it using Nitro server routes and sitemap
9dayjsReplaced with native Intl
10prism-themesContent module highlight
11vue-infinite-loadingCustom wrote it from scratch
12vue-masonry-cssCustom wrote it from scratch
13@iconify/vueReplaced with custom tiny Vue Components
14@nuxtjs/color-modeRelies on the operating system preference
15gsap-
16medium-zoom-
17vue-social-sharing-
18vue-tweet-embed-

This approach makes it much easier for me to upgrade my blog in the future without relying on external dependencies that much. By minimizing these dependencies, I aim to have more control over my site, making future upgrades much smoother and more manageable.

I hope you've enjoyed reading about my upgrade journey. Taking a little break from my book writing project to upgrade my website was a refreshing change. It gave me a fresh perspective and new insights that I can now bring back to my writing.