Nuxt.js - making web development simple and powerful
By Jonathan Machado
February 22, 2020
Why Nuxt?
When using Nuxt over vanilla Vue.js you are letting the framework make several (great) decisions for you concerning modules, default configurations, file structure and more. These decisions are based on best practices and designed to improve the developer experience. Also, Nuxt is very famous for Server Side Rendering and the positive effect it has on SEO!
Nuxt is a framework designed to give you a strong architecture following official Vue guidelines. Incrementally adoptable, it can be used to create from static landing pages to complex enterprise ready web applications.
Versatile by nature, it supports different targets (server, serverless or static) and server side rendering is switchable - Nuxt.js docs
For example, I use Nuxt Static Site Generation on this website. A simple npm run generate
command generates a static version of my website ready to be published.
The benefits of static site generation include: faster loading time on the user browser, better SEO, hosting (usually free for static files) and simplicity to publish/deploy your application.
Let's walk through some of Nuxt main features:
Standard folder structure
Nuxt implements an improved folder structure based on best practices. The image below highlights the folders used by Nuxt:
You can find details of each one of the folders here: https://nuxtjs.org/guide/directory-structure.
Automatic routing configuration
You don't have to manually configure a new route in Vue Router for every new page you create like you do with Vue.
With Nuxt, all you have to do is to create a .vue
file in your pages
folder and Nuxt automatically creates the routing configuration for you!
└───pages
│ about.vue
│ index.vue
│
├───articles
│ index.vue
│ _slug.vue
│
└───users
_id.vue
You can also capture URL parameters by creating a file with an underscore _
prefix, like in the _slug.vue
and _id.vue
examples above.
Let's get our hands dirty!
So, let's get started with our Nuxt application.
We're going to use the nxp
command (which is installed by default since NPM 5.2.0):
$ npx create-nuxt-app <project-name>
It will ask us several questions about: the project name, author and:
-
if we want to use a CSS library or not;
I'm going to use TailwindCSS on this article, but you can choose any library you're familiar with
-
if we want to use a Custom Server Framework (e.g Express);
I will use Nuxt default server
-
if we want to add any Nuxt Module;
Modules are Nuxt.js extensions which can extend its core functionality and add endless integrations. - https://nuxtjs.org/guide/modules/
I will use Axios: Secure and Easy Axios integration with Nuxt.js to make HTTP requests
-
Linting tools
I'm going to use ESLint and Prettier
-
Test framework
None
-
Rendering Mode
Great article about each mode: https://recurse.me/posts/choosing-a-nuxt-mode.html
I'm picking the default mode: Universal. But you can change it at any time in your
nuxt.config.js
file.
Nuxt will then create the project for us:
There it is, our brand new Nuxt project ready for take off!
Let's cd
into our project directory and run our project:
$ cd hello-nuxt
$ npm run dev
Notice that Nuxt builds things for the client and also for the server:
Automatic routing in action
Nuxt.js automatically generates the vue-router configuration based on your file tree of Vue files inside the pages
directory.
So, let's add an about.vue
page and add a simple text to it:
// about.vue
<template>
<div>This is my about page.</div>
</template>
Now, if we navigate to http://localhost:3000/about
, we should see the page we have just created.
To create links to navigate between pages, Nuxt docs recommends to use the <nuxt-link>
component.
So let's create a link back to the home page:
// about.vue
<template>
<div>
<h1>This is my about page.</h1>
<nuxt-link to="/">Home page</nuxt-link>
</div>
</template>
So far so good :)
Pre-rendering in action
To see the pre-rendering in action, we're going to create a page that displays a lot of posts retrieved from an API. Then we will count on Nuxt to generate a static page with all the data in it.
We're going to get the posts from a JSON placeholder API that will generate placeholder data for us: https://jsonplaceholder.typicode.com/posts - it returns a JSON array with 100 posts.
Now, in Vue we have some methods like created
and beforeMount
that can be used to make an API request for data. What method should we use when working with Nuxt?
You may want to fetch data and render it on the server-side. Nuxt.js adds an asyncData
method to let you handle async operations before initializing the component - https://nuxtjs.org/guide/async-data
Alright! Nuxt will run the asyncData
on the server side to pre-render our pages with the data they need.
So, in our index.vue
page we're going to add the asyncData
method that will be called before initializing the component:
// index.vue
<script>
import axios from 'axios'
export default {
components: {},
async asyncData({ params }) {
// params: will give us access to the URL params.
// Get request using Axios (don't foget to import axios)
const { data } = await axios.get(
'https://jsonplaceholder.typicode.com/posts'
)
return { posts: data }
}
}
</script>
By returning { posts: data }
Nuxt will add a posts property to the component's data. Now, all we have to do is to loop through the posts and display its details. Let's get rid of all the default html part from our default page:
// pages/index.vue
<template>
<div v-for="post in posts" :key="post.id">
<h2>{{post.title}}</h2>
<p>{{post.body}}</p>
</div>
</template>
This is what the whole file looks like now:
PS: I've added some CSS classes to make it clearer. If you're using a different CSS framework other than Tailwind CSS, you might have to make some changes to the classes names.
// pages/index.vue
<template>
<div class="container flex-wrap max-w-xl">
<h1 class="text-2xl font-bold my-10">Posts</h1>
<div v-for="post in posts" :key="post.id" class="border mb-4 p-4 text-left">
<h2 class="text-lg font-semibold">{{post.title}}</h2>
<p class="text-base">{{post.body}}</p>
</div>
</div>
</template>
<script>
import axios from 'axios'
export default {
components: {},
async asyncData({ params }) {
// params: will give us access to the URL params.
// Get request using Axios (don't foget to import Axios)
const { data } = await axios.get(
'https://jsonplaceholder.typicode.com/posts'
)
return { posts: data }
}
}
</script>
<style>
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
</style>
Our application is fetching data from the API and it looks like this:
Ok, now that we have it working, let's finally test the pre-rendering.
We're going to run the generate
command:
$ npm run generate
That will generate our static files in the /dist folder:
There we have it!
If you want to double check if your index.html
is actually pre-rendered you could either open it on a text editor and confirm that all the posts are in there or even turn your wi-fi off and open the index.html
on your browser - all posts will be displayed, no API has been called. Awesome!
Now you could publish the static files to any static hosting you'd like (Firebase Hosting, Netlify and etc.). Actually, Nuxt webisite uses this very same command to generate their website. The only difference is that the command is ran automatically once the docs are updated:
We don't want to manually generate the application every time we update the docs repository, it triggers a hook to Netlify which:
- Clones the nuxtjs.org repository
- Installs the dependencies via npm install
- Runs npm run generate
- Serves the dist directory
We now have an automated Static Generated Web Application :)
That's the same strategy I use for this website: once content is changed, a trigger fires a build process on Netlify and the static files are generated again.
Since your pages are already pre-rendered, the browser loads them as fast as it can be on the user browser. Once it’s loaded, it’ll start running as a normal SPA. (Yes, and I got this wrong when I started learning Nuxt. I assumed every page the user would navigate to would be an static page fetched from the server. Nop. Your app will still run its API calls (if any) as the user navigates through your app).
There's been some discussion about a full static mode for the future: Full static generated mode · Issue #22 · nuxt/rfcs
This was a quick Getting Started to make you familiar with Nuxt.
I recommend you to check the Nuxt.js official documentation for more information about all the elements of this framework!