This post will walk you through the process of building server-rendered webpages in Vue — a progressive JavaScript framework that is simple to start using. I’ll also discuss Nuxt, a tool that makes the server-rendering process seamless. Finally, as a practical example, we will build an app that shows pictures of dogs based on their breed.
We are going to build a server rendered Vue app that loads very quickly, even before JavaScript is loaded, and is discoverable by search engines.
To better understand the problem, open an SPA built with any framework and try to inspect the page. Here is an example of one of my Vue demo projects:
Regardless of the project’s size, relevance, or beauty, this is what you end up with:
The content you see in your page source is the server response. Notice how it’s just the div#id
tag that’s shown and all other contents, including those pretty images, are nowhere to be found.
That’s a problem.
Actually, there are a lot of potential problems we could discuss.
Let’s focus on the most glaring — web crawling. Search engines and other web crawlers don’t know much about the visuals of your website after they are rendered. They just care about that ugly HTML sent as a response from your server. Here, when a crawler visits our website, it goes home with nothing but that div tag and some contents in the head tag.
How about a more subtle problem? Unsurprisingly, JavaScript frameworks (in our case, Vue) heavily depend on JavaScript. As a matter of fact, their views in single-page applications (SPAs) are generated and controlled with JavaScript. When things go wrong with JS loading, your user is stuck with a blank screen.
There is a Vue library that you can use in your Vue project to serve the contents on the server. This library is known as vue-server-renderer
and can be installed via npm. It also has good documentation.
Going this route is a little more difficult when compared to first getting started with Vue. Even though the documentation does its best to simplify things, SSR in general is a tricky concept.
The Webpack’s Prerender SPA plugin could be an option when vue-server-render
is hard to get started with. Unfortunately, it’s only reliable for simple SEO marketing pages ( “about” or “contact us”, for example). When you’re working with lots of routes/dynamic routes , the plugin bails on you.
Nuxt looks at all of these problems and gives you a platform to build SPA projects that are server-rendered and easy to setup. Drop in a command line instruction and you are good to go. It was inspired by React’s Next which is an alternative for React developers to implement server-side rendering (SSR).
Enough talk. Let’s walk the walk.
Earlier, I mentioned that all it takes is a command line instruction to get your Nuxt project going. Let’s see how true that is:
vue init nuxt/starter know-your-dogs
The command relies on the Vue CLI. If you don’t have it installed, run:
npm install -g vue-cli
This will generate a gigantic project folder structure. Don’t worry about it. With time, you will learn what folders you need and what to put where.
Run the generated boilerplate and you’ll see this:
Now navigate to ./layouts/default.vue
and update the template with the following:
<template> <div class="layout"> <h1>Know Your Dog!</h1> <nuxt/> </div> </template>
With some update to the
[styles]()
, you should see the view change to:
Notice how the “Know Your Dog!” text added to the layout was included in the page rendered at the root URL of the app. This is because the default.vue
file is a layout file. It wraps other pages and provides generic information that is shared among a group of pages. The <nuxt/>
tag in the default.vue
will be replaced with the page at run time.
Unlike your usual Vue project, you don’t have to configure routes in Nuxt. Any component found in the pages directory is automatically mapped to a route based on its name. The index.vue
page is mapped to the root URL /
but if we had a page called dogs.vue
, it will be mapped to /dogs
.
We will see more on routing when we starting fleshing out our app. For now, let’s fetch a list of dogs from the dog.ceo API.
In Vue, you would normally fetch async data from the created
lifecycle method. This is not the case in Nuxt because this data also needs to be rendered on the server. For that reason, another method called asyncData
exists which renders the data fetched on both the server and the client.
Install Axios — a popular library for making HTTP requests:
yarn add axios
In pages/index.vue
, add the following method in the component object:
import axios from 'axios' export default { async asyncData () { const { data } = await axios.get('https://dog.ceo/api/breeds/list') return { breeds: data.message } }, }
We are harnessing the power of async/await
feature. When a response is returned, we bind the value to the view by returning an object containing the response.
You can still stick to callbacks if that’s where you’re most comfortable:
export default { asyncData ({ params }, callback) { axios.get('https://dog.ceo/api/breeds/list') .then((res) => { callback(null, { breeds: res.data.message }) }) } }
You can now render the returned response data using the component’s template:
<template> <section class="container"> <div> <a v-for="breed in breeds" :key="breed" class="breed"> {{breed}} </a> </div> </section> </template>
Here is the new look:
Now view the page source and notice how the contents are also rendered to the server:
We need to implement what happens when any of the breeds is clicked. What we want to do is to navigate to dogs/:id
and show a random image of the breed that was selected.
Create a folder named dogs
in “pages” and add a file with the _breed.vue
in the folder.
In the script tag, fetch a random image of the dog from the API based on a parameter:
import axios from 'axios' export default { async asyncData ({params}) { const { data } = await axios.get(`https://dog.ceo/api/breed/${params.breed}/images/random`) return { breed: data.message, name: params.breed } } }
asyncData
receives an object where params
is a property. The params
property is also an object that contains all the parameters passed into a page (in our case breed
). The page was configured to receive parameter by prefixing its file name with an underscore (_). We use this parameter to fetch a random image and set the image and breed name to the view.
Let’s display this image and name:
<div> <img :src="breed" alt=""> <h4>{{name.toUpperCase()}}</h4> </div>
Now you can see a little detail of the breed you selected:
When you view the page source, you will still see your markup available on the server:
You might not always need Nuxt, but when you do, what you have learned in this article is enough for you to get started. But there’s always more to learn. For that, head to the Nuxt website to learn more features like plugins, store, etc). If there’s interest, we’ll cover more review more Nuxt in future posts.
Debugging Vue.js applications can be difficult, especially when there are dozens, if not hundreds of mutations during a user session. If you’re interested in monitoring and tracking Vue mutations for all of your users in production, try LogRocket.
LogRocket is like a DVR for web and mobile apps, recording literally everything that happens in your Vue apps, including network requests, JavaScript errors, performance problems, and much more. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred.
The LogRocket Vuex plugin logs Vuex mutations to the LogRocket console, giving you context around what led to an error and what state the application was in when an issue occurred.
Modernize how you debug your Vue apps — start monitoring for free.
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowThe useReducer React Hook is a good alternative to tools like Redux, Recoil, or MobX.
Node.js v22.5.0 introduced a native SQLite module, which is is similar to what other JavaScript runtimes like Deno and Bun already have.
Understanding and supporting pinch, text, and browser zoom significantly enhances the user experience. Let’s explore a few ways to do so.
Playwright is a popular framework for automating and testing web applications across multiple browsers in JavaScript, Python, Java, and C#. […]
One Reply to "Building server-rendered apps in Vue using Nuxt.js"
That Really Help to understand how to use API in Nuxtjs and Use Routes, Thanks for blog