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:
- Cover the 2025 Football African Cup Of Nations (AFCON).
- Ingest our own match data reliably.
- Display that data in a uniform and structured way.
- Validate our ability to generate and display data without third-party dependencies.
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:
- 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 definedmain.jsscript runs and render the content.
- Static Display: If content is purely static, it displays almost instantly.
- 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.
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:
- 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.
- 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)
| Feature | Vue (CSR) | Nuxt (SSR) |
|---|---|---|
| Meta Tag Injection | Happens in browser after load | Injected on server before delivery |
| Social Sharing | Often shows generic “Loading…” | Shows rich previews (images/text) |
| URL Discovery | Bots must crawl JS to find links | Bots 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.