Build A Vue Web App For Browsing, Searching And Viewing Catalyst

Build A Vue Web App For Browsing, Searching And Viewing Catalyst

This is the repo for Not-Equal Catalyst's frontend webapp. It is a Vue.js project written in JavaScript, pug and sass and deployed through Docker where it is served using express and vue-ssr.

Catalyst | Vue WebApp

This is the repo for Not-Equal Catalyst's frontend webapp. It is a Vue.js project written in JavaScript, pug and sass and deployed through Docker where it is served using express and vue-ssr.

What is Not-Equal Catalyst?

Table of Contents
  • Development
    • Setup
    • Regular use
    • Irregular use
    • Code Structure
    • Webpack build
    • Code formatting
  • Deployment
    • Building the image
    • Using the image
    • Environment variables
  • Future work
Development

Setup

To develop on this repo you will need to have Docker and node.js installed on your dev machine and have an understanding of them. This guide assumes you have the repo checked out and are on macOS, but equivalent commands are available. You will also need a Trello account which is used to pull the data from.

You'll only need to follow this setup once for your dev machine.

# Install dependancies
npm install

# Setup your client environment
cp .env.example .env.local

# Follow these instructions to get your Trello credentials
open https://github.com/unplatform/catalyst-trello-scraper#setup

# Setup your server environment
cp .env.server.example .env.server.local

Regular use

These are the commands you'll regularly run to develop the API, in no particular order.

# Start up a redis instance, fetch projects and serve them with the api
# -> Run this in a new terminal tab
# -> Stop this with a Ctrl+C
# -> See `docker-compose.yml` for how it works
docker-compuse up

# Compile and run the vue-cli-service's server
# -> Internally uses webpack to transpile assets to html, css & js
# -> Stop this with a Ctrl+C
# -> Only runs the client, no ssr yet
npm run serve
open http://localhost:8080

Irregular use

These are commands you might need to run but probably won't, also in no particular order.

# Generate the table of contents for this readme
# -> It'll replace content between the toc-head and toc-tail HTML comments
npm run gen-readme-toc

# Manually lint code with TypeScript's `tsc`
npm run lint

# Manually format code
# -> This repo is setup to automatically format code on git-push
npm run prettier

# Manually build all assets (html, css, js & images)
# -> Runs both the other build commands together
# -> Writes to dist/
npm run build

# Manually build the assets for the client
npm run build:client

# Manually build the assets for the server (creates a vue-ssr-server-bundle-json)
npm run build:client

# Run the ssr server
# -> Requires .env.server.local to be setup
# -> Stop this with a Ctrl+C
# -> Just runs the server, no file watching or restarting
node server/index.js

Code Structure

Folder Contents
dist Where the html, css, js & img assets are built to
node_modules Where npm's modules get installed into
public Unmodified assets, served directly to the client
server The source code for the vue-ssr express server
src The source code for the web app
src/assets Image assets that are built into the app
src/components Reusable Vue components
src/data Static information for the web app
src/sass Custom styles written in sass
src/views The app's views, components which are routed to

Webpack build

This repo uses vue-cli-service to handle most webpack configuration, including babel, post-css and processing .vue components. There are some tweaks to the defaults, these can be found in vue.config.js and are detailed below.

  • shared.sass is automatically imported for each Vue component's <style> tags (with variables and mixins)
  • process.env.VUE_APP_VERSION is set to the package.json version
  • It adds vue-svg-loader
  • It sets up the required things for vue-ssr

Code formatting

This repo uses Prettier to automatically format code to a consistent standard. This works using the husky and lint-staged packages to automatically format code whenever you commit code. This means that code that is pushed to the repo is always formatted to a consistent standard.

You can manually run the formatter with npm run prettier if you want.

Prettier is slightly configured in .prettierrc.yml and also ignores files using .prettierignore.

Deployment

Building the image

This repo uses a GitLab CI to build a Docker image when you push a git tag. This is designed to be used with the npm version command so all docker images are semantically versioned. The :latest docker tag is not used.

This job runs using the .gitlab-ci.yml file which runs a docker build using the Dockerfile and only runs when you push a tag.

It pushes these docker images to the GitLab registry of the repo. A slight nuance is that it will replace a preceding v in tag names, formatting v1.0.0 to 1.0.0.

# Deploy a new version of the CLI
npm version # major | minor | patch
git push --tags
open https://openlab.ncl.ac.uk/gitlab/catalyst/vue-webapp/pipelines

Using the image

With this docker image you can easily deploy and run the vue-ssr server using docker-compose. The express server runs on 8080 inside the container, so you'll need to map that for external traffic.

Here's an example with docker-compose:

For more info see catalyst-example-stack

version: '3'

services:
  web-ui:
    image: openlab.ncl.ac.uk:4567/catalyst/vue-webapp:0.1.0
    ports:
      - 8080:8080
    environment:
      PUBLIC_URL: https://catalyst.not-equal.tech
      API_URL: https://api.catalyst.not-equal.tech
      REDIS_URL: redis://your_redis_url

Environment variables

There are some required environment variables, shown below.

Variable Description
REDIS_URL The redis connection uri
PUBLIC_URL Where the app is, used for generating opengraph meta
API_URL Where the api is, passed into the webapp through vuex

There are some optional variables too:

Variable Description
APP_NAME Set the app's name, used in opengraph
APP_INFO Set the app's description, used in opengraph
TWITTER_HANDLE The twitter handle of the project (used in opengraph)

There are files you can override with bind-mounts

Path File
/app/public/favicon.png The site's favicon
/app/public/opengraph.png The site's opengraph image e.g. for tweets
/app/public/categories/* Custom category images

Trello key-values

Key Usage
home.title The title on the homepage, shown after the hero
home.strapline The strapline on the homepage, in the hero
home.searchLabel The label next to the search field
home.noMatches A label when filtering returns no responses
home.noResponses A label when there are no responses at all
about.title The title of the about page
about.subtitle The subtitle of the about page
about.long The content of the about page
about.short The info displayed next to a project detail
notFound.title The title of the not found page
notFound.message The message of the not found page
Future work
Demo Download

How use Vue’s composition API to build highly performant Web Apps

How use Vue’s composition API to build highly performant Web Apps

In this post, we’ll take a look at how the Vue’s composition API improves the way we write code and how we can use it to build highly performant web apps

Vue’s flexible and lightweight nature makes it really awesome for developers who quickly want to scaffold small and medium scale applications.

However, Vue’s current API has certain limitations when it comes to maintaining growing applications. This is because the API organizes code by component options ( Vue’s got a lot of them) instead of logical concerns.

As more component options are added and the codebase gets larger, developers could find themselves interacting with components created by other team members, and that’s where things start to get really confusing, it then becomes an issue for teams to improve or change components.

Fortunately, Vue addressed this in its latest release by rolling out the Composition API. From what I understand, it’s a function-based API that is meant to facilitate the composition of components and their maintenance as they get larger. In this blog post, we’ll take a look at how the composition API improves the way we write code and how we can use it to build highly performant web apps.

Improving code maintainability and component reuse patterns

Vue 2 had two major drawbacks. The first was difficulty maintaining large components.

Let’s say we have a component called App.vue in an application whose job is to handle payment for a variety of products called from an API. Our initial steps would be to list the appropriate data and functions to handle our component:

// App.vue

<script >
import PayButton from "./components/PayButton.vue";

const productKey = "778899";
const API = `https://awesomeproductresources.com/?productkey=${productKey}`;  // not real ;)

export default {
    name: "app",
    components: {
        PayButton
    },
    mounted() {
          fetch(API)
            .then(response => {
                this.productResponse = response.data.listings;
            })
            .catch(error => {
                console.log(error);
            });
    },
    data: function() {
        return {
            discount: discount,
            productResponse: [],
            email: "[email protected]",
            custom: {
                title: "Retail Shop",
                logo: "We are an awesome store!"
            }
        };
    },
   computed: {
    paymentReference() {
              let text = "";
              let possible =
                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
              for (let i = 0; i < 10; i++)
                text += possible.charAt(Math.floor(Math.random() * possible.length));
              return text;
          }
        }
      };
</script>

All App.vue does is retrieve data from an API and pass it into the data property while handling an imported component payButton. It doesn’t seem like much and we’ve used at least three component options – component, computed and data and the [mounted()](https://vuejs.org/v2/api/#mounted) lifecycle Hook.

In the future, we’ll probably want to add more features to this component. For example, some functionality that tells us if payment for a product was successful or not. To do that we’ll have to use the method component option.

Adding the method component option only makes the component get larger, more verbose, and less maintainable. Imagine that we had several components of an app written this way. It is definitely not the ideal kind of framework a developer would want to use.

Vue 3’s fix for this is a setup() method that enables us to use the composition syntax. Every piece of logic is defined as a composition function outside this method. Using the composition syntax, we would employ a separation of concerns approach and first isolate the logic that calls data from our API:

// productApi.js
<script>
import { reactive, watch } from '@vue/composition-api';

const productKey = "778899";

export const useProductApi = () => {
    const state = reactive({
        productResponse: [],
        email: "[email protected]",
        custom: {
            title: "Retail Shop",
            logo: "We are an awesome store!"
        }
    });

    watch(() => {
        const API = `https://awesomeproductresources.com/?productkey=${productKey}`;

        fetch(API)
            .then(response => response.json())
            .then(jsonResponse => {
                state.productResponse = jsonResponse.data.listings;
            })
            .catch(error => {
                console.log(error);
            });
    });

    return state;
};
</script>

Then when we need to call the API in App.vue, we’ll import useProductApi and define the rest of the component like this:

// App.vue

<script>
    import { useProductApi } from './ProductApi';
    import PayButton from "./components/PayButton.vue";

export default {
    name: 'app',
    components: {
        PayButton
    },

    setup() {
        const state = useProductApi();

        return {
            state
        }
    }
}

function paymentReference() {
    let text = "";
    let possible =
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
    for (let i = 0; i < 10; i++)
        text += possible.charAt(Math.floor(Math.random() * possible.length));
    return text;
}
</script>

It’s important to note that this doesn’t mean our app will have fewer components, we’re still going to have the same number of components – just that they’ll use fewer component options and be a bit more organized.

Vue 2‘s second drawback was an inefficient component reuse pattern.

The way to reuse functionality or logic in a Vue component is to put it in a mixin or scoped slot. Let’s say we still have to feed our app certain data that would be reused, to do that let’s create a mixin and insert this data:

<script>
    const storeOwnerMixin = {
        data() {
            return {
                name: 'RC Ugwu',
                subscription: 'Premium'
            }
        }
    }

export default {
    mixins: [storeOwnerMixin]
}
</script>

This is great for small scale applications. But like the first drawback, the entire project begins to get larger and we need to create more mixins to handle other kinds of data. We could run into a couple of issues such as name conflicts and implicit property additions. The composition API aims to solve all of this by letting us define whatever function we need in a separate JavaScript file:

// storeOwner.js

export default function storeOwner(name, subscription) {
    var object = {
        name: name,
        subscription: subscription
    };
    return object;
}

and then import it wherever we need it to be used like this:

<script>
   import storeOwner from './storeOwner.js'
   export default {
     name: 'app',
     setup() {
         const storeOwnerData = storeOwner('RC Ugwu', 'Premium');

         return {
             storeOwnerData
         }
     }
 }
 </script>

Clearly, we can see the edge this has over mixins. Aside from using less code, it also lets you express yourself more in plain JavaScript and your codebase is much more flexible as functions can be reused more efficiently.

Vue Composition API compared to React Hooks

Though Vue’s Composition API and React Hooks are both sets of functions used to handle state and reuse logic in components – they work in different ways. Vue’s setup function runs only once while creating a component while React Hooks can run multiple times during render. Also for handling state, React provides just one Hook – useState:

import React, { useState } from "react";
const [name, setName] = useState("Mary");
const [subscription, setSubscription] = useState("Premium");
console.log(`Hi ${name}, you are currently on our ${subscription} plan.`);

The composition API is quite different, it provides two functions for handling state – ref and reactive . ref returns an object whose inner value can be accessed by its value property:

const name = ref('RC Ugwu');
const subscription = ref('Premium');
watch(() => {
    console.log(`Hi ${name}, you are currently on our ${subscription} plan.`);
});

reactive is a bit different, it takes an object as its input and returns a reactive proxy of it:

const state = reactive({
    name: 'RC Ugwu',
    subscription: 'Premium',
});
  watch(() => {
console.log(`Hi ${state.name}, you are currently on our ${state.subscription} plan.`);
});

Vue’s Composition API is similar to React Hooks in a lot of ways although the latter obviously has more popularity and support in the community for now, it will be interesting to see if composition functions can catch up with Hooks. You may want to check out this detailed post by Guillermo Peralta Scura to find out more about how they both compare to each other.

Building applications with the Composition API

To see how the composition API can further be used, let’s create an image gallery out of pure composition functions. For data, we’ll use Unsplash’s API. You will want to sign up and get an API key to follow along with this. Our first step is to create a project folder using Vue’s CLI:

# install Vue's CLI
npm install -g @vue/cli

# create a project folder
vue create vue-image-app

#navigate to the newly created project folder
cd vue-image-app

#install aios for the purpose of handling the API call
npm install axios

#run the app in a developement environment
npm run serve

When our installation is complete, we should have a project folder similar to the one below:

Vue’s CLI still uses Vue 2, to use the composition API, we have to install it differently. In your terminal, navigate to your project folder’s directory and install Vue’s composition plugin:

npm install @vue/composition-api

After installation, we’ll import it in our main.js file:

import Vue from 'vue'
import App from './App.vue'
import VueCompositionApi from '@vue/composition-api';

Vue.use(VueCompositionApi);
Vue.config.productionTip = false
new Vue({
  render: h => h(App),
}).$mount('#app')

It’s important to note that for now, the composition API is just a different option for writing components and not an overhaul. We can still write our components using component options, mixins, and scoped slots just as we’ve always done.

Building our components

For this app, we’ll have three components:

  • App.vue : The parent component — it handles and collects data from both children components- Photo.vue and PhotoApi.js
  • PhotoApi.js: A functional component created solely for handling the API call
  • Photo.vue : The child component, it handles each photo retrieved from the API call

First, let’s get data from the Unsplash API. In your project’s src folder, create a folder functions and in it, create a PhotoApi.js file:

import { reactive } from "@vue/composition-api";
import axios from "axios";
export const usePhotoApi = () => {
  const state = reactive({
    info: null,
    loading: true,
    errored: false
  });
   const PHOTO_API_URL =
      "https://api.unsplash.com/photos/?client_id=d0ebc52e406b1ac89f78ab30e1f6112338d663ef349501d65fb2f380e4987e9e";
    axios
      .get(PHOTO_API_URL)
      .then(response => {
        state.info = response.data;
      })
      .catch(error => {
        console.log(error);
        state.errored = true;
      })
      .finally(() => (state.loading = false));
  return state;
};

In the code sample above, a new function was introduced from Vue’s composition API – reactive.

reactive is the long term replacement of Vue.observable() , it wraps an object and returns the directly accessible properties of that object.

Let’s go ahead and create the component that displays each photo. In your src/components folder, create a file and name it Photo.vue. In this file, input the code sample below:

<template>
  <div class="photo">
    <h2>{{ photo.user.name }}</h2>
    <div>
      <img width="200" :alt="altText" :src="photo.urls.regular" />
    </div>
    <p>{{ photo.user.bio }}</p>
  </div>
</template>
<script>
  import { computed } from '@vue/composition-api';
  export default {
    name: "Photo",
    props: ['photo'],
    setup({ photo }) {
      const altText = computed(() => `Hi, my name is ${photo.user.name}`);
      return { altText };
    }
  };
</script>
<style scoped>
p {
  color:#EDF2F4;
}
</style>

In the code sample above, the Photo component gets the photo of a user to be displayed and displays it alongside their bio. For our alt field, we use the setup() and computed functions to wrap and return the variable photo.user.name.

Finally, let’s create our App.vue component to handle both children components. In your project’s folder, navigate to App.vue and replace the code there with this:

<template>
  <div class="app">
    <div class="photos">
      <Photo v-for="photo in state.info" :photo="photo" :key="photo[0]" />
    </div>
  </div>
</template>
<script>
  import Photo from './components/Photo.vue';
  import { usePhotoApi } from './functions/photo-api';
  export default {
    name: 'app',
    components: { Photo },
    setup() {
      const state = usePhotoApi();
      return {
        state
      };
    }
  }
</script>

There, all App.vue does is use the Photo component to display each photo and set the state of the app to the state defined in PhotoApi.js.

Conclusion

It’s going to be interesting to see how the Composition API is received. One of its key advantages I’ve observed so far is its ability to separate concerns for each component – every component has just one function to carry out. This makes stuff very organized. Here are some of the functions we used in the article demo:

  • setup – this controls the logic of the component. It receives props and context as arguments
  • ref – it returns a reactive variable and triggers the re-render of the template on change. Its value can be changed by altering the value property
  • reactive – this returns a reactive object. It re-renders the template on reactive variable change. Unlike ref, its value can be changed without changing the value property

Have you found out other amazing ways to implement the Composition API? Do share them in the comments section below. You can check out the full implementation of the demo on CodeSandbox

10 Best Vue Icon Component For Your Vue.js App

10 Best Vue Icon Component For Your Vue.js App

In this article, I will collect 10 Vue icon component to bring more interactivity, better UI design to your Vue application.

Icons are the vital element of the user interface of the product enabling successful and effective interaction with it. In this article, I will collect 10 Vue icon component to bring more interactivity, better UI design to your Vue application.

1. Animated SweetAlert Icons for Vue

A clean and simple Vue wrapper for SweetAlert's fantastic status icons. This wrapper is intended for users who are interested in just the icons. For the standard SweetAlert modal with all of its bells and whistles, you should probably use Vue-SweetAlert 2

Demo: https://vue-sweetalert-icons.netlify.com/

Download: https://github.com/JorgenVatle/vue-sweetalert-icons/archive/master.zip

2. vue-svg-transition

Create 2-state, SVG-powered animated icons.

Demo: https://codesandbox.io/s/6v20q76xwr

Download: https://github.com/kai-oswald/vue-svg-transition/archive/master.zip

3. Vue-Awesome

Awesome SVG icon component for Vue.js, with built-in Font Awesome icons.

Demo: https://justineo.github.io/vue-awesome/demo/

Download: https://github.com/Justineo/vue-awesome/archive/master.zip

4. vue-transitioning-result-icon

Transitioning Result Icon for Vue.js

A scalable result icon (SVG) that transitions the state change, that is the SVG shape change is transitioned as well as the color. Demonstration can be found here.

A transitioning (color and SVG) result icon (error or success) for Vue.

Demo: https://transitioning-result-icon.dexmo-hq.com/

Download: https://github.com/dexmo007/vue-transitioning-result-icon/archive/master.zip

5. vue-zondicons

Easily add Zondicon icons to your vue web project.

Demo: http://www.zondicons.com/icons.html

Download: https://github.com/TerryMooreII/vue-zondicons/archive/master.zip

6. vicon

Vicon is an simple iconfont componenet for vue.

iconfont
iconfont is a Vector Icon Management & Communication Platform made by Alimama MUX.

Download: https://github.com/Lt0/vicon/archive/master.zip

7. vue-svgicon

A tool to create svg icon components. (vue 2.x)

Demo: https://mmf-fe.github.io/vue-svgicon/v3/

Download: https://github.com/MMF-FE/vue-svgicon/archive/master.zip

8. vue-material-design-icons

This library is a collection of Vue single-file components to render Material Design Icons, sourced from the MaterialDesign project. It also includes some CSS that helps make the scaling of the icons a little easier.

Demo: https://gitlab.com/robcresswell/vue-material-design-icons

Download: https://gitlab.com/robcresswell/vue-material-design-icons/tree/master

9. vue-ionicons

Vue Icon Set Components from Ionic Team

Design Icons, sourced from the Ionicons project.

Demo: https://mazipan.github.io/vue-ionicons/

Download: https://github.com/mazipan/vue-ionicons/archive/master.zip

10. vue-ico

Dead easy, Google Material Icons for Vue.

This package's aim is to get icons into your Vue.js project as quick as possible, at the cost of all the bells and whistles.

Demo: https://material.io/resources/icons/?style=baseline

Download: https://github.com/paulcollett/vue-ico/archive/master.zip

I hope you like them!

A Vue Forum App Build with Vue Frontend

A Vue Forum App Build with Vue Frontend

A fullstack application built with Vue on the frontend and Node/Express on the backend.

Vue Forum App — Frontend

A fullstack application built with Vue on the frontend and Node/Express on the backend.

Demo    Backend

This repo demonstrates almost everything you need to know to build a complete fullstack application using Vue and Node/Express. This demo covers things like:

  • Authentication/Authorization with JWT
  • Routing
  • Communicating with a backend API
  • Managing the state of the app with Vuex
  • Uploading Images
  • Forms Validation
  • Handling errors
  • Loading states
  • More stuff
Running the demo
  1. Install and run the backend project
  2. Download this repo
  3. Create .env in the root directory, and add:
VUE_APP_API_CLIENT='server'
VUE_APP_API_SERVER_BASE_URL='http://localhost:5000'

I'm here assuming that the backend will run on localhost:5000. If you set VUE_APP_API_CLIENT to mock, you'll use data from the mock store, which means you won't need the backend running.

  1. Run npm install
  2. Run npm run serve

To build it and run it in production mode:

  1. Run npm run build
  2. Run npm run start
Download