When I started learning Vue, I was pleasantly surprised by this framework. It turned out to be very simple and easy to learn. Its API had enough functionality for everyday tasks. All in all, I was delighted.

But one day, when I needed to configure a website for SEO, the internal tools of Vue were not enough. I had to dive into the depths of the Internet, where I found a framework that never ceases to amaze me.

Nuxt.js is a multifunctional, intuitive framework, or a very high-quality add-on to Vue. Its main task is to simplify a developer’s life by giving him or her all the tools needed to create websites of any complexity.

I suggest that today we take a brief look at its main features.

In this article, let’s talk about:

  1. Basic structure of files and folders
  2. nuxt.config.js settings file
  3. SEO settings
  4. Routes
  5. Plugins
  6. Storing
  7. SSG
  8. SSR

Separately, I will show you how to set up SSG, SSR in production and create your own API using nuxt server.

Image.

Files and folders

Nuxt has prepared a ready-made structure for us, where most of the files and folders are tied to a certain functionality.

On the one hand, it allows not worrying about where and how to store files; on the other hand, it may seem that nuxt limits us. But I will tell you from my experience: there have been no problems so far.

  • .nuxt is a folder. In real time, nuxt collects compiled, but not yet compressed files into it. When you run the npm run dev or npm run build commands, the files from this very folder will be used.
  • components — a folder for page components. Buttons, inputs, selectors, etc.
  • layouts — page wrappers. Sometimes, you may need a wrapper with a sidebar on the left, for example, for the admin panel, but at the same time, a sidebar is not needed for authorization pages. In this case, different layouts will help us — with and without a sidebar.
  • middlewares — a folder for functions that should be run before rendering the layout or pages. Through them you can, for example, check if the user has access to a certain page and if not, redirect him or her to a special page.
  • pages — a folder for pages. The files created in it are converted to routers. You do not need to configure anything. I wrote more about it below.
  • plugins — all the plugins that will be installed into the project must be in this folder. It is not obligatory, but it’s customary.
  • static — the folder where they usually store the favicon, various manifests, icons for metadata, etc. The files in this folder will be accessible via a direct link, e.g. localhost:3000/favicon.ico
  • store — a temporary storage that allows you to centralize data.
  • nuxt.config.js — the main settings file. That’s where we’ll start.

Main settings file

nuxt.config.js — this file is the entry point, where literally everything is configured. It is located in the root of the project. There, you add metadata, connect plugins, configure the server, configure webpack, connect env variables, etc.

For env variables to be available in this file, you have to install the dotenv library and import it at the beginning of the file, like this:

require('dotenv').config()

...

module.exports = {
  env: {
    API_URL: process.env.NODE_API_URL
  }
}

Next, you can add variables to the env block.

If you need any other library in this file, such as lodash, it is also installed and imported at the beginning of the file.

Settings for SEO

When developing a website in Vue, I encountered the problem that I could not set up metainformation separately for each page. I had to look for plugins and set up html file generation for each route; in short, I had to do some searching. That is how I got acquainted with nuxt.

It allows you to configure general metadata for all pages, as well as individual data for each page.

General metadata is configured in the nuxt.config.js file, in the head block. Here’s an example:

head: {
  htmlAttrs: {
    lang: 'en'
  },
  title: 'My site',
  meta: [
    { charset: 'utf-8' },
    { name: 'viewport', content: 'width=device-width, initial-scale=1' },
    { name: 'yandex-verification', content: 'xxx' },
    { name: 'facebook-domain-verification', content: 'xxx' }
  ],
  link: [
    { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
    { rel: 'sitemap', type: 'application/xml', href: 'https://localhost/sitemap.xml' }
  ],
  scripts: [
    { src: 'https://polyfill.io/v3/polyfill.min.js?features=IntersectionObserver' }
  ]
}

The settings for an individual page are specified in the page file, in the pages folder.

export default {
  name: 'Page',
  head() {
    bodyAttrs: {
      class: 'page-1'
    }
    meta: [
      { name: 'description', content: 'description' },
      { property: 'og:url', content: 'url' },
      { property: 'og:type', content: 'website' },
      { property: 'og:title', content: 'title' },
      { property: 'og:description', content: 'description' },
      { property: 'og:image', content: 'image' }
    ],
    link: [
      { ... }
    ],
    scripts: [
      { ... }
    ]
  }
}

You can read more about metadata settings on this page.

Creating Routes

As I wrote above, we create pages in the pages folder. This is simple. When you add a file called Blog.vue to this folder, nuxt will create a new route — localhost:3000/blog — which will be the link to the blog page.

If you need to create a page that will be responsible for an individual blog post, you can do it like this:

  1. Create a blog folder in the pages folder
  2. In the blog folder, add two files — index.vue and _id.vue
  3. The index.vue file will be responsible for the list of posts, and _id.vue for individual posts
  4. If everything is set up correctly, the post page will open at localhost:3000/blog/:id, where instead of :id you add the id of the required post.
Image.

Adding plugins

Since nuxt has several modes of operation, not all plugins can be plugged directly into components. This is due to the fact that components are pre-processed on the server, where there is no window object, document, or in general the browser API. Because of this, there will be errors.

To solve this problem, in the nuxt.config.js file, there is a special array — plugins, in which all plugins are connected.

Let’s connect some to give an example. In the plugins folder, create a file with the name of the package; I installed v-tooltip. In the file, add the following settings:

import Vue from 'vue'
import VTooltip from 'v-tooltip'

Vue.use(VTooltip)

Then go to nuxt.config.js and connect the new plugin.

plugins: [
  { src: '~/plugins/vtooltip.js', mode: 'client' }
]

Pay attention to the mode key: I specified it to tell nuxt that this plugin should run only on the client side, where there is a browser API. If you add the server value to the mode key, the plugin will run only on the server side. It won’t get to the client.

Image.

Store

Under the hood, Vuex is used.

The nuxt development team decided to make life easier for us by writing an additional add-on for vuex, which helps to write less code and therefore fewer bugs.

To add a module to the nuxt repository, it is enough to create a new file in the store folder, in which variables, actions, mutations, and getters should be specified. The name of this file will be the name of the module that will be called in the code to get the required data.

Below, I’ll show you an example of a module that requests a list of products via API:

// products.js

export const state = () => ({
  loaded: false,
  list: []
})

export const mutations = {
  SET_DATA(state, data) {
    state.list = data
  },
  SET_LOADED_STATUS(state, status) {
    state.loaded = status
  }
}

export const actions = {
  async getProducts({ commit }) {
    try {
      const products = API.GetProducts() // делаем запрос к api
      commit('SET_DATA', products)
      commit('SET_LOADED_STATUS', true)
    } catch (err) {
      if (err) throw err
    }
  }
}

export const getters = {
  products(state) {
    return state.list
  }
}

And somewhere in the code, we try to get this data:

// Home.vue

<template>
  <div>
    {{ productsList }}
  </div>
</template>

<script>
import { mapState, mapActions } from 'vuex'

export default {
  name: 'Home',
  computed: {
    ...mapState('products', {
      productsList: 'list',
    }),
  },
  created() {
    this.getProducts()
  },
  methods: {
    ...mapActions('categories', ['getProducts']),
  }
}
</script>

SSG

Static site generation — this method of project deployment is more suitable for websites that do not have dynamic pages.

The essence of SSG is simple — when a project is built for production, ready-to-use html files will be generated in the dist folder. With them, we will work further. Also, we will need to add our own server, which will run the project (I will tell below about this).

SSR

Server side rendering — will be the best solution for a project where pages are created in real time, i.e. through the admin panel, for example, pages of the blog.

In the case of SSR, a server built into nuxt will be running in production, which will ensure that new html files are generated in real time when new data is received, e.g. via API. You won’t have to restart or configure anything on the hosting side; nuxt takes care of it.

Well, here we get to the main topic of the article, where we will set up the project for two different types of work.

SSG Server Setup

We will need an Express server.

Let’s install and add settings for it.

npm i express

In the root of the project, create the file index.js — it will store all the server settings.

const express = require('express');
const app = express();
const path = require('path');

const port = process.env.PORT || 5000;

app.use(express.static('dist'));

app.get('*', (req, res) => {
  res.sendFile(path.resolve(__dirname, 'dist', 'index.html'));
});

app.listen(port, () =>
  console.log(`Server is running on: http://localhost:${port}`));

Next, in nuxt.config.js file, you need to specify static value for the target key. This will mean that nuxt will work in html file generation mode in dist folder. This is the folder we set our server to.

Also, in the settings file, you will have to list all the pages that are to be generated. Find the generate key and specify the required pages.

generate: {
  routes: ['/', '/about']
}

In this case, the main page and the About page will be generated.

Now, you need to run the command to generate

npm run generate

In the dist folder, css, js and html files will be created; that is all that is necessary. And all this will be compressed and optimized.

If you need to set up a project on hosting, I suggest you read one of my articles. It will help you get your project up and running quickly and without any problems, and it will be completely ready for production.

Image.

But that’s not all. I highly recommend that you check out the project where SSG was set up until recently. There, you will find everything you need in case you want to set up SSG in your project, too.

SSR Server Setup

Setting up SSR is actually easier than SSG because nuxt provides its own server. We don’t have to install express or configure anything; everything is ready and configured.

There are three steps you need to take to get it up and running:

  • In the nuxt.config.js file, change the value for the target key from static to server.
  • Run the command npm run build — it will optimize all files in the .nuxt folder, which will be monitored by the server
  • And run the server itself with the command npm start or nuxt start

With a successful start, the console will display the following message:

Nuxt @ v2.15.2

▸ Environment: production
▸ Rendering:   server-side
▸ Target:      server

Memory usage: 61.2 MB (RSS: 176 MB)

Listening: http://localhost:3000/

The message shows: nuxt indicated that it is running in the production mode, where everything is optimized and compressed.

Now, you don’t need to specify in generate which pages to generate. Nuxt will generate html in real time.

Creating an API on the nuxt server

By setting up SSR, you can create your own API, which gives even more possibilities.

For example, a website has a form that should mail data. In order not to describe all the logic on the frontend side and not to show the tokens, you can create a separate API point, write a simple smtp server for it, and easily send requests to it. In this case, we will not load frontend with additional code + all the tokens will be on the server side, which is much safer, and you won’t need to pay for a third-party API, which will do the same things but for a fee.

Let’s set it up.

First of all, create two folders. One general — server, where all server files will be located; the second — middlewares will be added to the folder server; it is needed for API points.

Create a file called logger.js in the middlewares folder and put some simple code in it.

export default function (req, res, next) {
  console.log('Hello world!')
  next()
}

When we access it, it will only display a message to the console.

Then, in nuxt.config.js file, add a new key serverMiddleware. In it, you need to specify the path to the API point and the address where it will be available.

serverMiddleware: [
  { path: '/api/log', handler:  '~/server/middlewares/logger.js' }
]

Now, if you query localhost:3000/api/log, you will see the message “Hello world!” in the console.

In this way, you can write any handlers that help simplify the logic on the frontend, making it easier, more accessible, and faster.

Image.

Conclusion

Everything I wrote above can be seen on a real example here. We are actively working on our website, where we try to apply the best of Nuxt. There, you can read more details about SSR.

I recommend reading the official Nuxt documentation; it has a lot of interesting stuff.

Thank you!

Link to the Vue Boilerplate.
How to configure Apollo GraphQL in Nuxt application.

How to Configure Apollo GraphQL in Nuxt Application

How to Configure Apollo GraphQL in...

How to Configure Apollo GraphQL in Nuxt Application

Good time of the day, friends!Today I want to show you how to set up Apollo GraphQl in a Nuxt application, where nuxt will take care of both client...

Strapi - Things to Keep in Mind Before Migrating to This CMS

Strapi: Things to Keep in Mind Before Migrating to...

Strapi: Things to Keep in Mind Before...

Strapi: Things to Keep in Mind Before Migrating to This CMS

When it comes to CMS, the modern market has already stepped so much that the choice is becoming increasingly difficult. There are so many options for...

Svelte vs React

Svelte vs. React: Which to Choose for Your Project?

Svelte vs. React: Which to Choose for...

Svelte vs. React: Which to Choose for Your Project?

JavaScript frameworks have revolutionized the landscape of web development and equipped developers with powerful tools and standardized methodologies...