Dylan  Iqbal

Dylan Iqbal

1560953015

Build Universal Applications with Nuxt.js

In this tutorial, you’ll build an application with Nuxt using multiple routes populated with data from an API all rendered on the server. Then you will protect that information with authentication and require users to sign in. All you need to follow along all is a version of NPM newer than 5.2.0 and your preferred editor.

Reducing the time between a user clicking your application and the content being displayed is vital. Optimized images? Check! Minified CSS? Check! Minified JS? Check! But if your application is a single page app (or SPA) there is a large bundle of JavaScript that must reach the user before the site can be rendered.

Universal applications address this problem by executing as much as possible on your server and sending only the finished page to the client. Nuxt.js is a framework built on top of Vue designed to provide opinionated defaults to address a lot of the issues developers encounter as they develop universal applications.

With a Vue single page app, your index page looks like this:

<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>Demo App</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but WidgetCo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
  <script type="text/javascript" src="/app.js"></script>
  </body>
</html>

Everything within that page is rendered only once that final app.js is retrieved from the server. This impacts not just clients on a slow internet connection but those who can’t access JavaScript applications, all they will see is a blank page or the noscript warning. The vast majority of users will now be running with JavaScript enabled but this still blocks one major visitor to your site’s content, search engine crawlers. One workaround is to create static content pages but this can cause further problems if you want to place this content behind the authentication logic that you have defined in your router.

Look at the same page prepared with Nuxt.

<html data-n-head-ssr data-n-head="">
  <head data-n-head="">
    <title data-n-head="true">intro-to-nuxt</title>
    <meta data-n-head="true" charset="utf-8">
    <meta data-n-head="true" name="viewport" content="width=device-width, initial-scale=1">
    <meta data-n-head="true" data-hid="description" name="description" content="My astonishing Nuxt.js project">
    <link data-n-head="true" rel="icon" type="image/x-icon" href="/favicon.ico">
    <link data-n-head="true" rel="stylesheet" href="https://fonts.googleapis.com/css?family=Berkshire+Swash|Roboto">
  </head>
  <body data-n-head="">
    <div data-server-rendered="true" id="__nuxt">
        <div id="__layout">
            <div id="defaultLayout">
                <header>
                    <h1 id="branding">WidgetCo</h1>
                </header>
                <div class="content">
                    <div>
                        <h1 class="statement">The amazing new Widget is coming soon</h1>
                        <p class="subtext">It's revolutionary it will change the world of <span class="userAgent"></span> widgets as we know it.</p>
                        <p class="subtext">Be sure to sign-up to find out more about the next generation of widgets and follow our progress</p>
                        <a href="/learnMore" class="callToAction">Learn More</a> <a href="/progress" class="callToAction">Follow Our Progress</a>
                    </div>
                </div>
                <footer id="footer">
                    Made with Nuxt
                </footer>
            </div>
        </div>
    </div>
  </body>
</html>

This content is immediately more readable and is easy for bots to index without the need to separately manage content for them to find.

Nuxt.js provides three deployment options for your application; traditional SPA, server rendered, and statically generated. Depending on your deployment option Nuxt includes intelligently bundles Vue 2, Vue Router, Vuex, Vue Server Renderer, and Vue-meta all into a 60kB package with webpack, vue-loader, and babel-loader to support bundling and ES6/7 transpilation.

Can you do all of this in Vue without using Nuxt? Absolutely! There is an entire guide on building SSR applications with Vue. Nuxt only provides convention over configuration with sensible defaults for project structure. If you want to jump directly to building your application logic without as much wiring then an opinionated framework like Nuxt is a great place to start.

Zero to One

To get started, execute the following command from the terminal to launch the Nuxt template.

npx create-nuxt-app intro-to-nuxt

The Nuxt template guides you through the setup of your project metadata. To keep it simple you should select the default for each option.

Once the template has been completed, you are left with a simple project structure and can start the application in a development mode using the following two commands.

cd intro-to-nuxt  
npm run dev

During the build, you will notice both a client and a server package

are prepared. Once the build completes if you open a browser to

http://localhost:3000 you are greeted by the Nuxt splash screen.

Now that you have a running application, you can take a tour of the structure that Nuxt created for you.

  • Assets and components: These are present as you would expect with a Vue project, except they are now present at the root level rather than being within /src.
  • Static: Contains resources which will be made available exactly as they are from the root of the application. This is the same as the public directory you would get with a Vue project.
  • Layouts: Vue files in this folder provide the scaffolding for your application. These are wrappers around the <nuxt /> tag which displays the page.
  • Middleware: Vue files in this folder are invoked by the router before rendering a page.
  • Pages: These are the routes of your Nuxt application. The router generated by Nuxt will create a route for each Vue file in this directory.
  • Plugins: Vue files in this directory allow you to execute logic before running the application.
  • Store: This folder acts as the repository for Vuex (the state management library for Vue).

Finally, in the root directory, you will seenuxt.config.js. This allows us to define the behavior of our Nuxt application, such as setting global includes and middleware. The keys available here are extensive, we’ll touch on some during this tutorial but it’s worth browsing the configuration documentation to see all of the options available to you.

Build Your Nuxt Application

Let’s build the sample out into something a little more realistic. For this tutorial, you’ll build a simple promo and release status page for a product.

In your editor of choice open up the directory created by the Nuxt template.

Update index.vue in the pages directory with some relevant content:

<template>
  <div>
    <h1 class="statement">The amazing new Widget is coming soon</h1>
    <p class="subtext">It's revolutionary it will change the world of <UserAgent />  widgets as we know it.</p>
    <p class="subtext">Be sure to sign-up to find out more about the next generation of widgets
    and follow our progress</p>
  </div>
</template>

<script>
import UserAgent from '../components/userAgent.vue'
export default {
  components: {
    UserAgent
  }
}
</script>

<style>
</style>

This page is now referencing a standard Vue component in our component directory, so you must create the file userAgent.vue in that directory with the following content:

<template>
    <span class="userAgent"></span>
</template>
<script>
export default {
  data() {
    return {
      userbrowser: detectAgent()
    }
  }
}
function detectAgent(){
    if(process.client){
        if(navigator.userAgent.indexOf("Firefox") !== -1 ) 
        {
            return 'Firefox'
        }
        else if(navigator.userAgent.indexOf("Chrome") !== -1 )
        {
            return 'Chrome'
        }
        else if(navigator.userAgent.indexOf("Safari") !== -1)
        {
            return 'Safari'
        }
        else 
        {
            return 'browser'
        }
    }
}
</script>
<style>
</style>

One of the difficulties of handling components originally built for SPAs in a universal application is managing how to detect and behave when the user’s browser isn’t present. Nuxt exposes process.client, process.server and process.static globally to determine the context the renderer is running in. In userAgent.vue you’re using the process.client conditional to ensure that the navigator is never referenced during the server side render. If you were to remove this conditional logic, you would get an error during build like this:

Now that you have a landing page you can build out some additional content. Add the following inside the div tags of index.vue.

    <nuxt-link to="/learnMore" class="callToAction">Learn More</nuxt-link>
    <nuxt-link to="/progress" class="callToAction" no-prefetch>Follow Our Progress</nuxt-link>

The nuxt-link behaves in much the same as router-link in Vue and is used to create links between the pages of your application. One of the benefits of using nuxt-link is that when a nuxt-link is displayed the linked page is pre-fetched to improve responsiveness. You can disable this behavior by adding the no-pretech property to the link.

Add two more pages to populate those links. Create the files learnMore.vue and progress.vue in the pages folder. The Nuxt router will automatically create routes for these pages based on the file names.

First the learnMore.vue:

<template>
  <div>
    <h1 class="statement">Learn more about our widgets</h1>
    <p class="bodytext">We grow the finest widgets with our secret recipe.</p>
    <p class="bodytext">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in 
        urna sed mauris consequat semper. Vestibulum faucibus id velit facilisis
        pharetra. Vivamus tincidunt orci eget metus pretium tristique. Nullam mi
        massa, interdum et sagittis in, pellentesque id metus. Praesent in 
        mattis purus, vitae auctor nisi. Maecenas ut orci nec urna vestibulum
        laoreet. Phasellus lacinia iaculis imperdiet. Nullam tincidunt velit
        eu tortor varius scelerisque. Nullam placerat ligula tincidunt mi
        placerat blandit.
        Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas sodales
        finibus diam, a aliquet sapien. Nam molestie eros non tincidunt facilisis.
        Praesent facilisis massa a lorem commodo, a ultricies arcu vehicula. Curabitur a
        tincidunt magna. Maecenas porta sodales turpis id tempus. Etiam fringilla
        tincidunt ullamcorper. Phasellus quis dolor dignissim, tincidunt dolor et,
        viverra neque. Praesent at tellus turpis. Integer nec aliquet est, ut ultricies
        ex. Sed purus ex, pretium ut facilisis quis, accumsan eu elit. Nullam ac egestas
        metus, non viverra libero. Integer a turpis diam. Duis ullamcorper eleifend est
        id ullamcorper.
    </p>
    <nuxt-link to="/" class="callToAction">Go back</nuxt-link>
  </div>
</template>

<script>
    export default {
        head () {
            return {
                title: `About our widgets`,
                meta: [
                    { hid: 'description', name: 'description', content: 'WidgetCo provides the finest in modern widgets, find out how...' },
                    { name: 'keywords', content: 'widgetCo, widgets, widget design'},
                ]
            }
        }
    }
</script>

<style>
</style>

For the learn more page you have extended the default head values to ensure that you have a good page description and keywords embedded in the meta. Any values set here will override any global head values you set in the nuxt.config.js. This is all handled by [vue-meta](<a href="https://github.com/nuxt/vue-meta)" target="_blank">https://github.com/nuxt/vue-meta)</a>.

Next, you’ll create a page with some dynamic content by talking to an API. For this tutorial, we’ll mock an API with a static JSON file. Create status.json in the static folder and give it the following content:

{
    "statusDate": "2018-04-14",
    "statusUpdate": "We are sorry to report that bad weather has impacted the growth of our widgets. We are working as fast as we can to get widgets dispatched to you."
}

To make your API calls you’ll be using the promise-driven Axios library. From the terminal install this package with the following command:

npm install axios

You are now ready to create your page. Create progress.vue in the pages directory and populate it with the following content:

<template>
  <div>
    <h1 class="statement">Progress Report</h1>
    <p></p>
    <p class="bodytext">
      
    </p>
    <nuxt-link to="/" class="callToAction">Go back</nuxt-link>
  </div>
</template>

<script>
const axios = require('axios'); 
export default {
  asyncData ({ params }) {
    return axios.get('http://localhost:3000/status.json')
    .then((res) => {
      return {
        statusUpdate: res.data.statusUpdate,
        statusDate: res.data.statusDate
      }
    })
  }
}
</script>

<style>
</style>


On this page, you are using the asyncData component to make the Axios call. On the server side, the result is then parsed and made available to the template using the `` syntax. The difference between asyncData and the data syntax is where the call is executed. With data, the call is always made from the client side after the page reaches the client a further call is made to replace values that came with the page. With asyncData, the request is made by the server and the result is then merged with the values already in data.

Better, but what about the structure which will be common between pages?

This is where layouts come in. Each of the pages you’ve just created sit within a layout so you can reuse features without needing to write them into each page. As you have not defined a layout explicitly, the default layout created by the template is being used. Open the default.vue from the layouts folder. Layouts must include the <nuxt /> tag which renders the page, however, the rest of the structure is up to you, include any HTML or Vue components you need. Replace the default.vue content with the following:

<template>
  <div id=defaultLayout>
    <header><h1 id="branding">WidgetCo</h1></header>
    <div class="content">
      <nuxt />
    </div>
    <footer id="footer">
      Made with Nuxt
    </footer>
  </div>
</template>

<style>
  body #__nuxt, #__layout,#defaultLayout {
    display: flex;
    min-height: 98vh;
    flex-direction: column;
  }
  .content {
    flex: 1;
  }
</style>

Now you have common elements which can be displayed around your pages. You can use different layouts to handle a change in presentation between different parts of your site from marketing to documentation to tutorials.

Currently, your application is looking pretty bland so let’s add some CSS. Inside the assets directory create a new folder called css and add a main.css file with the following content:

html{
    background: #20313b;
}

body{
    font-family: 'Roboto', sans-serif;
    color: hsl(240, 5%, 83%);
}

.content{
    margin-top: 50px;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    font-weight: lighter;
}

footer{
    font-size: smaller;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    font-weight: lighter;
}

header{
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    font-weight: lighter;
}

#branding{
    font-family: 'Berkshire Swash', cursive;
}

.statement{
    color: white;
    font-size: 350%
}

.callToAction {
    background-color: #e22866;
    color: white;
    border-radius: 4px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 2px;
    line-height: 45px;
    height: 45px;
    border: 6px solid transparent;
    cursor: pointer;
    text-decoration: none;
}

.userAgent{
    color: #e22866
}

.page-enter-active, .page-leave-active{
    transition: opacity .5s
}

.page-enter, .page-leave-active{
    opacity: 0
}

You can add this stylesheet to the head of all of your pages easily by adding it to the nuxt.config.js. Open this file from the root directory of your project, this file is organized into a number of arrays. The template project has included the common ones for you, each is described by a short comment update the global CSS to include your new file:

 /*
  ** Global CSS
  */
  css: [
    '@/assets/css/main.css'
  ],

That stylesheet also includes a couple of fonts from Google which you need to link from your head. You’ll find this declared near the top of the file. You’ll add to the link section with the link to the stylesheet.

  /*
  ** 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=Berkshire+Swash|Roboto' }
    ]
  }

Your console may show a refresh when nuxt.config.js is saved. However, since nuxt.config.js is executed before the service is run, you’ll need to stop the running process and restart with npm run dev. Once you’ve done so, you’ll have a styled page like the one below.

Protect Your Resources in Nuxt

Perhaps you don’t want to share the information on the progress page with just anyone who visits the site. Instead, you want to restrict that information to people who have registered. You also want to use modern web authentication standards like OAuth and OpenID Connect, which you’ll use to retrieve tokens and thus grant access to your resources.

You could build everything yourself, we only need email address and password after all. But how should you store that password? How does someone get back into their account if they forget their password? What happens when you need to enable multi-factor authentication? How can you allow users of this site to access other sites from your company?

Okta to the rescue! Okta provides a secure, simple and standards-based identity source for your application. No more writing registration forms!

First go to developer.okta.com/signup which will guide you through getting a free developer tenant on Okta. Your tenant will have a name such as dev-1234.okta.com make a note of this address we’ll need it later.

Once you have signed in as an administrator select Applications from the menu at the top of the page, then Add application.

As you are working as a universal application you’ll select Web here. This determines if a client secret is generated for the application. Single page applications do not have secure storage for this secret so one is not generated if you select “Single-Page App”.

On the next screen, you need to provide a few details about the application you are creating. The key values are Base URIs and Login Redirect URIs. The former tells Okta where to expect authentication attempts from, and the later tells Okta where it is allowed to send users to after authentication. For your development environment, add <a href="http://localhost:3000" target="_blank">http://localhost:3000</a> as the base URI and <a href="http://localhost:3000/auth/callback" target="_blank">http://localhost:3000/auth/callback</a> as the login redirect URI. Click done!

This next page shows you the configuration of your application. You’ll need the two values shown at the very bottom of this page, Client ID and Client Secret.

You’ll put them in an .env file in the root of your project, your OAUTH_ISSUER will contain your tenant name followed by /oauth2/v1

SECRET_KEY="sufficiently long random string to encrypt cookies"
OAUTH_ISSUER="https://{yourOktaDomain}/oauth2/v1/"
CLIENT_ID="{yourClientId}"
CLIENT_SECRET="{yourClientSecret}t"

Remember this file contains your application’s access to your OAuth provider and should not be checked into source control. To enable Nuxt to read this file you need to install a package from npm.

npm i @nuxtjs/dotenv

Once that is installed add the following line to the top of nuxt.config.js:

require('dotenv').config()

You also need to enable your Nuxt application to use your identity provider as a source of users. To do this you’ll use another npm package to make the application OAuth aware.

In your terminal, stop the running application and use the following command to install the library:

npm i nuxt-oauth

Note: there is an official Nuxt Community Auth module which supports OAuth. However, as of this writing, it does not include a nonce on requests for tokens. Therefore, it is not standards compliant.
Once that is installed, you need to configure its behavior in the nuxt.config.js. First, add nuxt-oauth to the array of modules.

  modules: [
    ['nuxt-oauth']
  ],

Then add a new oauth section to configure the OAuth library.

  oauth: {
    sessionName: 'WidgetCoSession',
    secretKey: process.env.SECRET_KEY,
    oauthHost: process.env.OAUTH_ISSUER,
    oauthClientID: process.env.CLIENT_ID,
    oauthClientSecret: process.env.CLIENT_SECRET,
    scopes: ['openid', 'profile'],
  },

This implementation requires a Vuex store. Nuxt will not create the store by default, you must create an empty index.vue file in the store folder. Once Nuxt detects this file it will include the correct dependencies for you.

Now that you have OAuth configured, you need to configure which routes require authentication. You can do this by adding the value authenticated: true to the default export of a page. Update the script tag of progress.vue in the pages folder with the following code.

<script>
const axios = require('axios'); 
export default {
  authenticated: true,
  asyncData ({ params }) {
    return axios.get('http://localhost:3000/status.json')
    .then((res) => {
      return {
        statusUpdate: res.data.statusUpdate,
        statusDate: res.data.statusDate
      }
    })
  }
}
</script>

Launch a private session in your browser and revisit localhost:3000. Now when you navigate to the progress screen you’ll be required to login.

Congratulations! You’ve now built a universal JavaScript application! Content is prepared on the server and sent to the user as multiple SEO-friendly pages complete with route specific metadata. You have used asyncData to populate your pages with dynamic content from an API. Finally you have protected sensitive information behind an identity provider and can force users to login before granting access.

Note: All of the source code for this article can be found on GitHub.##

#vue-js #nuxt-js

What is GEEK

Buddha Community

Build Universal Applications with Nuxt.js

Benefits of Angular JS based Applications

AngularJS was introduced in the year 2009, by Google. AngularJS is a software framework used worldwide by developers. The entire base of this framework is open source. AngularJS has gained popularity among developers because of how it has become for them to create web applications. AngularJS helps in building apps that require less work and reduces the use of unnecessary codes. AngularJS application development is a javascript framework. AngularJS has a clear goal to make the entire process simpler, it also helps app development process and operations as much as it could. AngularJS is used for building applications that support MVC (model view controller) and SPAs (single page web apps) coding and programming structures. AngularJS has been used by some of the top companies in the world to simplify their app development process, like, Google, Paypal, Udemy, mobile site in iPad for HBO, etc. To read more click on the link.

#hire angular js developer #hire dedicated angular js developer #angular js application development #hire dedicated angular js team #hire best angular js application developer

Node JS Development Company| Node JS Web Developers-SISGAIN

Top organizations and start-ups hire Node.js developers from SISGAIN for their strategic software development projects in Illinois, USA. On the off chance that you are searching for a first rate innovation to assemble a constant Node.js web application development or a module, Node.js applications are the most appropriate alternative to pick. As Leading Node.js development company, we leverage our profound information on its segments and convey solutions that bring noteworthy business results. For more information email us at hello@sisgain.com

#node.js development services #hire node.js developers #node.js web application development #node.js development company #node js application

Dylan  Iqbal

Dylan Iqbal

1560953015

Build Universal Applications with Nuxt.js

In this tutorial, you’ll build an application with Nuxt using multiple routes populated with data from an API all rendered on the server. Then you will protect that information with authentication and require users to sign in. All you need to follow along all is a version of NPM newer than 5.2.0 and your preferred editor.

Reducing the time between a user clicking your application and the content being displayed is vital. Optimized images? Check! Minified CSS? Check! Minified JS? Check! But if your application is a single page app (or SPA) there is a large bundle of JavaScript that must reach the user before the site can be rendered.

Universal applications address this problem by executing as much as possible on your server and sending only the finished page to the client. Nuxt.js is a framework built on top of Vue designed to provide opinionated defaults to address a lot of the issues developers encounter as they develop universal applications.

With a Vue single page app, your index page looks like this:

<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    <title>Demo App</title>
  </head>
  <body>
    <noscript>
      <strong>We're sorry but WidgetCo doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
    </noscript>
    <div id="app"></div>
  <script type="text/javascript" src="/app.js"></script>
  </body>
</html>

Everything within that page is rendered only once that final app.js is retrieved from the server. This impacts not just clients on a slow internet connection but those who can’t access JavaScript applications, all they will see is a blank page or the noscript warning. The vast majority of users will now be running with JavaScript enabled but this still blocks one major visitor to your site’s content, search engine crawlers. One workaround is to create static content pages but this can cause further problems if you want to place this content behind the authentication logic that you have defined in your router.

Look at the same page prepared with Nuxt.

<html data-n-head-ssr data-n-head="">
  <head data-n-head="">
    <title data-n-head="true">intro-to-nuxt</title>
    <meta data-n-head="true" charset="utf-8">
    <meta data-n-head="true" name="viewport" content="width=device-width, initial-scale=1">
    <meta data-n-head="true" data-hid="description" name="description" content="My astonishing Nuxt.js project">
    <link data-n-head="true" rel="icon" type="image/x-icon" href="/favicon.ico">
    <link data-n-head="true" rel="stylesheet" href="https://fonts.googleapis.com/css?family=Berkshire+Swash|Roboto">
  </head>
  <body data-n-head="">
    <div data-server-rendered="true" id="__nuxt">
        <div id="__layout">
            <div id="defaultLayout">
                <header>
                    <h1 id="branding">WidgetCo</h1>
                </header>
                <div class="content">
                    <div>
                        <h1 class="statement">The amazing new Widget is coming soon</h1>
                        <p class="subtext">It's revolutionary it will change the world of <span class="userAgent"></span> widgets as we know it.</p>
                        <p class="subtext">Be sure to sign-up to find out more about the next generation of widgets and follow our progress</p>
                        <a href="/learnMore" class="callToAction">Learn More</a> <a href="/progress" class="callToAction">Follow Our Progress</a>
                    </div>
                </div>
                <footer id="footer">
                    Made with Nuxt
                </footer>
            </div>
        </div>
    </div>
  </body>
</html>

This content is immediately more readable and is easy for bots to index without the need to separately manage content for them to find.

Nuxt.js provides three deployment options for your application; traditional SPA, server rendered, and statically generated. Depending on your deployment option Nuxt includes intelligently bundles Vue 2, Vue Router, Vuex, Vue Server Renderer, and Vue-meta all into a 60kB package with webpack, vue-loader, and babel-loader to support bundling and ES6/7 transpilation.

Can you do all of this in Vue without using Nuxt? Absolutely! There is an entire guide on building SSR applications with Vue. Nuxt only provides convention over configuration with sensible defaults for project structure. If you want to jump directly to building your application logic without as much wiring then an opinionated framework like Nuxt is a great place to start.

Zero to One

To get started, execute the following command from the terminal to launch the Nuxt template.

npx create-nuxt-app intro-to-nuxt

The Nuxt template guides you through the setup of your project metadata. To keep it simple you should select the default for each option.

Once the template has been completed, you are left with a simple project structure and can start the application in a development mode using the following two commands.

cd intro-to-nuxt  
npm run dev

During the build, you will notice both a client and a server package

are prepared. Once the build completes if you open a browser to

http://localhost:3000 you are greeted by the Nuxt splash screen.

Now that you have a running application, you can take a tour of the structure that Nuxt created for you.

  • Assets and components: These are present as you would expect with a Vue project, except they are now present at the root level rather than being within /src.
  • Static: Contains resources which will be made available exactly as they are from the root of the application. This is the same as the public directory you would get with a Vue project.
  • Layouts: Vue files in this folder provide the scaffolding for your application. These are wrappers around the <nuxt /> tag which displays the page.
  • Middleware: Vue files in this folder are invoked by the router before rendering a page.
  • Pages: These are the routes of your Nuxt application. The router generated by Nuxt will create a route for each Vue file in this directory.
  • Plugins: Vue files in this directory allow you to execute logic before running the application.
  • Store: This folder acts as the repository for Vuex (the state management library for Vue).

Finally, in the root directory, you will seenuxt.config.js. This allows us to define the behavior of our Nuxt application, such as setting global includes and middleware. The keys available here are extensive, we’ll touch on some during this tutorial but it’s worth browsing the configuration documentation to see all of the options available to you.

Build Your Nuxt Application

Let’s build the sample out into something a little more realistic. For this tutorial, you’ll build a simple promo and release status page for a product.

In your editor of choice open up the directory created by the Nuxt template.

Update index.vue in the pages directory with some relevant content:

<template>
  <div>
    <h1 class="statement">The amazing new Widget is coming soon</h1>
    <p class="subtext">It's revolutionary it will change the world of <UserAgent />  widgets as we know it.</p>
    <p class="subtext">Be sure to sign-up to find out more about the next generation of widgets
    and follow our progress</p>
  </div>
</template>

<script>
import UserAgent from '../components/userAgent.vue'
export default {
  components: {
    UserAgent
  }
}
</script>

<style>
</style>

This page is now referencing a standard Vue component in our component directory, so you must create the file userAgent.vue in that directory with the following content:

<template>
    <span class="userAgent"></span>
</template>
<script>
export default {
  data() {
    return {
      userbrowser: detectAgent()
    }
  }
}
function detectAgent(){
    if(process.client){
        if(navigator.userAgent.indexOf("Firefox") !== -1 ) 
        {
            return 'Firefox'
        }
        else if(navigator.userAgent.indexOf("Chrome") !== -1 )
        {
            return 'Chrome'
        }
        else if(navigator.userAgent.indexOf("Safari") !== -1)
        {
            return 'Safari'
        }
        else 
        {
            return 'browser'
        }
    }
}
</script>
<style>
</style>

One of the difficulties of handling components originally built for SPAs in a universal application is managing how to detect and behave when the user’s browser isn’t present. Nuxt exposes process.client, process.server and process.static globally to determine the context the renderer is running in. In userAgent.vue you’re using the process.client conditional to ensure that the navigator is never referenced during the server side render. If you were to remove this conditional logic, you would get an error during build like this:

Now that you have a landing page you can build out some additional content. Add the following inside the div tags of index.vue.

    <nuxt-link to="/learnMore" class="callToAction">Learn More</nuxt-link>
    <nuxt-link to="/progress" class="callToAction" no-prefetch>Follow Our Progress</nuxt-link>

The nuxt-link behaves in much the same as router-link in Vue and is used to create links between the pages of your application. One of the benefits of using nuxt-link is that when a nuxt-link is displayed the linked page is pre-fetched to improve responsiveness. You can disable this behavior by adding the no-pretech property to the link.

Add two more pages to populate those links. Create the files learnMore.vue and progress.vue in the pages folder. The Nuxt router will automatically create routes for these pages based on the file names.

First the learnMore.vue:

<template>
  <div>
    <h1 class="statement">Learn more about our widgets</h1>
    <p class="bodytext">We grow the finest widgets with our secret recipe.</p>
    <p class="bodytext">
        Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas in 
        urna sed mauris consequat semper. Vestibulum faucibus id velit facilisis
        pharetra. Vivamus tincidunt orci eget metus pretium tristique. Nullam mi
        massa, interdum et sagittis in, pellentesque id metus. Praesent in 
        mattis purus, vitae auctor nisi. Maecenas ut orci nec urna vestibulum
        laoreet. Phasellus lacinia iaculis imperdiet. Nullam tincidunt velit
        eu tortor varius scelerisque. Nullam placerat ligula tincidunt mi
        placerat blandit.
        Interdum et malesuada fames ac ante ipsum primis in faucibus. Maecenas sodales
        finibus diam, a aliquet sapien. Nam molestie eros non tincidunt facilisis.
        Praesent facilisis massa a lorem commodo, a ultricies arcu vehicula. Curabitur a
        tincidunt magna. Maecenas porta sodales turpis id tempus. Etiam fringilla
        tincidunt ullamcorper. Phasellus quis dolor dignissim, tincidunt dolor et,
        viverra neque. Praesent at tellus turpis. Integer nec aliquet est, ut ultricies
        ex. Sed purus ex, pretium ut facilisis quis, accumsan eu elit. Nullam ac egestas
        metus, non viverra libero. Integer a turpis diam. Duis ullamcorper eleifend est
        id ullamcorper.
    </p>
    <nuxt-link to="/" class="callToAction">Go back</nuxt-link>
  </div>
</template>

<script>
    export default {
        head () {
            return {
                title: `About our widgets`,
                meta: [
                    { hid: 'description', name: 'description', content: 'WidgetCo provides the finest in modern widgets, find out how...' },
                    { name: 'keywords', content: 'widgetCo, widgets, widget design'},
                ]
            }
        }
    }
</script>

<style>
</style>

For the learn more page you have extended the default head values to ensure that you have a good page description and keywords embedded in the meta. Any values set here will override any global head values you set in the nuxt.config.js. This is all handled by [vue-meta](<a href="https://github.com/nuxt/vue-meta)" target="_blank">https://github.com/nuxt/vue-meta)</a>.

Next, you’ll create a page with some dynamic content by talking to an API. For this tutorial, we’ll mock an API with a static JSON file. Create status.json in the static folder and give it the following content:

{
    "statusDate": "2018-04-14",
    "statusUpdate": "We are sorry to report that bad weather has impacted the growth of our widgets. We are working as fast as we can to get widgets dispatched to you."
}

To make your API calls you’ll be using the promise-driven Axios library. From the terminal install this package with the following command:

npm install axios

You are now ready to create your page. Create progress.vue in the pages directory and populate it with the following content:

<template>
  <div>
    <h1 class="statement">Progress Report</h1>
    <p></p>
    <p class="bodytext">
      
    </p>
    <nuxt-link to="/" class="callToAction">Go back</nuxt-link>
  </div>
</template>

<script>
const axios = require('axios'); 
export default {
  asyncData ({ params }) {
    return axios.get('http://localhost:3000/status.json')
    .then((res) => {
      return {
        statusUpdate: res.data.statusUpdate,
        statusDate: res.data.statusDate
      }
    })
  }
}
</script>

<style>
</style>


On this page, you are using the asyncData component to make the Axios call. On the server side, the result is then parsed and made available to the template using the `` syntax. The difference between asyncData and the data syntax is where the call is executed. With data, the call is always made from the client side after the page reaches the client a further call is made to replace values that came with the page. With asyncData, the request is made by the server and the result is then merged with the values already in data.

Better, but what about the structure which will be common between pages?

This is where layouts come in. Each of the pages you’ve just created sit within a layout so you can reuse features without needing to write them into each page. As you have not defined a layout explicitly, the default layout created by the template is being used. Open the default.vue from the layouts folder. Layouts must include the <nuxt /> tag which renders the page, however, the rest of the structure is up to you, include any HTML or Vue components you need. Replace the default.vue content with the following:

<template>
  <div id=defaultLayout>
    <header><h1 id="branding">WidgetCo</h1></header>
    <div class="content">
      <nuxt />
    </div>
    <footer id="footer">
      Made with Nuxt
    </footer>
  </div>
</template>

<style>
  body #__nuxt, #__layout,#defaultLayout {
    display: flex;
    min-height: 98vh;
    flex-direction: column;
  }
  .content {
    flex: 1;
  }
</style>

Now you have common elements which can be displayed around your pages. You can use different layouts to handle a change in presentation between different parts of your site from marketing to documentation to tutorials.

Currently, your application is looking pretty bland so let’s add some CSS. Inside the assets directory create a new folder called css and add a main.css file with the following content:

html{
    background: #20313b;
}

body{
    font-family: 'Roboto', sans-serif;
    color: hsl(240, 5%, 83%);
}

.content{
    margin-top: 50px;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    font-weight: lighter;
}

footer{
    font-size: smaller;
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    font-weight: lighter;
}

header{
    display: flex;
    flex-direction: column;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    font-weight: lighter;
}

#branding{
    font-family: 'Berkshire Swash', cursive;
}

.statement{
    color: white;
    font-size: 350%
}

.callToAction {
    background-color: #e22866;
    color: white;
    border-radius: 4px;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 2px;
    line-height: 45px;
    height: 45px;
    border: 6px solid transparent;
    cursor: pointer;
    text-decoration: none;
}

.userAgent{
    color: #e22866
}

.page-enter-active, .page-leave-active{
    transition: opacity .5s
}

.page-enter, .page-leave-active{
    opacity: 0
}

You can add this stylesheet to the head of all of your pages easily by adding it to the nuxt.config.js. Open this file from the root directory of your project, this file is organized into a number of arrays. The template project has included the common ones for you, each is described by a short comment update the global CSS to include your new file:

 /*
  ** Global CSS
  */
  css: [
    '@/assets/css/main.css'
  ],

That stylesheet also includes a couple of fonts from Google which you need to link from your head. You’ll find this declared near the top of the file. You’ll add to the link section with the link to the stylesheet.

  /*
  ** 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=Berkshire+Swash|Roboto' }
    ]
  }

Your console may show a refresh when nuxt.config.js is saved. However, since nuxt.config.js is executed before the service is run, you’ll need to stop the running process and restart with npm run dev. Once you’ve done so, you’ll have a styled page like the one below.

Protect Your Resources in Nuxt

Perhaps you don’t want to share the information on the progress page with just anyone who visits the site. Instead, you want to restrict that information to people who have registered. You also want to use modern web authentication standards like OAuth and OpenID Connect, which you’ll use to retrieve tokens and thus grant access to your resources.

You could build everything yourself, we only need email address and password after all. But how should you store that password? How does someone get back into their account if they forget their password? What happens when you need to enable multi-factor authentication? How can you allow users of this site to access other sites from your company?

Okta to the rescue! Okta provides a secure, simple and standards-based identity source for your application. No more writing registration forms!

First go to developer.okta.com/signup which will guide you through getting a free developer tenant on Okta. Your tenant will have a name such as dev-1234.okta.com make a note of this address we’ll need it later.

Once you have signed in as an administrator select Applications from the menu at the top of the page, then Add application.

As you are working as a universal application you’ll select Web here. This determines if a client secret is generated for the application. Single page applications do not have secure storage for this secret so one is not generated if you select “Single-Page App”.

On the next screen, you need to provide a few details about the application you are creating. The key values are Base URIs and Login Redirect URIs. The former tells Okta where to expect authentication attempts from, and the later tells Okta where it is allowed to send users to after authentication. For your development environment, add <a href="http://localhost:3000" target="_blank">http://localhost:3000</a> as the base URI and <a href="http://localhost:3000/auth/callback" target="_blank">http://localhost:3000/auth/callback</a> as the login redirect URI. Click done!

This next page shows you the configuration of your application. You’ll need the two values shown at the very bottom of this page, Client ID and Client Secret.

You’ll put them in an .env file in the root of your project, your OAUTH_ISSUER will contain your tenant name followed by /oauth2/v1

SECRET_KEY="sufficiently long random string to encrypt cookies"
OAUTH_ISSUER="https://{yourOktaDomain}/oauth2/v1/"
CLIENT_ID="{yourClientId}"
CLIENT_SECRET="{yourClientSecret}t"

Remember this file contains your application’s access to your OAuth provider and should not be checked into source control. To enable Nuxt to read this file you need to install a package from npm.

npm i @nuxtjs/dotenv

Once that is installed add the following line to the top of nuxt.config.js:

require('dotenv').config()

You also need to enable your Nuxt application to use your identity provider as a source of users. To do this you’ll use another npm package to make the application OAuth aware.

In your terminal, stop the running application and use the following command to install the library:

npm i nuxt-oauth

Note: there is an official Nuxt Community Auth module which supports OAuth. However, as of this writing, it does not include a nonce on requests for tokens. Therefore, it is not standards compliant.
Once that is installed, you need to configure its behavior in the nuxt.config.js. First, add nuxt-oauth to the array of modules.

  modules: [
    ['nuxt-oauth']
  ],

Then add a new oauth section to configure the OAuth library.

  oauth: {
    sessionName: 'WidgetCoSession',
    secretKey: process.env.SECRET_KEY,
    oauthHost: process.env.OAUTH_ISSUER,
    oauthClientID: process.env.CLIENT_ID,
    oauthClientSecret: process.env.CLIENT_SECRET,
    scopes: ['openid', 'profile'],
  },

This implementation requires a Vuex store. Nuxt will not create the store by default, you must create an empty index.vue file in the store folder. Once Nuxt detects this file it will include the correct dependencies for you.

Now that you have OAuth configured, you need to configure which routes require authentication. You can do this by adding the value authenticated: true to the default export of a page. Update the script tag of progress.vue in the pages folder with the following code.

<script>
const axios = require('axios'); 
export default {
  authenticated: true,
  asyncData ({ params }) {
    return axios.get('http://localhost:3000/status.json')
    .then((res) => {
      return {
        statusUpdate: res.data.statusUpdate,
        statusDate: res.data.statusDate
      }
    })
  }
}
</script>

Launch a private session in your browser and revisit localhost:3000. Now when you navigate to the progress screen you’ll be required to login.

Congratulations! You’ve now built a universal JavaScript application! Content is prepared on the server and sent to the user as multiple SEO-friendly pages complete with route specific metadata. You have used asyncData to populate your pages with dynamic content from an API. Finally you have protected sensitive information behind an identity provider and can force users to login before granting access.

Note: All of the source code for this article can be found on GitHub.##

#vue-js #nuxt-js

Sean Robertson

Sean Robertson

1560834345

Building a Universal Application with Nuxt.js and Django

In this article, we will see how to create a Universal application using Django and Nuxt.js. Django will handle the backend operations and provide the APIs using the (DRF) Django Rest Framework, while Nuxt.js will create the frontend.

Introduction

Table of Contents

The advent of modern JavaScript libraries such as React.js and Vue.js has transmogrified Front-end web development for the better. These libraries ship with wonderful features including SPA (Single Page Applications) which is basically the dynamic loading of the content in web pages without a full reload to the browser.

The concept behind most Single Page Applications is Client-Side Rendering. In Client-Side Rendering, the majority of content is rendered in a browser using JavaScript; on page load, the content doesn’t load initially until the JavaScript has fully downloaded and renders the rest of the site.

Client-Side Rendering is a relatively recent concept and there are trade-offs associated with its use. A notable negative side is that, since the content is not exactly rendered until the page is updated using JavaScript, SEO for the website will suffer as there will hardly be any data for search engines to crawl.

Server-Side Rendering, on the other hand, is the conventional way of getting HTML pages rendered on a browser. In the older Server-Side Rendered applications, the web application is built using a Server-Side language such as PHP. When a web page is requested by a browser, the remote server adds the (dynamic) content and delivers a populated HTML page.

Just as there are downsides to Client-Side Rendering, Server-Side rendering makes the browser send server requests too frequently and perform repetitions of full page reloads for similar data.

At this point, you must be thinking: “what if we could initially load the web page with an SSR (Server-Side Rendering) solution, then use a framework to handle the further dynamic routing and fetch only necessary data?”

Great thinking! There are JavaScript frameworks that already implement this solution and the resulting applications are called Universal Applications.

It is correct to say: Universal app = SSR + SPA.
In summary, a universal application is used to describe JavaScript code that can execute on the client and the server side. In this article, we will build a Universal Recipe application using Nuxt.js.

Nuxt.js is a higher-level framework for developing Universal Vue.js applications. Its creation was inspired by React’s Next.js and it helps to abstract the difficulties (server configuration and client code distribution) that arise in setting up Server-Side Rendered Vue.js applications. Nuxt.js also ships with lots of features that aid development between client side and server side such as async data, middleware, layouts etc.

It is correct to say: Universal app = SSR + SPA.
In this article, we will see how to create a Universal application using Django and Nuxt.js. Django will handle the backend operations and provide the APIs using the (DRF) Django Rest Framework, while Nuxt.js will create the frontend.

Here’s a demo of the final application:

From the image above, we see that the final application is a basic Recipes application that performs CRUD operations.

The source code for this tutorial is available here on GitHub.

Prerequisites

To follow along with this tutorial, you will need the following installed on your machine:

  1. Python3.
  2. Pip.
  3. Npm.

It is correct to say: Universal app = SSR + SPA.
The tutorial assumes that the reader has possession of the following:

  1. Python3.
  2. Pip.
  3. Npm.

Let’s dive right in!

Setting up the Backend

In this section, we will set up the backend and create all the folders that we need to get things up and running, so launch a new instance of a terminal and create the project’s directory by running this command:

$ mkdir recipes_app

Next, we will navigate into the directory:

cd recipes_app

Now we will install Pipenv using Pip and activate a new virtual environment:

$ pip install pipenv
$ pipenv shell

It is correct to say: Universal app = SSR + SPA.
Let’s install Django and other dependencies using Pipenv:

(recipes_app) $ pipenv install django django-rest-framework django-cors-headers

It is correct to say: Universal app = SSR + SPA.
Now, we will create a new Django project called api and a Django application called core:

(recipes_app) $ django-admin startproject api
(recipes_app) $ cd api
(recipes_app) $ python manage.py startapp core

Let’s register the core application, together with rest_framework and cors-headers, so that the Django project recognises it. Open the api/settings.py file and update it accordingly:

# api/settings.py

# Application definition
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', # add this
    'corsheaders', # add this
    'core' # add this 
  ] 

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware', # add this
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

 # add this block below MIDDLEWARE
CORS_ORIGIN_WHITELIST = (
    'localhost:3000',
)

# add the following just below STATIC_URL
MEDIA_URL = '/media/' # add this
MEDIA_ROOT = os.path.join(BASE_DIR, 'media') # add this

It is correct to say: Universal app = SSR + SPA.### Defining the Recipe model

Let’s create a model to define how the Recipe items should be stored in the database, open the core/models.py file and completely replace it with the snippet below:

# core/models.py

from django.db import models
# Create your models here.

class Recipe(models.Model):
    DIFFICULTY_LEVELS = (
        ('Easy', 'Easy'),
        ('Medium', 'Medium'),
        ('Hard', 'Hard'),
    )
    name = models.CharField(maxlength=120)
    ingredients = models.CharField(max_length=400)
    picture = models.FileField()
    difficulty = models.CharField(choices=DIFFICULTY_LEVELS, max_length=10)
    prep_time = models.PositiveIntegerField()
    prep_guide = models.TextField()

    def __str_(self):
        return "Recipe for {}".format(self.name)

The code snippet above describes six properties on the Recipe model:

Creating serializers for the Recipe model

We need serializers to convert model instances to JSON so that the frontend can easily work with the received data. We will create a core/serializers.py file and update it with the following:

# core/serializers.py

from rest_framework import serializers
from .models import Recipe 
class RecipeSerializer(serializers.ModelSerializer):

    class Meta:
        model = Recipe
        fields = ("id", "name", "ingredients", "picture", "difficulty", "prep_time", "prep_guide")

In the code snippet above, we specified the model to work with and the fields we want to be converted to JSON.

Setup the Admin panel

Django provides us with an admin interface out of the box; the interface will make it easy to test CRUD operations on the Recipe model we just created, but first, we will do a little configuration.

Open the core/admin.py file and completely replace it with the snippet below:

# core/admin.py

from django.contrib import admin
from .models import Recipe  # add this
# Register your models here.

admin.site.register(Recipe) # add this

Creating the Views

Let’s create a RecipeViewSet class in the core/views.py file, completely replace it with the snippet below:

# core/views.py

from rest_framework import viewsets
from .serializers import RecipeSerializer
from .models import Recipe

class RecipeViewSet(viewsets.ModelViewSet):
    serializer_class = RecipeSerializer
    queryset = Recipe.objects.all()

It is correct to say: Universal app = SSR + SPA.### Setting up the URLs

Head over to the api/urls.py file and completely replace it with the code below. This code specifies the URL path for the API:

# api/urls.py
from django.contrib import admin
from django.urls import path, include        # add this
from django.conf import settings             # add this
from django.conf.urls.static import static   # add this

urlpatterns = [
    path('admin/', admin.site.urls),
    path("api/", include('core.urls'))       # add this
]

# add this
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Now create a urls.py file in the core directory and paste in the snippet below:

# core/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import RecipeViewSet

router = DefaultRouter()
router.register(r'recipes', RecipeViewSet)

urlpatterns = [
    path("", include(router.urls))
]

In the code above, the router class generates the following URL patterns:

Running Migrations

Because we recently created a Recipe model and defined its structure, we need to make a Migration file and apply the changes on the model to the database, so let’s run the following commands:

(recipes_app) $ python manage.py makemigrations
(recipes_app) $ python manage.py migrate

Now, we will create a superuser account to access the admin interface:

(recipes_app) $ python manage.py createsuperuser

It is correct to say: Universal app = SSR + SPA.
Hooray! That’s all the configuration that needs to be done on the backend. We can now test the APIs we created, so let’s start the Django server:

(recipes_app) $ python manage.py runserver

Once the server is running, head over to http://localhost:8000/api/recipes/ to ensure it works:

We can create a new Recipe item using the interface:

We can also perform DELETE, PUT, and PATCH operations on specific Recipe items using their id primary keys. To do this, we will visit an address with this structure /api/recipe/{id}. Let’s try with this address — http://localhost:8000/api/recipes/1:

That’s all for the backend of the application, now we can move on to fleshing out the frontend.

Setting up the frontend

In this section of the tutorial, we will build the front-end of the application. We want to place the folder for the front-end code in the root of the recipes_app directory. So, navigate out of the api directory (or spin up a fresh terminal to run alongside the previous one) before running the commands in this section.

Let’s create a nuxt application called client with this command:

$ npx create-nuxt-app client

It is correct to say: Universal app = SSR + SPA.
Once the installation is complete, create-nuxt-app will ask a few questions about extra tools to be added. We will answer them as follows:

This will trigger the installation of dependencies using the selected package manager and finally, you will be presented with a screen like this:

Let’s run the following commands to start the application in development mode:

$ cd client
$ npm run dev

Once the development server has started, head over to http://localhost:3000 to see the application:

Awesome! Now let’s take a look at the directory structure of the client folder:

├── client
  ├── assets/
  ├── components/
  ├── layouts/
  ├── middleware/
  ├── node_modules/
  ├── pages/
  ├── plugins/
  ├── static/
  └── store/

Here’s a breakdown of what these directories are for:

There is also a nuxt.config.js file in the client folder, this file contains custom configuration for the Nuxt.js app. Before we continue, download this zip file, extract it and put the images/ folder inside the static/ directory.

Structure of the pages

Remember how we said that Nuxt.js reads all the .vue files in the pages/ directory and uses the information to create the application’s router? In this section, we will add some .vue files to the pages/ directory so that our application will have five pages as so:

Let’s add the following .vue files and folders to the pages/ directory so we have this exact structure:

├── pages/
   ├── recipes/
     ├── _id/
       └── edit.vue
       └── index.vue
     └── add.vue
     └── index.vue
  └── index.vue

The file structure above will generate the following routes:

It is correct to say: Universal app = SSR + SPA.### Creating the homepage

In Nuxt.js, Layouts are a great help when you want to change the look and feel of your application. Now, each instance of a Nuxt.js application ship with a default Layout, we want to remove all the styles so they do not interfere with our application.

Open the layouts/default.vue file and replace it with the following snippet below:

<template>
  <div>
    <nuxt/>
  </div>
</template>

<style>
</style>

Let’s update the pages/index.vue file with the code below:

<template>
  <header>
    <div class="text-box">
      <h1>La Recipes 😋</h1>
      <p class="mt-3">Recipes for the meals we love ❤️ ️</p>
      <nuxt-link class="btn btn-outline btn-large btn-info" to="/recipes">
        View Recipes <span class="ml-2">&rarr;</span>
      </nuxt-link>
    </div>
  </header>
</template>
<script>
export default {
  head() {
    return {
      title: "Home page"
    };
  },
};
</script>
<style>
header {
  min-height: 100vh;
  background-image: linear-gradient(
      to right,
      rgba(0, 0, 0, 0.9),
      rgba(0, 0, 0, 0.4)
    ),
    url("/images/banner.jpg");
  background-position: center;
  background-size: cover;
  position: relative;
}
.text-box {
  position: absolute;
  top: 50%;
  left: 10%;
  transform: translateY(-50%);
  color: #fff;
}
.text-box h1 {
  font-family: cursive;
  font-size: 5rem;
}
.text-box p {
  font-size: 2rem;
  font-weight: lighter;
}
</style>

From the code above, <nuxt-link> is a Nuxt.js component which can be used to navigate between pages. It is very similar to the <router-link> component from Vue Router.

Let’s start the front-end development server (if it isn’t already running), visit http://localhost:3000/, and see what the Homepage looks like:

npm run dev

It is correct to say: Universal app = SSR + SPA.
Every page in this application will be a Vue Component and Nuxt.js provides special attributes and functions to make the development of applications seamless. You can find documentation on all these special attributes here.

For the sake of this tutorial, we will make use of two of these functions:

Creating the Recipes List page

Let’s create a Vue.js component called RecipeCard.vue in the components/ directory and update it with the snippet below:

<template>
  <div class="card recipe-card">
    <img :src="recipe.picture" class="card-img-top" >
    <div class="card-body">
      <h5 class="card-title">{{ recipe.name }}</h5>
      <p class="card-text">
        <strong>Ingredients:</strong> {{ recipe.ingredients }}
      </p>
      <div class="action-buttons">
        <nuxt-link :to="`/recipes/${recipe.id}/`" class="btn btn-sm btn-success"> View </nuxt-link>
        <nuxt-link :to="`/recipes/${recipe.id}/edit/`" class="btn btn-sm btn-primary"> Edit </nuxt-link>
        <button @click="onDelete(recipe.id)"  class="btn btn-sm btn-danger">Delete</button>
      </div>
    </div>
  </div>
</template>
<script>
export default {
    props: ["recipe", "onDelete"]
};
</script>
<style>
.recipe-card {
    box-shadow: 0 1rem 1.5rem rgba(0,0,0,.6);
}
</style>

The component above accepts two props:

  1. Python3.
  2. Pip.
  3. Npm.

Next, open the pages/recipes/index.vue and update it with the snippet below:

<template>
  <main class="container mt-5">
    <div class="row">
      <div class="col-12 text-right mb-4">
        <div class="d-flex justify-content-between">
          <h3>La Recipes</h3>
          <nuxt-link to="/recipes/add" class="btn btn-info">Add Recipe</nuxt-link>
        </div>
      </div>
      <template v-for="recipe in recipes">
        <div :key="recipe.id" class="col-lg-3 col-md-4 col-sm-6 mb-4">
          <recipe-card :onDelete="deleteRecipe" :recipe="recipe"></recipe-card>
        </div>
      </template>
    </div>
  </main>
</template>
<script>
import RecipeCard from "~/components/RecipeCard.vue";

const sampleData = [
  {
    id: 1,
    name: "Jollof Rice",
    picture: "/images/food-1.jpeg",
    ingredients: "Beef, Tomato, Spinach",
    difficulty: "easy",
    prep_time: 15,
    prep_guide:
      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis, porro. Dignissimos ducimus ratione totam fugit officiis blanditiis exercitationem, nisi vero architecto quibusdam impedit, earum "
  },
  {
    id: 2,
    name: "Macaroni",
    picture: "/images/food-2.jpeg",
    ingredients: "Beef, Tomato, Spinach",
    difficulty: "easy",
    prep_time: 15,
    prep_guide:
      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis, porro. Dignissimos ducimus ratione totam fugit officiis blanditiis exercitationem, nisi vero architecto quibusdam impedit, earum "
  },
  {
    id: 3,
    name: "Fried Rice",
    picture: "/images/banner.jpg",
    ingredients: "Beef, Tomato, Spinach",
    difficulty: "easy",
    prep_time: 15,
    prep_guide:
      "Lorem ipsum dolor sit amet consectetur adipisicing elit. Omnis, porro. Dignissimos ducimus ratione totam fugit officiis blanditiis exercitationem, nisi vero architecto quibusdam impedit, earum "
  }
];

export default {
  head() {
    return {
      title: "Recipes list"
    };
  },
  components: {
    RecipeCard
  },
  asyncData(context) {
    let data = sampleData;
    return {
      recipes: data
    };
  },
  data() {
    return {
      recipes: []
    };
  },
  methods: {
    deleteRecipe(recipe_id) {
      console.log(deleted `${recipe.id}`) 
    }
  }
};
</script>
<style scoped>
</style>

Let’s start the front-end development server (if it isn’t already running), visit http://localhost:3000/recipes, and see this recipes listing page:

npm run dev

From the image above, we see that three recipe cards appear even though we set recipes to an empty array in the component’s data section. The explanation for this is that the method asyncData is executed before the page loads and it returns an object which updates the component’s data.

Now, all we need to do is modify the asyncData method to make an api request to the Django backend and update the component’s data with the result.

Before we do that, we have to install and configure Axios:

npm install -s @nuxtjs/axios

Once Axios is installed, open the nuxt.config.js file and update it accordingly:

// client/nuxt.config.js

  /_
  ** Nuxt.js modules
  _/
  modules: [,
    // Doc: https://bootstrap-vue.js.org/docs/
    'bootstrap-vue/nuxt',
    '@nuxtjs/axios' // add this
  ],

  // add this Axios object
  axios: {
    baseURL: "http://localhost:8000/api"
  },

Now, open the pages/recipes/index.vue file and replace the <script> section with the one below:

[...]

<script>
import RecipeCard from "~/components/RecipeCard.vue";

export default {
  head() {
    return {
      title: "Recipes list"
    };
  },
  components: {
    RecipeCard
  },
  async asyncData({ $axios, params }) {
    try {
      let recipes = await $axios.$get(`/recipes/`);
      return { recipes };
    } catch (e) {
      return { recipes: [] };
    }
  },
  data() {
    return {
      recipes: []
    };
  },
  methods: {
    async deleteRecipe(recipe_id) {
      try {
        await this.$axios.$delete(`/recipes/${recipe_id}/`); // delete recipe
        let newRecipes = await this.$axios.$get("/recipes/"); // get new list of recipes
        this.recipes = newRecipes; // update list of recipes
      } catch (e) {
        console.log(e);
      }
    }
  }
};
</script>

[...]

In the code above, asyncData()receives an object called context, which we destructure to get $axios . You can check out all the attributes of context here.

It is correct to say: Universal app = SSR + SPA.
This line of code — let recipes = await $axios.$get("/recipes/") — is a shorter version of:

let response = await $axios.get("/recipes")
let recipes = response.data

The deleteRecipe() method deletes a particular recipe, fetches the most recent list of recipes from the Django backend and finally updates the component’s data.

We can start the front-end development server (if it isn’t already running) now and we will see that the recipe cards are now being populated with data from the Django backend.

It is correct to say: Universal app = SSR + SPA.
Let’s visit http://localhost:3000/recipes, and take a peek:

npm run dev

You can also try deleting recipe items and watch them update accordingly.

Adding new Recipes

As we already discussed, we want to be able to add new recipes from the front-end of the application so open the pages/recipes/add/ file and update it with the following snippet:

<template>
  <main class="container my-5">
    <div class="row">
      <div class="col-12 text-center my-3">
        <h2 class="mb-3 display-4 text-uppercase">{{ recipe.name }}</h2>
      </div>
      <div class="col-md-6 mb-4">
        <img
          v-if="preview"
          class="img-fluid"
          style="width: 400px; border-radius: 10px; box-shadow: 0 1rem 1rem rgba(0,0,0,.7);"
          :src="preview"
          alt
        >
        <img
          v-else
          class="img-fluid"
          style="width: 400px; border-radius: 10px; box-shadow: 0 1rem 1rem rgba(0,0,0,.7);"
          src="@/static/images/placeholder.png"
        >
      </div>
      <div class="col-md-4">
        <form @submit.prevent="submitRecipe">
          <div class="form-group">
            <label for>Recipe Name</label>
            <input type="text" class="form-control" v-model="recipe.name">
          </div>
          <div class="form-group">
            <label for>Ingredients</label>
            <input v-model="recipe.ingredients" type="text" class="form-control">
          </div>
          <div class="form-group">
            <label for>Food picture</label>
            <input type="file" name="file" @change="onFileChange">
          </div>
          <div class="row">
            <div class="col-md-6">
              <div class="form-group">
                <label for>Difficulty</label>
                <select v-model="recipe.difficulty" class="form-control">
                  <option value="Easy">Easy</option>
                  <option value="Medium">Medium</option>
                  <option value="Hard">Hard</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group">
                <label for>
                  Prep time
                  <small>(minutes)</small>
                </label>
                <input v-model="recipe.prep_time" type="number" class="form-control">
              </div>
            </div>
          </div>
          <div class="form-group mb-3">
            <label for>Preparation guide</label>
            <textarea v-model="recipe.prep_guide" class="form-control" rows="8"></textarea>
          </div>
          <button type="submit" class="btn btn-primary">Submit</button>
        </form>
      </div>
    </div>
  </main>
</template>
<script>
export default {
  head() {
    return {
      title: "Add Recipe"
    };
  },
  data() {
    return {
      recipe: {
        name: "",
        picture: "",
        ingredients: "",
        difficulty: "",
        prep_time: null,
        prep_guide: ""
      },
      preview: ""
    };
  },
  methods: {
    onFileChange(e) {
      let files = e.target.files || e.dataTransfer.files;
      if (!files.length) {
        return;
      }
      this.recipe.picture = files[0];
      this.createImage(files[0]);
    },
    createImage(file) {
      // let image = new Image();
      let reader = new FileReader();
      let vm = this;
      reader.onload = e => {
        vm.preview = e.target.result;
      };
      reader.readAsDataURL(file);
    },
    async submitRecipe() {
      const config = {
        headers: { "content-type": "multipart/form-data" }
      };
      let formData = new FormData();
      for (let data in this.recipe) {
        formData.append(data, this.recipe[data]);
      }
      try {
        let response = await this.$axios.$post("/recipes/", formData, config);
        this.$router.push("/recipes/");
      } catch (e) {
        console.log(e);
      }
    }
  }
};
</script>
<style scoped>
</style>

In submitRecipe(), once the form data has been posted and the recipe is created successfully, the app is redirected to /recipes/ using this.$router.

Create the Single Recipe View page

Let’s create the view that allows a user to view a single Recipe item, open the /pages/recipes/_id/index.vue file and paste in the snippet below:

<template>
  <main class="container my-5">
    <div class="row">
      <div class="col-12 text-center my-3">
        <h2 class="mb-3 display-4 text-uppercase">{{ recipe.name }}</h2>
      </div>
      <div class="col-md-6 mb-4">
        <img
          class="img-fluid"
          style="width: 400px; border-radius: 10px; box-shadow: 0 1rem 1rem rgba(0,0,0,.7);"
          :src="recipe.picture"
          alt
        >
      </div>
      <div class="col-md-6">
        <div class="recipe-details">
          <h4>Ingredients</h4>
          <p>{{ recipe.ingredients }}</p>
          <h4>Preparation time ⏱</h4>
          <p>{{ recipe.prep_time }} mins</p>
          <h4>Difficulty</h4>
          <p>{{ recipe.difficulty }}</p>
          <h4>Preparation guide</h4>
          <textarea class="form-control" rows="10" v-html="recipe.prep_guide" disabled />
        </div>
      </div>
    </div>
  </main>
</template>
<script>
export default {
  head() {
    return {
      title: "View Recipe"
    };
  },
  async asyncData({ $axios, params }) {
    try {
      let recipe = await $axios.$get(`/recipes/${params.id}`);
      return { recipe };
    } catch (e) {
      return { recipe: [] };
    }
  },
  data() {
    return {
      recipe: {
        name: "",
        picture: "",
        ingredients: "",
        difficulty: "",
        prep_time: null,
        prep_guide: ""
      }
    };
  }
};
</script>
<style scoped>
</style>

The code here is pretty straight forward. The new thing we introduce here is the params key seen in the asyncData() method. In this case we are using params to get the ID of the recipe we want to view. We extract params from the URL and prefetch its data before displaying it on the page.

We can view a single Recipe item on the web browser now and see a similar screen:

Create the Single Recipe Edit Page

We need to create the view that allows the user to edit and update a single Recipe item, so open the /pages/recipes/_id/edit.vue file and paste in the snippet below:

<template>
  <main class="container my-5">
    <div class="row">
      <div class="col-12 text-center my-3">
        <h2 class="mb-3 display-4 text-uppercase">{{ recipe.name }}</h2>
      </div>
      <div class="col-md-6 mb-4">
        <img v-if="!preview" class="img-fluid" style="width: 400px; border-radius: 10px; box-shadow: 0 1rem 1rem rgba(0,0,0,.7);"  :src="recipe.picture">
        <img v-else class="img-fluid" style="width: 400px; border-radius: 10px; box-shadow: 0 1rem 1rem rgba(0,0,0,.7);"  :src="preview">
      </div>
      <div class="col-md-4">
        <form @submit.prevent="submitRecipe">
          <div class="form-group">
            <label for>Recipe Name</label>
            <input type="text" class="form-control" v-model="recipe.name" >
          </div>
          <div class="form-group">
            <label for>Ingredients</label>
            <input type="text" v-model="recipe.ingredients" class="form-control" name="Ingredients" >
          </div>
          <div class="form-group">
            <label for>Food picture</label>
            <input type="file" @change="onFileChange">
          </div>
          <div class="row">
            <div class="col-md-6">
              <div class="form-group">
                <label for>Difficulty</label>
                <select v-model="recipe.difficulty" class="form-control" >
                  <option value="Easy">Easy</option>
                  <option value="Medium">Medium</option>
                  <option value="Hard">Hard</option>
                </select>
              </div>
            </div>
            <div class="col-md-6">
              <div class="form-group">
                <label for>
                  Prep time
                  <small>(minutes)</small>
                </label>
                <input type="text" v-model="recipe.prep_time" class="form-control" name="Ingredients" >
              </div>
            </div>
          </div>
          <div class="form-group mb-3">
            <label for>Preparation guide</label>
            <textarea v-model="recipe.prep_guide" class="form-control" rows="8"></textarea>
          </div>
          <button type="submit" class="btn btn-success">Save</button>
        </form>
      </div>
    </div>
  </main>
</template>
<script>
export default {
  head(){
      return {
        title: "Edit Recipe"
      }
    },
  async asyncData({ $axios, params }) {
    try {
      let recipe = await $axios.$get(`/recipes/${params.id}`);
      return { recipe };
    } catch (e) {
      return { recipe: [] };
    }
  },
  data() {
    return {
      recipe: {
        name: "",
        picture: "",
        ingredients: "",
        difficulty: "",
        prep_time: null,
        prep_guide: ""
      },
      preview: ""
    };
  },
  methods: {
    onFileChange(e) {
      let files = e.target.files || e.dataTransfer.files;
      if (!files.length) {
        return;
      }
      this.recipe.picture = files[0]
      this.createImage(files[0]);
    },
    createImage(file) {
      let reader = new FileReader();
      let vm = this;
      reader.onload = e => {
        vm.preview = e.target.result;
      };
      reader.readAsDataURL(file);
    },
    async submitRecipe() {
      let editedRecipe = this.recipe
      if (editedRecipe.picture.indexOf("http://") != -1){
        delete editedRecipe["picture"]
      }
      const config = {
        headers: { "content-type": "multipart/form-data" }
      };
      let formData = new FormData();
      for (let data in editedRecipe) {
        formData.append(data, editedRecipe[data]);
      }
      try {
        let response = await this.$axios.$patch(`/recipes/${editedRecipe.id}/`, formData, config);
        this.$router.push("/recipes/");
      } catch (e) {
        console.log(e);
      }
    }
  }
};
</script>

<style>
</style>

In the code above, the submitRecipe() method has a conditional statement whose purpose is to remove the picture of an edited Recipe item from the data to be submitted if the picture was not changed.

Once the Recipe item has been updated, the application is redirected to the Recipes list page — /recipes/.

Setting up Transitions

Congratulations for making it this far! The application is fully functional and that’s great, however, we can give it a smoother look by adding transitions.

It is correct to say: Universal app = SSR + SPA.
We will set up transitions in the nuxt.config.js file. By default, the transition name is set to page, which simply means that the transitions we define will be active on all pages.

Let’s include the styling for the transition. Create a folder called css/ in the assets/ directory and add a transitions.css file within. Now open the transitions.css file and paste in the snippet below:

.page-enter-active,
.page-leave-active {
  transition: opacity .3s ease;
}
.page-enter,
.page-leave-to {
  opacity: 0;
}

Open the nuxt.config.js file and update it accordingly to load the CSS file we just created:

// nuxt.config.js

module.exports = {   /_
  ** Global CSS
  _/
  css: ['~/assets/css/transitions.css'], // update this
}

Voila! See how easy it is to add transitions to the application? Now our application will change frames on each navigation in a sleek way 😋:

Conclusion

In this article, we started out by learning the differences between Client-Side and Server-Side rendered applications. We went on to learn what a Universal application is and finally, we saw how to build a Universal application using Nuxt.js and Django.

The source code for this tutorial is available here on GitHub.

Learn More

10 Node Frameworks to Use in 2019

Machine Learning In Node.js With TensorFlow.js

Full Stack Developers: Everything You Need to Know

Building a mobile chat app with Nest.js and Ionic 4

Python Tutorial for Beginners (2019) - Learn Python for Machine Learning and Web Development

How To Set Up Django with Postgres, Nginx, and Gunicorn on Ubuntu 16.04

Python and Django Full Stack Web Developer Bootcamp

Django 2.1 & Python | The Ultimate Web Development Bootcamp

Python Django Dev To Deployment

Build a Backend REST API with Python & Django - Advanced

#django #nuxt-js #vue-js #python #web-development

Aria Barnes

Aria Barnes

1625232484

Why is Vue JS the most Preferred Choice for Responsive Web Application Development?

For more than two decades, JavaScript has facilitated businesses to develop responsive web applications for their customers. Used both client and server-side, JavaScript enables you to bring dynamics to pages through expanded functionality and real-time modifications.

Did you know!

According to a web development survey 2020, JavaScript is the most used language for the 8th year, with 67.7% of people choosing it. With this came up several javascript frameworks for frontend, backend development, or even testing.

And one such framework is Vue.Js. It is used to build simple projects and can also be advanced to create sophisticated apps using state-of-the-art tools. Beyond that, some other solid reasons give Vuejs a thumbs up for responsive web application development.

Want to know them? Then follow this blog until the end. Through this article, I will describe all the reasons and benefits of Vue js development. So, stay tuned.

Vue.Js - A Brief Introduction

Released in the year 2014 for public use, Vue.Js is an open-source JavaScript framework used to create UIs and single-page applications. It has over 77.4 million likes on Github for creating intuitive web interfaces.

The recent version is Vue.js 2.6, and is the second most preferred framework according to Stack Overflow Developer Survey 2019.

Every Vue.js development company is widely using the framework across the world for responsive web application development. It is centered around the view layer, provides a lot of functionality for the view layer, and builds single-page web applications.

Some most astonishing stats about Vue.Js:

• Vue was ranked #2 in the Front End JavaScript Framework rankings in the State of JS 2019 survey by developers.

• Approximately 427k to 693k sites are built with Vue js, according to Wappalyzer and BuiltWith statistics of June 2020.

• According to the State of JS 2019 survey, 40.5% of JavaScript developers are currently using Vue, while 34.5% have shown keen interest in using it in the future.

• In Stack Overflow's Developer Survey 2020, Vue was ranked the 3rd most popular front-end JavaScript framework.

Why is Vue.Js so popular?

• High-speed run-time performance
• Vue.Js uses a virtual DOM.
• The main focus is on the core library, while the collaborating libraries handle other features such as global state management and routing.
• Vue.JS provides responsive visual components.

Top 7 Reasons to Choose Vue JS for Web Application Development

Vue js development has certain benefits, which will encourage you to use it in your projects. For example, Vue.js is similar to Angular and React in many aspects, and it continues to enjoy increasing popularity compared to other frameworks.

The framework is only 20 kilobytes in size, making it easy for you to download files instantly. Vue.js easily beats other frameworks when it comes to loading times and usage.

Take a look at the compelling advantages of using Vue.Js for web app development.

#1 Simple Integration

Vue.Js is popular because it allows you to integrate Vue.js into other frameworks such as React, enabling you to customize the project as per your needs and requirements.

It helps you build apps with Vue.js from scratch and introduce Vue.js elements into their existing apps. Due to its ease of integration, Vue.js is becoming a popular choice for web development as it can be used with various existing web applications.

You can feel free to include Vue.js CDN and start using it. Most third-party Vue components and libraries are additionally accessible and supported with the Vue.js CDN.

You don't need to set up node and npm to start using Vue.js. This implies that it helps develop new web applications, just like modifying previous applications.

The diversity of components allows you to create different types of web applications and replace existing frameworks. In addition, you can also choose to hire Vue js developers to use the technology to experiment with many other JavaScript applications.

#2 Easy to Understand

One of the main reasons for the growing popularity of Vue.Js is that the framework is straightforward to understand for individuals. This means that you can easily add Vue.Js to your web projects.

Also, Vue.Js has a well-defined architecture for storing your data with life-cycle and custom methods. Vue.Js also provides additional features such as watchers, directives, and computed properties, making it extremely easy to build modern apps and web applications with ease.

Another significant advantage of using the Vue.Js framework is that it makes it easy to build small and large-scale web applications in the shortest amount of time.

#3 Well-defined Ecosystem

The VueJS ecosystem is vibrant and well-defined, allowing Vue.Js development company to switch users to VueJS over other frameworks for web app development.

Without spending hours, you can easily find solutions to your problems. Furthermore, VueJs lets you choose only the building blocks you need.

Although the main focus of Vue is the view layer, with the help of Vue Router, Vue Test Utils, Vuex, and Vue CLI, you can find solutions and recommendations for frequently occurring problems.

The problems fall into these categories, and hence it becomes easy for programmers to get started with coding right away and not waste time figuring out how to use these tools.

The Vue ecosystem is easy to customize and scales between a library and a framework. Compared to other frameworks, its development speed is excellent, and it can also integrate different projects. This is the reason why most website development companies also prefer the Vue.Js ecosystem over others.

#4 Flexibility

Another benefit of going with Vue.Js for web app development needs is flexibility. Vue.Js provides an excellent level of flexibility. And makes it easier for web app development companies to write their templates in HTML, JavaScript, or pure JavaScript using virtual nodes.

Another significant benefit of using Vue.Js is that it makes it easier for developers to work with tools like templating engines, CSS preprocessors, and type checking tools like TypeScript.

#5 Two-Way Communication

Vue.Js is an excellent option for you because it encourages two-way communication. This has become possible with the MVVM architecture to handle HTML blocks. In this way, Vue.Js is very similar to Angular.Js, making it easier to handle HTML blocks as well.

With Vue.Js, two-way data binding is straightforward. This means that any changes made by the developer to the UI are passed to the data, and the changes made to the data are reflected in the UI.

This is also one reason why Vue.Js is also known as reactive because it can react to changes made to the data. This sets it apart from other libraries such as React.Js, which are designed to support only one-way communication.

#6 Detailed Documentation

One essential thing is well-defined documentation that helps you understand the required mechanism and build your application with ease. It shows all the options offered by the framework and related best practice examples.

Vue has excellent docs, and its API references are one of the best in the industry. They are well written, clear, and accessible in dealing with everything you need to know to build a Vue application.

Besides, the documentation at Vue.js is constantly improved and updated. It also includes a simple introductory guide and an excellent overview of the API. Perhaps, this is one of the most detailed documentation available for this type of language.

#7 Large Community Support

Support for the platform is impressive. In 2018, support continued to impress as every question was answered diligently. Over 6,200 problems were solved with an average resolution time of just six hours.

To support the community, there are frequent release cycles of updated information. Furthermore, the community continues to grow and develop with backend support from developers.



Wrapping Up

VueJS is an incredible choice for responsive web app development. Since it is lightweight and user-friendly, it builds a fast and integrated web application. The capabilities and potential of VueJS for web app development are extensive.

While Vuejs is simple to get started with, using it to build scalable web apps requires professionalism. Hence, you can approach a top Vue js development company in India to develop high-performing web apps.

Equipped with all the above features, it doesn't matter whether you want to build a small concept app or a full-fledged web app; Vue.Js is the most performant you can rely on.

Original source

 

#vue js development company #vue js development company in india #vue js development company india #vue js development services #vue js development #vue js development companies