How to create your first Nuxt.js app
Tags: vue, node, javascript, webdev
Published: 2020-11-24 07:18:00

*Learn how to create a Nuxt.js application. This is a complete, step-by-step tutorial.*

In this post we provide instructions on how to create an application with Nuxt.js and share links to additional sources reviewing some of the topics in more depth. This post begins a series of our articles. Here we will discuss basics of building an app:

* project creation and configuration,
* assets and statics: styles, fonts, images, posts,
* components,
* pages and layouts,
* deployment.

Next time we are going to cover such topics as:

* dark mode,
* multilingual applications,
* PWA and SEO, including `Sitemap` auto-generation and `robots.txt`,
* setting up Analytics (Google and Yandex) and bug tracker (`Sentry`),
* application optimization for passing tests `Lighthouse` /` PageSpeed`.

What topics are you interested in? Write comments below, please.

# Introduction #

Over the recent years, many different frameworks for building static websites by using pre-rendering have emerged. Today we are going to talk about one of them — Nuxt.js. This open source framework is built on top of another well known frontend framework, Vue.js, but we think it has a number of distinct advantages.

To back up our point of view we decided to build a real application from scratch using Nuxt.js. Look what we got! With our step-by-step instruction, you can repeat this experiment yourself. Please note that to fully understand the article, you will need basic knowledge of working with Vue.js. Good luck!

# Briefly about Nuxt.js #

`Nuxt` is a high-level framework based on `Vue`. With Nuxt.js you can develop out-of-the-box isomorphic web applications by abstracting away the details of the server and client code distribution. With this approach, we save time and can focus on the development.

The key advantages of `Nuxt`:
* `SPA, SSR` and pre-rendering are already configured; the only thing we need to do is to choose. 

In this application we use a pre-rendering for the product-mode. It means that we generate all the pages of a web site in advance and then deploy to hosting for transmitting static data.
* Great `SEO` for all search engines as the result of using `SSR` or pre-renderer.
* Quick interaction with the site compared to static websites. It is achieved by loading only the necessary `js chunks`, `css styles` and `API` requests (most of the process is automated by `webpack 4` working under the hood of `Nuxt`).
* Excellent `Google Lighthouse` / `Page Speed` performance. With the right configuration, you can get 100/100 even on a weak server.
* `CSS Modules`, `Babel`, `Postscc` and other nice tools are pre-configured using [create-nuxt-app](https://github.com/nuxt/create-nuxt-app).
* Default project structure allows for convenient work in medium-sized and large teams.
* Over 50 ready-to-use modules and the ability to use any packages from the extensive Vue.js ecosystem.

I could go on and on about `Nuxt` advantages. This is the framework that I really love for its ease of use and the ability to create flexible and easily scalable applications. So, let’s start and see all the advantages in practice.

Find more information about Nuxt.js on the [official website](https://ru.nuxtjs.org/). Detailed guides are also available [here](https://ru.nuxtjs.org/docs/2.x/get-started/installation).

# Design #

Well-arranged, ready-made design or, even better, a UI-kit, will make any application development much faster and easier. If you don’t have an available UI-designer at hand, that’s fine. Within the framework of our instruction, we will manage ourselves!

Specifically for this article, I prepared a modern, minimalist blog design with simple functionality, enough to demonstrate `Nuxt` performance capabilities.
For development, I used an online tool,  `Figma`.  The design and UI kit are available via [this link](https://www.figma.com/file/s1B9t0XOmRhtNY8daezIs7/Nuxt.js-blog). You can copy this template and use it in your project.

# Creating a project #

To create a project, we will use the [create-nuxt-app](https://github.com/nuxt/create-nuxt-app) utility from `Nuxt` developers, which allows configuring the application template with `cli`.

Initialize a project and state its name:
```bash
npx create-nuxt-app nuxt-blog
```
Further, the utility will offer to choose a set of preferred libraries and packages over a few steps, after that it will independently download, adjust and configure them for the project.
You can see a complete list of the selected options on [Github](https://github.com/mikhail-shpakov/nuxt-blog#selected-options-nuxt-create-app).

> For this project the configuration with `Typescript` will be used. When developing in `Vue` with `Typescript`, you can use two `APIs`: [Options API](https://typescript.nuxtjs.org/cookbook/components/#options-api) or [Class API](https://typescript.nuxtjs.org/cookbook/components/#class-api). They have the same functionality, but different syntax. Personally, I prefer `Options API` syntax, that’s why it will be used in our project.

After creating the project, we can run our application using the command: `npm run dev`. It will now be available on `localhost: 3000`.

`Nuxt` uses a [webpack-dev-server](https://github.com/webpack/webpack-dev-server) with installed and configured [HMR](https://webpack.js.org/concepts/hot-module-replacement/) as a local server, which makes development fast and convenient.

> Since we are creating a demo version of an application, I will not write tests for it.  But I highly recommend not to neglect application testing in commercial development.
If you are new to this topic, I advise you to look at [Jest](https://github.com/facebook/jest) —  a very simple but powerful tool that supports working with Nuxt in combination with [vue-test-utils](https://vue-test-utils.vuejs.org/ru/).

# The project structure #
Nuxt creates a default directory and file structure suitable for a quick development start.
```
-- Assets
-- Static
-- Pages
-- Middleware
-- Components
-- Layouts
-- Plugins
-- Store
-- nuxt.config.js
-- ...other files
```
This structure is perfectly suitable for our project, so we will not change it.
You can read more about the purpose of different directories on the [Nuxt website](https://nuxtjs.org/docs/2.x/get-started/directory-structure).

# Building an application #

Before writing the code, let’s do the following:

1) Delete the starter components and pages created by `Nuxt`.
2) Install `pug` and `scss` to make development more convenient 
  and faster. Run the command:

```bash
npm i --save-dev pug pug-plain-loader node-sass sass-loader fibers
```

After that, the `lang` attribute will become available for the `template` and `style` tags.

```javascript
<template lang="pug"></template>

<style lang="scss"></style>
```

3) Add support for deep selector `::v-deep` to the `stylelint` configuration, which will allow you to apply styles to child components, ignoring `scoped`. You can read more about this selector [here](https://vue-loader.vuejs.org/guide/scoped-css.html#deep-selectors).

```javascript
{
  rules: {  
    'at-rule-no-unknown': null,  
    'selector-pseudo-element-no-unknown': [  
      true,  
      {  
        ignorePseudoElements: ['v-deep'],  
       },  
     ],  
   },
  }
  ```

All preparations are over, let’s go to the next step.

### Posts ###

Posts will be stored in the `content/posts`, directory, that we will create at the root of the project as a set of `markdown` files.

Let's create 5 small files, so that we can start working with them right away. To make it simple, name them `1.md`, `2.md`, etc.

In the `content` directory, create a `Posts.d.ts` file, where we define the types for the object containing all the necessary information about the post:
```typescript
export type Post = { 
  id: number 
  title: string
  desc: string
  file: string
  img: string 
}
```
I think the meanings of the fields should be clear from their names.

Moving on. In the same directory, create another file called `posts.ts` with the following content:

```typescript
import { Post } from './Post'  

export default [  
  {
    id: 1,  
    title: 'Post 1',  
    desc:  
      'A short description of the post to keep the user interested.' +  
      ' Description can be of different lengths, blocks are aligned' +  
      ' to the height of the block with the longest description',  
    file: 'content/posts/1.md',
    img: 'assets/images/1.svg',
  },  

  ...

  {  
    id: 5,  
    title: 'Post 5',  
    desc:  
      'A short description of the post to keep the user interested.' +  
      ' Description can be of different lengths, blocks are aligned' +  
      ' to the height of the block with the longest description',  
    file: 'content/posts/5.md',
    img: 'assets/images/5.svg',
  },  
] as Post[]
```

In the `img` property, we refer to images in the `assets/images` directory, but we haven't created this directory yet, so let's do it now.

Now, let's add images in `.svg` format to the created directory with the names that we specified above.

I will take 5 images from [unDraw](https://undraw.co/illustrations). This great resource is constantly updated and contains many free `svg` images.

Now that everything is ready, the `content` directory should look like this:
```
content/
-- posts.ts
-- Posts.d.ts
-- posts/
---- 1.md
---- 2.md
---- 3.md
---- 4.md
---- 5.md
```
And in the `assets` directory, the `images` subdirectory should have appeared with the following content:
```
assets/
-- images/
---- 1.svg
---- 2.svg
---- 3.svg
---- 4.svg
---- 5.svg
...
``` 

#### Dynamic file generation ####

Since we will get images and files with post texts dynamically, it’s necessary to implement a global mixin, which we can use further in all components.

To do this, create a `mixins` subdirectory in the `plugins` directory, and in the subdirectory create a `getDynamicFile.ts` file with the following content:

```typescript
import Vue from 'vue'  
  
export const methods = {  
  getDynamicFile(name: string) {  
    return require(`@/${name}`)
 },  
}  
  
Vue.mixin({  
  methods,  
})
```

All we need to do now is enable this mixin in the `nuxt.config.js` file:

```javascript
{
  plugins: [  
    '~plugins/mixins/getDynamicFile.ts',  
  ],
}
```

### Fonts ###

After creating posts let’s enable fonts. The easiest way is to use the wonderful [Webfontloader](https://github.com/Developmint/nuxt-webfontloader) library, which allows you to get any font from [Google Fonts](https://fonts.google.com/). However, in commercial development proprietary fonts are used more often, so let's look at such a case here.

As the font for our application I chose `Rubik`, which is distributed under the [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL). It can also be downloaded from [Google Fonts](https://fonts.google.com/specimen/Rubik).

Please note that in the downloaded archive the fonts will be in the `otf` format, but since we are working with the `web`, the `woff` and `woff2` formats will be our best choice.They have smaller size than other formats, but they are fully [supported](https://caniuse.com/woff) in all modern browsers. To convert `otf` to the necessary formats, you can use one of the many free online services.

So, we have the fonts in the needed formats, now it's time to add them to the project. To do this, create a `fonts` subdirectory in the `static` directory and add the fonts there. Create a `fonts.css` file in the same directory; it will be responsible for adding our fonts in the application with the following content:

```css
@font-face {  
  font-family: "Rubik-Regular";  
  font-weight: normal;  
  font-style: normal;  
  font-display: swap;  
  src:  
	  local("Rubik"),  
	  local("Rubik-Regular"),  
	  local("Rubik Regular"),  
	  url("/fonts/Rubik-Regular.woff2") format("woff2"),  
	  url("/fonts/Rubik-Regular.woff") format("woff");  
}  
  
...
```

You can see the full contents of the file in the [repository](https://github.com/mikhail-shpakov/nuxt-blog/blob/master/static/fonts/fonts.css).

You should pay attention to two things:

1) We specify `font-display: swap;`, defining how the font added via `font-face` will be displayed depending on whether it has loaded and is ready to use.

In this case, we do not set a block period and set an infinite swap period. Which means that the font is loaded as a background process without blocking the page loading, and the font will be displayed when ready.

2) In `src`, we set the load order by priority.

First, we check if the needed font is installed on the user's device by checking possible variations of the font name. If you don't find it, check if the browser supports the more modern `woff2` format, and if not, then use the `woff` format. There is a chance that the user has an outdated browser (for example, `IE` <9), in this case, we will further specify the fonts built into the browser as a `fallback`.

After creating the file with font loading rules, you need to add it in the application — in the `nuxt.config.js` file in the `head` section:

```javascript
{
  head: {  
    link: [  
      {  
        as: 'style',  
        rel: 'stylesheet preload prefetch',  
        href: '/fonts/fonts.css',  
      },  
    ],  
  },
}
```

Note that here, as earlier, we are using the `preload` and `prefetch` properties, thereby setting high priority in the browser for loading these files without blocking the page rendering.
Let's add `favicon` to the `static` directory of our application right away, which can be generated using any free online service.

Now the `static` directory looks like this:
```
static/
-- fonts/
---- fonts.css
---- Rubik-Bold.woff2
---- Rubik-Bold.woff
---- Rubik-Medium.woff2
---- Rubik-Medium.woff
---- Rubik-Regular.woff2
---- Rubik-Regular.woff
-- favicon.ico
```
Moving on to the next step.

### Reused styles ###

In our project, all the used styles are described with a single set of rules, which makes development much easier, so let's transfer these styles from `Figma` to the project files.

In the `assets` directory, create a `styles` subdirectory, where we will store all styles reused in the project. And the `styles` directory will contain the `variables.scss` file with all our `scss` variables.

You can see the contents of the file in the [repository](https://github.com/mikhail-shpakov/nuxt-blog/blob/master/assets/styles/variables.scss).

Now we need to connect these variables to the project so that they are available in any of our components. In Nuxt the [@nuxtjs/style-resources](https://github.com/nuxt-community/style-resources-module) module is used for this purpose.

Let’s install this module:

```bash
npm i @nuxtjs/style-resources
``` 

And add the following lines to `nuxt.config.js`:

```javascript
{
  modules: [
    '@nuxtjs/style-resources',
  ],

  styleResources: {  
    scss: ['./assets/styles/variables.scss'],  
  },
}
```

Well done!  Variables from this file will be available in any component.

The next step is to create a few helper classes and global styles that will be used throughout the application. This approach will allow you to centrally manage common styles and quickly adapt the application if the layout design is changed.

Create a `global` subdirectory in the `assets/styles` directory with the following files:

1) `typography.scss` file will contain all the helper classes to control text, including links.
Note that these helper classes change styles depending on the user's device resolution: smartphone or PC.

2) `transitions.scss` file will contain global animation styles, both for transitions between pages, and for animations inside components, if needed in the future.

3) `other.scss` file will contain global styles, which can not yet be separated into a specific group.

The `page` class will be used as a common container for all components on the page and will form the correct padding on the page.

The `.section` class will be used to denote the logical unit boundaries, and the `.content` class will be used to restrict the content width and its centering on the page. We will see how these classes are used further when we start implementing components and pages.

4) `index.scss` is a common file that will be used as a single export point for all global styles.

You can see the full contents of the file on [Github](https://github.com/mikhail-shpakov/nuxt-blog/tree/master/assets/styles/global).

At this step, we connect these global styles to make them available throughout the application. For this task `Nuxt` has a `css` section in the `nuxt.config.js` file:
 
```javascript
{
  css: ['~assets/styles/global'],
}
```

> I should say that in the future, `css` classes will be assigned according to the following logic:

> 1) If a tag has both helper classes and local classes, then the local classes will be added directly to the tag, for example, `p.some-local-class`, and the helper classes will be specified in the `class` property, for example, `class = "body3 medium "`.

> 2) If a tag has either helper classes or local classes, they will be added directly to the tag.

> I use this approach for my convenience, it helps to visually distinguish between global and local classes right away.

Before the development, let's install and enable `reset.css` so that our layout looks the same in all browsers.  To do this, we install the required package:

```bash
npm i reset-css
```

And enable it in the `nuxt.config.js` file in the already familiar `css` section, that will now look like this:
 
```javascript
{
  css: [
    '~assets/styles/global',
    'reset-css/reset.css',
  ],
}
```

Got it? If you did, we are ready to move on to the next step.

### Layouts ###

In `Nuxt`, Layouts are wrapper files for our app that allow you to reuse common components between them and implement the necessary common logic. Since our application is pretty simple, it will be enough for us to use the default `layout` - `default.vue`.

Also, in `Nuxt` a separate `layout` is used for an error page like `404`, which is actually a simple page.

`Layouts` in the [repository](https://github.com/mikhail-shpakov/nuxt-blog/tree/master/layouts).

**default.vue**

Our `default.vue` will have no logic and will look like this:

```html
<template lang="pug">  
div  
  nuxt
  db-footer
</template>
```
  
Here we use 2 components:
1) `nuxt` during the building process it will be replaced with a specific page requested by the user.
2) `db-footer` is our own Footer component (we will write it a little later), that will be automatically added to every page of our application.

**error.vue**

By default, when any error returns from the server in the `http` status, `Nuxt` redirects to `layout/error.vue` and passes an object containing the description of the received error via a prop named `error`.
Let's look at the `script` section, which will help to unify the work with the received errors:
 
```typescript
<script lang="ts">  
import Vue from 'vue'  
  
type Error = {  
  statusCode: number  
  message: string  
}  
  
type ErrorText = {  
  title: string  
  subtitle: string  
}  
  
type ErrorTexts = {  
  [key: number]: ErrorText  
  default: ErrorText  
}  

export default Vue.extend({  
  name: 'ErrorPage',  
  
  props: {  
    error: {  
      type: Object as () => Error,  
      required: true,  
    },  
  },  
  
  data: () => ({  
    texts: {  
      404: {  
        title: '404. Page not found',  
        subtitle: 'Something went wrong, no such address exists',  
      },  
      default: {  
        title: 'Unknown error',  
        subtitle: 'Something went wrong, but we`ll try to figure out what`s wrong',  
      },  
    } as ErrorTexts,  
  }),  

  computed: {  
    errorText(): ErrorText {  
      const { statusCode } = this.error  
      return this.texts[statusCode] || this.texts.default  
    },  
  },  
})  
</script>
```

What is going on here:

1) First, we define the types that will be used in this file.

2) In the `data` object, we create a dictionary that will contain all unique error messages for some specific, considerable errors we choose and a default message for all other errors.
 
3) In the computed `errorText` property we check if the received error is in the dictionary. If the error is there, then we return its message. If it’s not, we return the default message.

In this case our template will look like this:

```html
<template lang="pug">  
section.section  
  .content  
    .ep__container  
      section-header(  
        :title="errorText.title"  
        :subtitle="errorText.subtitle"  
      )  

      nuxt-link.ep__link(  
        class="primary"  
        to="/"  
      ) Home page  
</template>
```

Note that here we are using the `.section` and `.content` global utility classes that we have created earlier in the `assets/styles/global/other.scss` file. They allow to center the content on the page.

Here the `section-header` component is used; it has not yet been created, but later it will be a universal component for displaying headers. We will implement it when we start discussing components.

The `layouts` directory look like this:
```
layouts/
-- default.vue
-- error.vue
```
Let’s move on to creating components.

### Components ###

Components are the building blocks of our application. Let’s start with the components that we have already mentioned above.

I will not describe the components’ styles not to make this article too long. You can find them in the application [repository](https://github.com/mikhail-shpakov/nuxt-blog/tree/master/components).

**SectionHeader**

The headers in our application have the same style, so it makes total sense to use one component to display them and change the displayed data through the props.

Let’s look at the `script` section of this component.
 
```typescript
<script lang="ts">  
import Vue from 'vue'  

export default Vue.extend({  
  name: 'SectionHeader',  

  props: {  
    title: {  
      type: String,  
      required: true,  
    },  
    subtitle: {  
      type: String,  
      default: '',  
    },  
  },  
})  
</script>
```

Now let’s see what the template will look like:
 
```html
<template lang="pug">  
section.section  
  .content  
    h1.sh__title(  
      class="h1"  
    ) {{ title }}  

    p.sh__subtitle(  
      v-if="subtitle"  
      class="body2 regular"  
    ) {{ subtitle }}  
</template>
```

As we can see, this component is a simple wrapper for the displayed data and does not have any logic.

**LinkToHome**

The simplest component in our application is the link above the title that leads to the home page from the selected post page.

This component is really tiny, so I will write all its code here (without styles):
 
```html
<template lang="pug">  
section.section  
  .content  
    nuxt-link.lth__link(  
      to="/"  
      class="primary"  
    )  
      img.lth__link-icon(  
        src="~/assets/icons/home.svg"  
        alt="icon-home"  
      )  
      | Home  
</template>  
  
<script lang="ts">  
import Vue from 'vue'  

export default Vue.extend({  
  name: 'LinkToHome',  
})  
</script>  
```

Note that we request the `home.svg` icon from the `assets/icons` directory. You need to create this directory first and add there the necessary icon.

**DbFooter**

DbFooter component is very simple. It contains `copyright` and a link to generate a letter.

The requirements are clear, so let’s start the implementation from the `script` section.

```typescript
<script lang="ts">  
import Vue from 'vue'  

export default Vue.extend({  
  name: 'DbFooter',  

  computed: {  
    copyright(): string {
      const year = new Date().getUTCFullYear()
      return `© ${year} · All rights reserved`
    },  
  },  
})  
</script>
```
 
In DbFooter there is only one computed property that returns the current year, concatenated with a given string Now let’s look at the template:
 
```html
<template lang="pug">  
section.section  
  .content  
    .footer  
      a.secondary(
        href="mailto:example@mail.com?subject=Nuxt blog"
      ) Contact us  
      p.footer__copyright(
        class="body3 regular"
      ) {{ copyright }}  
</template>
```

When clicking on the `Contact us` link, we will open the native mail client and immediately set the message subject. This solution is suitable for our application demo, but in real life, a more appropriate solution would be to implement a feedback form to send messages directly from the site.

**PostCard**

Postcard is a pretty simple component without any complexities. 

```typescript
<script lang="ts">  
import Vue from 'vue'  
import { Post } from '~/content/Post'  

export default Vue.extend({  
  name: 'PostCard',  

  props: {  
    post: {  
      type: Object as () => Post,  
      required: true,  
    },  
  },  

  computed: {  
    pageUrl(): string {  
      return `/post/${this.post.id}`  
    },  
  },  
})  
</script>
```

In the `script` section, we define one `post` prop, which will contain all the necessary information about the post.

We also implement the `pageUrl` computed property for use in the template, which will return us a link to the desired post page.

The template will look like this:

```html
<template lang="pug">  
nuxt-link.pc(:to="pageUrl")  
  img.pc__img(  
    :src="getDynamicFile(post.img)"  
    :alt="`post-image-${post.id}`"  
  )  

  p.pc__title(class="body1 medium") {{ post.title }}  
  p.pc__subtitle(class="body3 regular") {{ post.desc }}  
</template>
```

Note that the root element of the template is `nuxt-link`. This is done to enable the user to open the post in a new window using the mouse.

This is the first time that the `getDynamicFile` global  mixin we created earlier in this article is used.

**PostList**

The main component on the home page consists of a post counter at the top and a list of posts.

The `script` section for this component:

```typescript
<script lang="ts">  
import Vue from 'vue'  
import posts from '~/content/posts'  

export default Vue.extend({  
  name: 'PostList',  
  
  data: () => ({  
    posts,  
  }),  
})  
</script>
```

Note that after importing the array of posts, we add them to the `data` object so that the template has access to this data in the future.

The template looks like this:

```html
<template lang="pug">  
section.section  
  .content  
    p.pl__count(class="body2 regular")  
      img.pl__count-icon(  
        src="~/assets/icons/list.svg"  
        alt="icon-list"  
      )  
      | Total {{ posts.length }} posts  

    .pl__items  
      post-card(  
        v-for="post in posts"  
        :key="post.id"  
        :post="post"  
      )  
</template>
```

Don't forget to add the `list.svg` icon to the `assets/icons` directory for everything to work as expected.

**PostFull**

`PostFull` is the main component on a separate post page that displays the post content.

For this component, we need the [@nuxtjs/markdownit](https://github.com/nuxt-community/modules/tree/master/packages/markdownit) module, which is responsible for converting md to html.

Let's install it: 
```bash
npm i @nuxtjs/markdownit
```

Then let’s add `@nuxtjs/markdownit` to the `modules` section of the `nuxt.config.js` file:

```javascript
{
  modules:  [
    '@nuxtjs/markdownit',
  ],
}
```

Excellent! Let's start implementing the component. As usual, from the `script` section:

```typescript
<script lang="ts">  
import Vue from 'vue'  
import { Post } from '~/content/Post'  
  
export default Vue.extend({  
  name: 'PostFull',  
  
  props: {  
    post: {  
      type: Object as () => Post,  
      required: true,  
    },  
  },  
})  
</script>
```

In the `script` section, we define one prop `post`, which will contain all the necessary information about the post.

Let’s look at the template:

```html
<template lang="pug">  
section.section  
  .content  
    img.pf__image(  
      :src="getDynamicFile(post.img)"  
      :alt="`post-image-${post.id}`"  
    )  

    .pf__md(v-html="getDynamicFile(post.file).default")  
</template>
```

As you can see, we dynamically get and render both an image and a `.md` file using our `getDynamicFile` mixin.

I think you noticed that we use the v-html directive to render the file, since `@nuxtjs/markdownit` do the rest. That’s extremely easy!

We can use the `::v-deep` selector to customize styles of rendered `.md` file. Take a look on [Github](https://github.com/mikhail-shpakov/nuxt-blog/blob/master/components/PostFull/index.vue) to see how this component is made.

In this component, I only set indents for paragraphs to show the principle of customization, but in a real application, you will need to create a complete set of styles for all used and necessary html elements.

### Pages ###

When all the components are ready, we can create the pages.

As you probably already understood from the design, our application consists of a main page with a list of all posts and a dynamic web page that displays the selected post.

`Pages` directory structure:
```
pages/
-- index.vue
-- post/
---- _id.vue
```

All components are self-contained, and their states are determined through props, so our pages will look like a list of components specified in the right order.

The main page will look like this:

```html
<template lang="pug">  
.page  
  section-header(  
    title="Nuxt blog"  
    subtitle="The best blog you can find on the global internet"  
  )  

  post-list  
</template>  
  
<script lang="ts">  
import Vue from 'vue'  

export default Vue.extend({  
  name: 'HomePage',  
})  
</script>
```

To set proper indentation, we used the global `.page` class we created earlier in `assets/styles/global/other.scss`.

A separate post page will look a little more complex. Let's take a look at the `script` section first:

```typescript
<script lang="ts">  
import Vue from 'vue'  
import { Post } from '~/content/Post'  
import posts from '~/content/posts'

export default Vue.extend({  
  validate({ params }) {  
    return /^\d+$/.test(params.id)  
  },  
  
  computed: {  
    currentId(): number {  
      return Number(this.$route.params.id)  
    },  
    currentPost(): Post | undefined {  
      return posts.find(({ id }) => id === this.currentId)  
    },  
  },  
})  
</script>
```

We see the `validate` method. This method is absent in `Vue`, `Nuxt` provides it to validate the parameters received from the router. Validate will be called every time you navigate to a new route. In this case, we just check that the `id` passed to us is a number. If the validation fails, the user will be returned to the `error.vue` error page.

There are 2 computed properties presented here. 
Let's take a closer look at what they do:

1) `currentId` - this property returns us the current post `id` (which was obtained from the router parameters), having previously converted it to `number`.

2) `currentPost` returns an object with information about the selected post from the array of all posts.

Well, we seem to figure it out. Let's take a look at the template:

```html
<template lang="pug">  
.page
  link-to-home  

  section-header(  
    :title="currentPost.title"  
  )  

  post-full(  
    :post="currentPost"  
  )
</template>
```

The style section for this page, as well as for the main page, is missing.

The code for the pages on [Github](https://github.com/mikhail-shpakov/nuxt-blog/tree/master/pages).

# Deployment to [Hostman](http://hostman.com/) #

Hooray! Our application is almost ready. It's time to start deploying it.

To do this task I will use the [Hostman cloud platform](http://hostman.com/), which allows to automate the deployment process.

Besides, [Hostman](http://hostman.com/) provides a free plan for static sites. That is exactly what we need.

To publish we should click the `Create` button in the platform interface, select a free plan and connect our Github repository, specifying the necessary options for deployment.

Immediately after that, publishing will automatically start and a free domain will be created in the `*.hostman.site zone` with the `ssl` certificate from Let's Encrypt.

From now with every new push to the selected branch (`master` by default) a new version of the application will deploy. Simple and convenient!

# Conclusion #

So, what we have now:

* [Design](https://www.figma.com/file/s1B9t0XOmRhtNY8daezIs7/MVP-on-a-modern-stack-in-1-day?node-id=34%3A0)
* [Github](https://github.com/mikhail-shpakov/nuxt-blog)
* [Demo of the first part](https://nuxt-blog.hostman.site/) 

We tried to demonstrate in practice how to work with Nuxt.js. We have managed to build a simple application from start to finish, from making a UI kit to a deployment process.

If you have followed all the steps from this post, congratulations on creating your first Nuxt.js application! Was it difficult? What do you think about this framework? If you have any questions or suggestions, feel free to write comments below.

# Sources: #

**Building**

* Official site [Nuxt.js](https://ru.nuxtjs.org/) 
* [@nuxtjs/style-resources](https://github.com/nuxt-community/style-resources-module) module 
* [Options API](https://typescript.nuxtjs.org/cookbook/components/#options-api) or [Class API](https://typescript.nuxtjs.org/cookbook/components/#class-api)
* [webpack-dev-server](https://github.com/webpack/webpack-dev-server)
* [HMR](https://webpack.js.org/concepts/hot-module-replacement/)
* [Jest](https://github.com/facebook/jest)

**Fonts and Images**

* [Open Font License](https://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=OFL)
* [Google Fonts](https://fonts.google.com/specimen/Rubik)
* [Webfontloader](https://github.com/Developmint/nuxt-webfontloader) library
* images from [unDraw](https://undraw.co/illustrations)

**Deployment**

* [Hostman cloud platform](http://hostman.com/)