The Switch: Moving Djolosports from Vue 3 SPA to Nuxt 3

Vue is my favorite Frontend Framework. It does not force you to scaffold your project in a specific way like Angular, and it provides superior performance with less boilerplate compared to React (I am ready to die on this hill—come at me, React die-hards).

As I had to make a choice for Djolosports, the decision was clear as day: the frontend would be in Vue.

For the V1 of Djolosports, our goals were simple:

It was a success. We covered 52 games accurately and generated substantial insights from granular data. However, there was a tiny, annoying problem: the media branch could not share articles professionally, and it was impossible to find Djolosports in Google search results.

The Limitation: Client-Side Rendering (CSR)

Vue is a client-side framework. When a user makes a request, several things happen:

  1. Bundle Loading: The browser loads the entire JavaScript bundle (logic, animations, API calls). This is injected into an HTML element with id="app". Then the defined main.js script runs and render the content.
Vue app code
The Vue app is loaded within that single index.html page
  1. Static Display: If content is purely static, it displays almost instantly.
  2. Dynamic Fetching: If data is needed, the browser only makes the network request after the Vue application is loaded.

Under a standard Vue app, dynamic content is never available at the exact moment the client accesses the page. This specificity is a Search Engine Optimization (SEO) killer.

The Routing Problem

Vue-router is a client-side system. The list of routes is only available after the JavaScript runs. When a search engine bot visits djolosports.com/en/sports/, the server sends the same empty index.html file as it does for the homepage. The “routing” only happens in the browser. Search bots see an empty page and won’t rank it.

Vue app code
All the routes are loaded within the Javascript code

The Solution: Switching to Nuxt

Enter Nuxt, the “big brother” of Vue. It is a powerful framework that comes with a special, invisible server called Nitro.

Nitro is designed to be “serverless-first.” It doesn’t need a dedicated Node.js or Python environment; it bundles Vue components into a tiny server that runs on minimal environments like Vercel, Netlify, or Cloudflare Workers.

How it works:

  1. On the Nitro Server: When a user (or a Google bot) requests a page, Nitro runs the Vue code on the server, fetches the data, and generates a static HTML string. This is sent to the user instantly.
  2. In the Browser (Hydration): Once the HTML arrives, the browser downloads a small Vue bundle that “wakes up” the static HTML, making it reactive. This is Hydration.

The page is never blank. Search engine bots receive a document full of keywords, titles, and metadata.

Comparing the Routing Systems

Nuxt uses a file-based routing system. You don’t write a configuration file; if you create pages/sports/football.vue, Nuxt automatically creates the route /sports/football.

Because it is an SSR framework, it maps these routes on the server. The bot receives a full document specific to “Football,” making it the standard for content-heavy platforms.

SEO: Vue (CSR) vs. Nuxt (SSR)

FeatureVue (CSR)Nuxt (SSR)
Meta Tag InjectionHappens in browser after loadInjected on server before delivery
Social SharingOften shows generic “Loading…”Shows rich previews (images/text)
URL DiscoveryBots must crawl JS to find linksBots see all links in raw HTML

Closing Thoughts

In a pure Vue app, you are building a Single Page Application (SPA). To the internet, the entire site looks like one single page changing its clothes.

Nuxt transforms that SPA into a Multi-Page Experience for the outside world while keeping the smooth, “no-reload” feeling for the user. Djolosports is now powered by Nuxt, a scalable decision that will allow our platform to reach higher grounds.