Getting started

Nuxt.js - making web development simple and powerful

An overview of Nuxt and its static site generator - the technology I used to build this website.
Jonathan Machado avatar picture

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:

Img

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.

Img

Nuxt will then create the project for us:

Img

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:

Img

Img

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:

Img

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:

Img

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!

https://nuxtjs.org/


Stay in touch

Receive updates about new articles as well as curated and helpful content for web devs. No spam, unsubscribe at any time.