Building a dynamic web app with Vuejs framework Nuxtjs + Express — Part1: Getting Started

Ly Channa
6 min readMar 9, 2020

--

Building a non-refresh web app with a desktop-like experience is not that hard, you just need a right tool.

Introduction

Vuejs is a great javascript framework, but building a full functionality web app is not easy. It lacks an architectural structure and its router generates a lot of boilerplate code. This is how Nuxtjs comes into play. NuxtJs is an easy to learn, progressive and high-performance framework that can be used for:

  • Static content webpages: Create static pages easily. Share partials, footers, headers, and sidebars like a pro.
  • Server-side rendering: Render your content on the server-side, SEO friendly, encapsulate business logic on the server-side.
  • Single page application: Build a next-generation web application without page refreshing.

Installation

Nuxtjs installation page gives pretty well and details step by step to do this.

yarn create nuxt-app nuxtavocado

From the above options I chose: Yarn as package manager, Ant Design Vue as UI framework, Express as web server framework, axios + pwa + dotenv as nuxtjs modules and jest as test framework. You might choose the same to follow along this blog. When we get deeper I will also show alot of automate testing with jest from what I observe testing in nodejs app are rare and very basic, hopefully this blog will be a cornerstone for you to see the importance of unit test, integration test and lead to a agile development with nodejs particulary Express and Jest.

Then

cd nuxtavocado
yarn dev
Error: listen EADDRINUSE: address already in use 127.0.0.1:3000
at Server.setupListenHandle [as _listen2] (net.js:1309:16)
at listenInCluster (net.js:1357:12)
at GetAddrInfoReqWrap.doListen [as callback] (net.js:1496:7)
at GetAddrInfoReqWrap.onlookup [as oncomplete] (dns.js:69:10)
Emitted 'error' event on Server instance at:
at emitErrorNT (net.js:1336:8)
at processTicksAndRejections (internal/process/task_queues.js:84:21) {
code: 'EADDRINUSE',
errno: -48,
syscall: 'listen',
address: '127.0.0.1',
port: 3000
}
[nodemon] app crashed - waiting for file changes before starting...

Because Nuxtjs use port 3000 by default, I have rails app server running on port 3000, This causes Nuxtjs failed to start.

Now let’s starts to change the default port of Nuxtjs to 8000 for now

// nuxtjs.config.jsmodule.exports = {
mode: 'universal',
/*
** Customer server config
*/
server: {
port: 8000
},

Let’s try to run again

> yarn dev
. . .
READY Server listening on http://localhost:8000

Separate configurations from code

// .env
SERVER_PORT=8080

in nuxtjs.config.js

require('dotenv').config()module.exports = {
mode: 'universal',
// srcDir: 'src',
// buildDir: 'functions/.nuxt',
server: {
port: process.env.PORT || 8000
},

Now go ahead restart the server in the terminal

yarn dev...
ℹ Waiting for file changes 12:36:10
READY Server listening on http://localhost:8080
git init .
git add .
git commit -m 'Finish the installation'
git remote add origin my_git_repo_address
git push origin master

Create a layout and Page

Common stylesheets for every page

under /assets create a folder stylesheets

/assets/stylesheets/main/reset.css
/assets/stylesheets/main/layout.css
/assets/stylesheets/main/animate.css

with the following content

/assets/stylesheets/main/reset.css

html, body, * {
padding: 0px;
margin: 0px;
}

/# /assets/stylesheets/main/layout.cs

.container {
min-height: 600px;
}

/assets/stylesheets/main/animate.css

.page-enter-active, .page-leave-active {
transition: opacity .5s;
}
.page-enter, .page-leave-to {
opacity: 0;
}
.animate-logo {
animation: 3s appear;
margin: auto;
}
@keyframes appear {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}

Now create a plugin under the /plugins/ folder

// plugins/main-style.jsimport '~/assets/stylesheets/main/animate.css'
import '~/assets/stylesheets/main/reset.css'
import '~/assets/stylesheets/main/layout.css'

Now register the main-style.js plugin in the nuxt.config.js

...
plugins: [
'@/plugins/antd-ui',
'@/plugins/main-style'
],

Create our own logo

Copy your logo to assets/images/logo.png

under components open Logo.vue and modify with the following content

<template>
<nuxt-link to="/" class="animate-logo" style="border-radius: 6px;">
<img src="~/assets/images/logo.png" height="32">
</nuxt-link>
</template>

Modify our home page

Open to edit pages/index.vue

<template>
<div class="container">
Home
</div>
</template><script>
export default {
layout: 'default'
}
</script>

Modify the default layout

Open layouts/default.vue

<template>
<a-layout id="components-layout-demo-top-side">
<bmb-header />
<a-layout-content>
<nuxt />
</a-layout-content>
<a-layout-footer style="text-align: center">
Ant Design ©2018 Created by Ant UED
</a-layout-footer>
</a-layout>
</template>
<script>
import BmbHeader from '@/components/Header'
export default {
components: {
BmbHeader
}
}
</script>

Create our first component for Header in components/Header.vue

<template>
<a-layout-header class="manu-header" :style="{ position: 'fixed', zIndex: 1, width: '100%', background: '#fff' }">
<div class="menu-left">
<logo class="logo" />
<a-menu
theme="light"
mode="horizontal"
:style="{ lineHeight: '64px' }"
>
<a-menu-item key="1">
Item
</a-menu-item>
</a-menu>
</div>
<div>
<nuxt-link to="/login">
<a-button type="" shape="round" icon="key">
Sign In
</a-button>
</nuxt-link>
<nuxt-link to="/registration">
<a-button type="primary" shape="round" icon="user">
Sign Up
</a-button>
</nuxt-link>
</div>
</a-layout-header>
</template>
<script>
import Logo from '@/components/Logo'
export default {
components: {
Logo
}
}
</script>
<style scoped>
.menu-left {
display: flex;
justify-content: flex-start
}
.manu-header{
justify-content: space-between;
display: flex;
}
.svg-inline--fa.fa-w-20{
width: 16px;
}
.svg-inline--fa fa-grin-hearts fa-w-16{
width: 16px
}
.svg-inline--fa.fa-w-16 {
width: 16px;
}
.ant-layout-header {
/* height: 64px;
padding: 0 50px;
line-height: 64px;
background: #001529; */
height: 64px;
background: white;
box-shadow: 0 2px 4px #ddd;
position: relative;
z-index: 10;
max-width: 100%;
}
</style>

Now let’s restart our server with yarn dev

Now let commit our changes

git add .
git commit -m 'Custom layout and page with ant design'
git push origin master

Now we have our Nuxtjs app with custom layout and page using Ant design UI for Vuejs.

Autocorrect ESLint error Config in Nuxtjs

You might have problems with ESLint raising errors. ESLint is a tool to help identify and report js style guide for a maintainable, high-quality code with ease. However, it might be a bit tricky when you first start using it or you are working with a long js file. If you happen to copy code around it will be overwhelming to fix the errors raise the ESLint. Luckily ESLint is very flexible because it can be set to autocorrect and format your code beautifully. So below is how to configure it in Nuxtjs app:

In nuxt.config.js

...
build: {
/*
** You can extend webpack config here
*/
extend (config, ctx) {
if ( !(ctx.isDev && ctx.isClient)) {
console.log('Not Lint custom');
return
}
console.log('Lint custom')
let rule = {
enforce: 'pre',
test: /\.(js|vue)$/,
loader: 'eslint-loader',
exclude: /(node_modules)/,
options: {
fix: true
}
}
config.module.rules.push(rule)
}

}

Now let’s start the server to apply config change.

Navigation Between Pages

We are going to create 2 pages for users to sign in and sign up.

pages/login.vue
pages/registration.vue

For pages/login.vue

<template>
<div>
<h1>
Login
</h1>
</div>
</template>

and pages/registration.vue

<template>
<div>
<h1>
Registration
</h1>
</div>
</template>

Now visit http://localhost:8080/registration

Let’s commit

git add .
git commit -m 'Add basic session pages'
git push origin master

Conclusion

Getting started with Nuxtjs is pretty easy and straightforward. Next, we will build a fully functional login page with the Express server-side framework communicating with an API server to handle the login to prove Nuxtjs for a dynamic web application. Next, I will show how to do authentication and unit test our logic with the jest framework.

--

--