How to Create and Deploy a Nuxt.JS Application

Introduction

Nuxt.JS is a framework for creating Vue.JS applications, you can choose between Universal, Static Generated or Single Page application.

Why Nuxt.JS?

  • Nuxt.JS create a framework flexible enough that can be used as a main project base or in addition to your current project based on it. Nuxt.JS focuses on UI rendering while abstracting away the client / server distribution.
  • Nuxt.JS create single page applications (SPA mode) quickly, useful to keep Nuxt features while working on back office applications.
  • Nuxt.JS comes with a lot of features to help you in your development between the client side and the server side such as Asynchronous Data, Middleware, Layouts, Pages, Plugins etc.
  • Nuxt.JS presets all the configuration needed to make your development of a server rendered Vue.JS application more enjoyable.

Resources

The following resources were used in this tutorial:

Under the hood Nuxt.JS uses Webpack with vue-loader and babel-loader to bundle, code-split and minify your code.

Setup

Create a Nuxt.JS project by running the following command on your terminal:

$ npx create-nuxt-app <project-name>

Or with yarn:

$ yarn create nuxt-app <project-name>

It will ask you some questions:

  1. Choose between integrated server-side frameworks:

Select None for this tutorial

2. Choose your favorite UI framework:

Select Vuetify for this tutorial

3.  Choose your favorite testing framework:

  • None (feel free to add one later)
  • Jest
  • AVA

Select None as we won’t be testing.

4. The Nuxt mode you want (Universal or SPA)

5.  Add axios module to make HTTP request easily into your application.

6.  Add EsLint to Lint your code on save.

7.  Add Prettier to prettify your code on save.

When answered, it will install all the dependencies so the next step is to navigate to the project folder and launch it with:

$ cd <project-name>
$ npm run dev

The application is now running on http://localhost:3000.

NOTE: Nuxt.js listens to changes in the pages directory so there is no need to restart the application when adding new pages.

Here is what the applications looks like on port http://localhost:3000.

Here is what the directory structure looks like on Visual Studio Code editor.

For the majority of the tutorial we would most work with within the layout > default.vue file and the pages > index.vue and pages > inspire.vue files respectively.

First, remove one of the drawers, icons and rename the app to NewsApp.

Lastly, adding a route and making modification on the inspire route to news, below is a code sample to effect the changes:

Building a News App

<template> 
   <v-app dark> 
       <v-navigation-drawer v-model="drawer" :mini-variant="miniVariant" :clipped="clipped" fixed app > 
           <v-list> 
               <v-list-tile v-for="(item, i) in items" :key="i" :to="item.to" router exact > 
                  <v-list-tile-action> 
                     <v-icon>{{ item.icon }}</v-icon> 
                   </v-list-tile-action> 
                 <v-list-tile-content> 
              <v-list-tile-title v-text="item.title" />
            </v-list-tile-content> </v-list-tile> 
          </v-list> 
      </v-navigation-drawer> 
<!-- title bar --> 
<v-toolbar :clipped-left="clipped" fixed app > 

<v-toolbar-side-icon @click="drawer = !drawer" /> 

<v-toolbar-title v-text="title" /> <v-spacer /> 

</v-toolbar> <!-- end title bar -->

 <!-- main content -->
 <v-content> 
<v-container> 

<nuxt /> 

</v-container> 

</v-content> 

<!-- ends main content -->

 <!-- footer page --> 

<v-footer :fixed="fixed" app >

 <span>&copy; 2019</span> 

</v-footer>

 <!-- ends footer --> 

</v-app>

 </template>

 <script> 

export default { data() { return { clipped: false, drawer: false, fixed: false, items: [ { icon: 'apps', title: 'Welcome', to: '/' }, { icon: 'bubble_chart', title: 'News', to: '/news' }, { icon: 'group_work', title: 'About', to: '/about' } ], miniVariant: false, right: true, rightDrawer: false, title: 'NewsApp' } } } 

</script>

Now lets make modification to the pages > index.vue. We include a carousel / slider to display images from a cdn to our News Web App. See the sample code below:

<template>
  <v-layout row wrap>
    <v-flex xs12>
    <v-carousel>
      <v-carousel-item
        v-for="(article, index)  in articles"
        :src="article.src"
        :key="index"
      >
      </v-carousel-item>

      </v-carousel>
      <v-divider></v-divider>
    </v-flex>
  </v-layout>
</template>

<script>
  export default {
    data () {
      
      return {
        articles: [
          {
            src: 'https://i0.wp.com/cdn.vanguardngr.com/wp-content/uploads/2018/10/pdp-members.gif?fit=412%2C230&ssl=1'
          },
          {
            src: 'https://cdn.punchng.com/wp-content/uploads/2019/06/02173535/Trump-and-Meghan.jpg'
          },
          {
            src: 'https://cdn.punchng.com/wp-content/uploads/2019/01/28153616/Pope-Francis1.jpg'
          },
          {
            src: 'https://cdn.punchng.com/wp-content/uploads/2018/10/01183201/Pastor-William-Kumuyi-and-President-Muhammadu-Buhari.jpg'
          }
        ],
        
      }
    }
  }
</script>

Now we need to sign up for an account on the official News API website for real time new top headlines.

A key would be generated once sign up has been successful hence users can make real time GET REQUEST to fetch data.

Moving on we need to modify the pages > news.vue to enable us make a GET request to our News API.

<template>
  <v-flex>
    <v-flex xs12 sm6 pb-3 offset-sm3 v-for="(article, index) in articles" :key="index">
      <v-card>
        <img
          :src="article.urlToImage"
          width="100%"
          height="200px"
        >

        <v-card-title primary-title>
          <div>
            <div class="headline">{{article.title}}</div>
          </div>
        </v-card-title>

        <v-card-text>
          {{article.content}}
        </v-card-text>
        
        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn flat :href="article.url" target="_blank">Open</v-btn>
          <v-spacer></v-spacer>
        </v-card-actions>
      </v-card>
    </v-flex>
  </v-flex>
</template>
<script>
  export default {
    data: () => ({
      show: false
    }),
    async asyncData({$axios}){
      const {articles} = await $axios.$get('https://newsapi.org/v2/top-headlines?country=ng&apiKey=af4129710bf14609b57b33cc43239681');
      return{articles};
    }
  }
</script>

Installing Axios and Font Awesome Icons

From the snippet above, I made use of my generated API key so you should feel free to replace it with once you have already signed up.

Up next, we need to tidy up our codes on the layouts > default.vue file such that relevant social media links to our profile be added including loading in of various brand icons.

To work with fonts in Nuxt we need to install Nuxt Font Awesome. Feel free to read the documentation.

We also need to setup Axios to enable us make successful request. Feel free to read documentation and setup.

Now we need to modify the nuxt.config.js and add our new installed configuration.

import VuetifyLoaderPlugin from 'vuetify-loader/lib/plugin'
import pkg from './package'


export default {
  mode: 'universal',

  /*
  ** Headers of the page
  */
  head: {
    title: pkg.name,
    meta: [
      { charset: 'utf-8' },
      { name: 'viewport', content: 'width=device-width, initial-scale=1' },
      { hid: 'description', name: 'description', content: pkg.description }
    ],
    link: [
      { rel: 'icon', type: 'image/x-icon', href: '/favicon.ico' },
      {
        rel: 'stylesheet',
        href:
          'https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Material+Icons'
      }
    ]
  },

  /*
  ** Customize the progress-bar color
  */
  loading: { color: '#fff' },

  /*
  ** Global CSS
  */
  css: [
    '~/assets/style/app.styl'
  ],

  /*
  ** Plugins to load before mounting the App
  */
  plugins: [
    '@/plugins/vuetify',
  ],

  /*
  ** Nuxt.js modules
  */
  modules: [
    '@nuxtjs/axios',
    'nuxt-fontawesome',

    ['nuxt-fontawesome', {
      component: 'fa', 
      imports: [
        //import whole set
        {
          set: '@fortawesome/free-solid-svg-icons',
          icons: ['fas']
        },
        
        {
         set:'@fortawesome/free-brands-svg-icons',
         icons: ['fab']
        } 
      ]
    }],
  ],

  axios: {
    // proxyHeaders: false
  },


  /*
  ** Build configuration
  */
  build: {
    transpile: ['vuetify/lib'],
    plugins: [new VuetifyLoaderPlugin()],
    loaders: {
      stylus: {
        import: ['~assets/style/variables.styl']
      }
    },
    /*
    ** You can extend webpack config here
    */
    extend(config, ctx) {
    }
  }

}

Adding Social Media Icons to Default Page

Lastly, add the existing features to the layouts > default.vue to include Social Media icons and our fetched news headlines.

<template>
  <v-app dark>
    <v-navigation-drawer
      v-model="drawer"
      :mini-variant="miniVariant"
      :clipped="clipped"
      fixed
      app
    >
      <v-list>
        <v-list-tile
          v-for="(item, i) in items"
          :key="i"
          :to="item.to"
          router
          exact
        >

          <v-list-tile-action>
            <v-icon>{{ item.icon }}</v-icon>
          </v-list-tile-action>

          <v-list-tile-content>
            <v-list-tile-title v-text="item.title" />
          </v-list-tile-content>

        </v-list-tile>
      </v-list>
    </v-navigation-drawer>
    
    <!-- title bar -->
    <v-toolbar
      :clipped-left="clipped"
      fixed
      app
    >
      <v-toolbar-side-icon @click="drawer = !drawer" />
      
      <v-toolbar-title v-text="title" />
      <v-spacer />
    </v-toolbar>
    <!-- end title bar -->

    <!-- main content -->
    <v-content>
      <v-container>
        <nuxt />
      </v-container>
    </v-content>
    <!-- ends main content -->
    <!-- footer page -->
  
    <v-footer
      :fixed="fixed"
      app
      height="auto"
    >
    <v-card
      class="flex dark lighten-1 white--text"
      flat
      tile

    >
      <v-card-title>
        <v-layout row wrap>
          <v-flex xs4>
            <strong class="subheading">Get connected</strong> 
          </v-flex>
          <v-flex xs2>
              <a href="https://www.linkedin.com/in/suleolanrewaju/"><fa :icon="fab.faLinkedin"  class="mx-4 fa-2x"/></a> 
          </v-flex>
          <v-flex xs2>
            <a href="https://medium.com/@suleabimbola/"><fa :icon="fab.faMedium"  class="mx-4 fa-2x"/></a>
          </v-flex>
          <v-flex xs2>
            <a href="https://twitter.com/lanromanero"><fa :icon="fab.faTwitter"  class="mx-4 fa-2x"/></a>
          </v-flex>
          <v-flex xs2>
            <a href="https://github.com/larrysul"><fa :icon="fab.faGithub"  class="mx-4 fa-2x"/></a>
          </v-flex>
        </v-layout>  

      </v-card-title>
    </v-card>
  </v-footer>

    <!-- ends footer -->
  </v-app>
</template>
<style>
  a{
    color:#fff
  }
</style>

<script>
import {fab} from '@fortawesome/free-brands-svg-icons'

export default {
  data() {
    return {
      clipped: false,
      drawer: false,
      fixed: false,
      items: [
        {
          icon: 'apps',
          title: 'Welcome',
          to: '/'
        },
        {
          icon: 'arrow_forward_io',
          title: 'Latest News',
          to: '/news'
        },
        {
          icon: 'arrow_forward_io',
          title: 'About App',
          to: '/about'
        }
      ],
      miniVariant: false,
      right: true,
      rightDrawer: false,
      title: 'Top Headlines'
    }

  },
  computed: {
    fab () {
         return fab
      }
  }
}
</script>

About Us Page

A brief information can also be added to the pages > about.vue.

<template>
    <div>
        <v-container>
            <v-layout>
                <h3>  Simple app based on Nuxt.js, which is a framework for creating Vue.js applications. It uses a news api <a href="https://newsapi.org/">https://newsapi.org/</a>  to get various content before rendering </h3>
            </v-layout>
        </v-container>
    </div>
</template>

Each time you make changes the Nuxt.JS recompiles and serves the app on localhost:3000. If it does not  you can always do npm run dev to start development server.

Now here is what our application looks pretty much like.

Welcome Page 

News Page 

Build and Deploy Using Surge

We need to run npm run generate in the command line interface. this will help build and generate the static files required to be deployed on Surge.

Installing Surge

To install Surge run npm install –global surge. This allows Surge to be installed globally and readily available any other time there is a need to deploy. For more information see the Surge online documentation.

Once installation is complete run surge. This will start the deployment and you will be required to set a path which is always in the \dist and generate a domain url through which the application will be accessed.

Useful Links:

News App is Live

News API with Nuxt.JS on GitHub

1
0
CategoriesTags

Related Posts