Ellis Herbert

Ellis Herbert


How to build a Single Page App using Go and Vue.js

Single-Page Applications (SPAs) improve user experience by offering rich UI interactions, fast feedback, and the relief of knowing you don’t need to download and install a traditional application. Browsers are now operating systems and websites are apps. While a SPA isn’t always the answer, for apps that rely on snappy user interaction they are increasingly common.

To the end user, a well-designed SPA feels like rainbows and unicorns. From the developer perspective, reality can be much the opposite. Tough problems long-since solved on the backend like authentication, routing, state management, data binding, and more become time-consuming frontend challenges. Luckily for us, JavaScript frameworks like Vue, React, and Angular exist to help us craft powerful applications and focus more of our time on critical functionality and not reinventing the wheel.

About Vue.js

Who better to describe Vue than its creator, Evan You?

Vue (pronounced /vjuː/, like view) is a progressive framework for building user interfaces. It is designed from the ground up to be incrementally adoptable, and can easily scale between a library and a framework depending on different use cases. It consists of an approachable core library that focuses on the view layer only, and an ecosystem of supporting libraries that helps you tackle complexity in large Single-Page Applications.

Here are some of Vue’s benefits:

  • A gentle learning curve and low barrier to entry
  • Provides the ability to bootstrap your app withvue-cli,saving you the hassle of setting up webpack and complex build pipelines
  • Explosive community growth! Vue now has more stars on GitHub than React and Angular
  • It’s flexible enough to adopt at a reasonable pace, component by component

Create Your Vue + Go App

In this tutorial, you will create a single-page application that shows love to open source projects on GitHub. For the frontend you’ll use Vue and popular tooling like vuex, vue-cli, vuetify, and vue-router. On the backend, you’ll use Go to write a REST API and persist your data in MongoDB.

Authentication and user management can be a major pain, so you’ll use JSON Web Token (JWT) based authentication when making requests from the SPA and Okta’s Go JWT Verifier as a middleware on your backend to validate the user’s token on every request.

Once complete, users will be able to authenticate via OpenID Connect (OIDC), search for projects on GitHub, favorite those projects and even add notes where needed!

Create the Vue and Go Directory Structure

For the sake of simplicity, let’s write the REST API and the SPA in the same project, starting with the project directory in the Go workspace.

Go projects live inside the directory the environment variable $GOPATH points to. In order to find the current $GOPATH value, run: go env GOPATH. To learn more about GOPATH, including how to set it yourself, refer to the official Go documentation on the topic.

If you’re totally new to Go, check out this article in order to understand how projects are organized inside the GOPATH directory.

With the GOPATH defined, you now can create a directory for your project:

mkdir -p $GOPATH/src/github.com/{YOUR_GITHUB_USERNAME}/kudo-oos

To get your SPA off the ground quickly, leverage the scaffolding functionality from vue-cli. The CLI will prompt you with a series of options – pick the technology appropriate for this project: vue.js, vuex, and, webpack.

Install vue-cli by running:

yarn global add @vue/cli

Then, create a new Vue project:

mkdir -p pkg/http/web
cd pkg/http/web
vue create app

You will be prompted with a series of questions about the project’s build details. For this app pick all the default choices.

Use the vue-cli to initialize a program

Congratulations, you have created your Vue.js SPA! Try it out by running:

cd app
yarn install
yarn serve

Open this URL: http://localhost:8080 in your browser and you should see the following.

Vue default page

Next, let’s make your SPA modern and responsive using vuetify.

Add Vuetify

Vuetify is a collection of Vue.js components that abstracts Material Design’s concepts. Vuetify provides out-of-the box features including a grid system, typography, basic layout, and also components like cards, dialogs, chips, tabs, icons and so on. Vuetify will pave your way to a rich UI!

When installing vuetify, you will be prompted with a series of questions. For the sake of simplicity just go with the default choices again.

vue add vuetify

Add vueify

Spin up your SPA again to see vuetify in action.

yarn serve

Vuetify page

Add Authentication to Your Vue App with Okta

Writing secure user auth and building login pages are easy to get wrong and can be the downfall of a new project. Okta makes it simple to implement all the user management functionality quickly and securely. Get started by signing up for a free developer account and creating an OIDC application in Okta.

Okta sign-up page

Once logged in, create a new application by clicking “Add Application”.

Okta add application

Select the “Single-Page App” platform option.

Okta create application

The default application settings should be the same as those pictured.

Okta application settings

Next, install the Okta Vue SDK by running the following command:

yarn add @okta/okta-vue

Create Your Vue App Routes

For this app, you need only 4 routes, all of which require authentication except for the login route.

The root route / is our landing page where the login component will be rendered. Once the user has authenticated, we redirect them to the /me route where the bulk of the functionality takes place: The user should be able to query for OSS projects via GitHub’s REST API, favorite projects returned from the query, see more details about the project, and leave a note describing why the project is important to them.

Take note that both the /me and repo/:id have a meta: { requiresAuth: true } property specifying that the user must be authenticated to access that area of the app. The Okta plugin will use it to redirect the user the the Okta’s login page if not authenticated.

First, create pkg/http/web/app/src/routes.js and define the following routes:

import Vue from 'vue';
import VueRouter from 'vue-router';
import Auth from '@okta/okta-vue'

import Home from './components/Home';
import Login from './components/Login';
import GitHubRepoDetails from './components/GithubRepoDetails';

Vue.use(Auth, {
  issuer: {ADD_YOUR_DOMAIN},
  client_id: {ADD_YOUR_CLIENT_ID},
  redirect_uri: 'http://localhost:8080/implicit/callback',
  scope: 'openid profile email'

export default new VueRouter({
 mode: 'history',
 routes: [
   { path: '/', component: Login },
   { path: '/me', component: Home, meta: { requiresAuth: true }},
   { name: 'repo-details', path: '/repo/:id', component: GitHubRepoDetails, meta: { requiresAuth: true } },
   { path: '/implicit/callback', component: Auth.handleCallback() }

Make sure to add your domain and client_id where indicated – these values can be found on the application overview page in the Okta Developer Console. Calling Vue.use(Auth, ...) will inject an authClient object into your Vue instance which can be accessed by calling this.$auth anywhere inside your Vue instance. This is what you’ll use to make sure a user is logged in and/or to force the user to identify themself!

Create Vue Components

The vue-router library contains a number of components to help developers create dynamic and rich UIs. One of them, router-view, renders the component for the matched route. In our case, when the user accesses the root route/,vue-routerwill render theLogincomponent as configured inrouters.js`.

Open ./kudo-oos/pkg/http/web/app/src/components/App.vue and copy in the following code.

   <Footer />

import Footer from '@/components/Footer.vue'

export default {
 name: 'App',
 components: { Footer },
 data() {
   return {}

For every route other than the matched route component, Vue will render the Footer component. Create ./kudo-oos/pkg/http/web/app/src/components/Footer.vue and copy in the following code to create that footer component.

 <v-footer class="pa-3 white--text" color="teal" absolute>
     Developed with ❤️  by {{YOUR_NAME}} &copy; {{ new Date().getFullYear() }}

Your landing page should now look like this:

Vue landing page

With our login component rendered, the user will be redirected to the login page after clicking the sign in button.

Okta sign-in

And after a successful login, the user is redirected back to your application to the configured route. In our app, that’s the /me route.

Vue app

The /me route was configured to render the Home component, which in turn renders the Sidebar,the Kudos, and Search vuetify tabs. Each tab renders a specific set of GitHubRepos.

Go ahead and create the ./kudo-oos/pkg/http/web/app/src/components/Home.vue component.

   <SearchBar v-on:search-submitted="githubQuery" />
   <v-container grid-list-md fluid class="grey lighten-4" >
       <v-tab class="white--text" :key="2">
       <v-tab class="white--text" :key="1">
       <v-tabs-items style="width:100%" v-model="tabs">
         <v-tab-item :key="2">
           <v-layout row wrap>
             <v-flex v-for="kudo in allKudos" :key="kudo.id" md4 >
               <GitHubRepo :repo="kudo" />
         <v-tab-item :key="1">
           <v-layout row wrap>
             <v-flex v-for="repo in repos" :key="repo.id" md4>
               <GitHubRepo :repo="repo" />

import SearchBar from './SearchBar.vue'
import GitHubRepo from './GithubRepo.vue'
import githubClient from '../githubClient'
import { mapMutations, mapGetters, mapActions } from 'vuex'

export default {
 name: 'Home',
 components: { SearchBar, GitHubRepo },
 data() {
   return {
     tabs: 0
 computed: mapGetters(['allKudos', 'repos']),
 created() {
 methods: {
   githubQuery(query) {
     this.tabs = 1;
       .then(response => this.resetRepos(response.items) )

.v-tabs__content {
  padding-bottom: 2px;

SearchBar is the first component rendered in Home. When the user enters a query into the text input in the Sidebar, the component triggers a call to the Github API. SearchBar simply emits an event to its parent, Home, which contains the githubQuery.

./kudo-oos/pkg/http/web/app/src/components/SearchBar.vue should look like this:

   <v-toolbar dark color="teal">
       label="Search for your OOS project on Github + Press Enter"
     <button @click.prevent="logout">Logout</button>

export default {
   data() {
     return {
       query: null,
   props: ['defaultQuery'],
   methods: {
     onSearchSubmition() {
       this.$emit('search-submitted', this.query);
     async logout () {
       await this.$auth.logout()

Thanks to @keyup.enter="onSearchSubmition", whenever the user hits enter onSearchSubmition emits search-submitted with the query value. How do we capture this event you may ask? Simple! On the Home component, when you mounted the Sidebar component you also added a “listener” v-on:search-submitted="githubQuery" that calls githubQuery on every search-submitted event.

The Sidebar is also responsible for logging the user out. Okta Vue SDK offers a handy method to clean up the session using the method this.$auth.logout(). Whenever the user logs out, they can be redirected to the login page.

The second component rendered in Home is the GithupRepo. This component is used inside two tabs: the first tab Kudos represents the user’s favorites OSS projects and the Search tab renders the OSS projects returned from GitHub.

 <v-card >
   <v-card-title primary-title>
     <div class="repo-card-content">
       <h3 class="headline mb-0">
         <router-link :to="{ name: 'repo-details', params: { id: repo.id }}" >{{repo.full_name}}</router-link>
     <v-btn @click.prevent="toggleKudo(repo)"  flat icon color="pink">
       <v-icon v-if="isKudo(repo)">favorite</v-icon>
       <v-icon v-else>favorite_border</v-icon>

import { mapActions } from 'vuex';

export default {
 data() {
   return {}
 props: ['repo'],
 methods: {
   isKudo(repo) {
     return this.$store.getters.isKudo(repo);

.repo-card-content {
  height: 90px;
  overflow: scroll;

Your SPA uses vuex to manage state in one centralized store accessible by all components. Vuex also ensures that access to the store is performed in a predictable fashion respecting a few rules. To read the state, you need to define getters, synchronous changes to the state must be done via mutations, and asynchronous changes are done via actions.

To install vuex, run:

yarn add vuex

You now need to create ./kudo-oos/pkg/http/web/app/src/store.js with actions, mutations and getters. Your initial data is { kudos: {}, repos: [] }. kudos holds all the user’s favorites OSS projects asa JavaScript Object where the key is the project id and the value is the project itself. repos is an array that holds the search results.

There are two cases in which you may need to mutate state. First, when the user logs in you need to fetch the user’s favorites OSS projects from the Go server and set the repos in the store by calling resetRepos. Second, when the user favorites or unfavorites an OSS project, you need update the kudos in the store by calling resetKudos to reflect that change on the server.

resetKudos is synchronous method that is called by actions inside asynchronous functions after each call to the Go server.

The Home component uses the getters allKudos and repos to render the list of Kudos and SearchResults. In order to know whether a repo has been favorited or not, your app needs to call the isKudo getter.

Create your ./kudo-oos/pkg/http/web/app/src/store.js with the code below:

import Vue from 'vue';
import Vuex from 'vuex';

import APIClient from './apiClient';


const store = new Vuex.Store({
 state: {
   kudos: {},
   repos: [],
 mutations: {
   resetRepos (state, repos) {
     state.repos = repos;
   resetKudos(state, kudos) {
     state.kudos = kudos;
 getters: {
   allKudos(state) {
     return Object.values(state.kudos);
   kudos(state) {
     return state.kudos;
   repos(state) {
     return state.repos;
   isKudo(state) {
     return (repo)=> {
       return !!state.kudos[repo.id];
 actions: {
   getKudos ({commit}) {
     APIClient.getKudos().then((data) => {
       commit('resetKudos', data.reduce((acc, kudo) => {
                              return {[kudo.id]: kudo, ...acc}
                            }, {}))
   updateKudo({ commit, state }, repo) {
     const kudos = { ...state.kudos, [repo.id]: repo };

     return APIClient
       .then(() => {
         commit('resetKudos', kudos)
   toggleKudo({ commit, state }, repo) {
     if (!state.kudos[repo.id]) {
       return APIClient
         .then(kudo => commit('resetKudos', { [kudo.id]: kudo, ...state.kudos }))

     const kudos = Object.entries(state.kudos).reduce((acc, [repoId, kudo]) => {
                     return (repoId == repo.id) ? acc
                                                : { [repoId]: kudo, ...acc };
                   }, {});

     return APIClient
       .then(() => commit('resetKudos', kudos));

export default store;

Inside actions you are performing ajax calls to the Go server. Every request made to the server must be authenticated or the server will respond with a client error. When the user logs in, an access token is created and can be accessed by calling: await Vue.prototype.$auth.getAccessToken(). This asynchronous function returns an access token required to send authenticated requests to the server.

The Go server exposes a REST API for the kudo resource. You will implement methods to make ajax calls in order to create with createKudo, update with updateKudo, delete with deleteKudo, and list all kudos withgetKudos. Notice that these methods call the perform method by passing the endpoint and the HTTP verb. perform, in turn, populates the request Authorization header with the access token so the Go server can validate the request.

Create your ./kudo-oos/pkg/http/web/app/src/apiClient.js with the code below.

import Vue from 'vue';
import axios from 'axios';

const BASE_URI = 'http://localhost:4444';

const client = axios.create({
  baseURL: BASE_URI,
  json: true

const APIClient =  {
  createKudo(repo) {
    return this.perform('post', '/kudos', repo);

  deleteKudo(repo) {
    return this.perform('delete', `/kudos/${repo.id}`);

  updateKudo(repo) {
    return this.perform('put', `/kudos/${repo.id}`, repo);

  getKudos() {
    return this.perform('get', '/kudos');

  getKudo(repo) {
    return this.perform('get', `/kudo/${repo.id}`);

  async perform (method, resource, data) {
    let accessToken = await Vue.prototype.$auth.getAccessToken()
    return client({
      url: resource,
      headers: {
        Authorization: `Bearer ${accessToken}`
    }).then(req => {
      return req.data

export default APIClient;

Each GithubRepo has a router-link to /repo/:id that renders the GithubRepoDetails component. GithubRepoDetails shows details about the OSS project, like how many times the project has been of starred and the amount of open issues. The user can also leave a note describing why the project is special by clicking the Kudo button. The message is sent to Go server button by calling updateKudo.

Create your ./kudo-oos/pkg/http/web/app/src/components/GithubRepoDetails.js with the code below.

  <v-container grid-list-md fluid class="grey lighten-4" >
    <v-layout align-center justify-space-around wrap>
      <v-flex md6>
        <h1 class="primary--text">
          <a :href="repo.html_url">{{repo.full_name}}</a>

        <v-chip class="text-xs-center">
          <v-avatar class="teal">
            <v-icon class="white--text">star</v-icon>
          Stars: {{repo.stargazers_count}}

        <v-chip class="text-xs-center">
          <v-avatar class="teal white--text">L</v-avatar>
          Language: {{repo.language}}

        <v-chip class="text-xs-center">
          <v-avatar class="teal white--text">O</v-avatar>
          Open Issues: {{repo.open_issues_count}}

          label="Show some love"
          hint="Describe why you love this project"
        <v-btn @click.prevent="updateKudo(repo)"> Kudo </v-btn>
        <router-link tag="a" to="/me">Back</router-link>

import { mapActions, mapGetters } from 'vuex';
import githubClient from '../githubClient';

export default {
  data() {
    return {
      repo: {}
  watch: {
    '$route': 'fetchData'
  computed: mapGetters(['kudos']),
  created() {
  methods: {
    fetchData() {
        .then((response) => {
          this.repo = Object.assign(response, this.kudos[this.$route.params.id])

Now that your router, store, and components are in place, go ahead and modify ./kudo-oos/pkg/http/web/app/src/main.js to properly initialize your SPA.

import '@babel/polyfill'
import Vue from 'vue'
import './plugins/vuetify'
import App from './App.vue'
import store from './store'
import router from './routes'

Vue.config.productionTip = process.env.NODE_ENV == 'production';


new Vue({
 render: h => h(App)

Note that we are calling router.beforeEach(Vue.prototype.$auth.authRedirectGuard()) to look for routes tagged with meta: {requiresAuth: true} and redirect the user to the authentication flow if they are not logged in.

Create a REST API with Go

Now that users can securely authenticate on the frontend, you need to create a HTTP server written in Go to handle the requests, validate whether the user is authenticated, and perform CRUD operations.

I like using the dep tool to manage dependencies, so be sure to install it from here before continuing.

dep init
dep ensure -add github.com/okta/okta-jwt-verifier-golang
dep ensure -add github.com/rs/cors
dep ensure -add github.com/globalsign/mgo

You now need a structure to represent a GitHub repository. Start by creating ./kudo-oos/pkg/core/kudo.go and define the following struct to represent a “kudo” (someone giving kudos to a specific repo).

package core

// Kudo represents a oos kudo.
type Kudo struct {
  UserID      string `json:"user_id" bson:"userId"`
  RepoID      string `json:"id" bson:"repoId"`
  RepoName    string `json:"full_name" bson:"repoName"`
  RepoURL     string `json:"html_url" bson:"repoUrl"`
  Language    string `json:"language" bson:"language"`
  Description string `json:"description" bson:"description"`
  Notes       string `json:"notes" bson:"notes"`

Next, create ./kudo-oos/pkg/core/repository.go file and add the following interface to represent an API for any persistence layer you might want to use. In this article, we are going to use MongoDB.

package core
// Repository defines the API a repository implementation should follow.
type Repository interface {
  Find(id string) (*Kudo, error)
  FindAll(selector map[string]interface{}) ([]*Kudo, error)
  Delete(kudo *Kudo) error
  Update(kudo *Kudo) error
  Create(kudo ...*Kudo) error
  Count() (int, error)

Finally, create the MongoDB repository that implements the interface you’ve just created. Create ./kudo-oos/pkg/storage/mongo.go and add the following code.

package storage

import (


const (
  collectionName = "kudos"

func GetCollectionName() string {
  return collectionName

type MongoRepository struct {
  logger  *log.Logger
  session *mgo.Session

// Find fetches a kudo from mongo according to the query criteria provided.
func (r MongoRepository) Find(repoID string) (*core.Kudo, error) {
  session := r.session.Copy()
  defer session.Close()
  coll := session.DB("").C(collectionName)

  var kudo core.Kudo
  err := coll.Find(bson.M{"repoId": repoID, "userId": kudo.UserID}).One(&kudo)
  if err != nil {
    r.logger.Printf("error: %v\n", err)
    return nil, err
  return &kudo, nil

// FindAll fetches kudos from the database.
func (r MongoRepository) FindAll(selector map[string]interface{}) ([]*core.Kudo, error) {
  session := r.session.Copy()
  defer session.Close()
  coll := session.DB("").C(collectionName)

  var kudos []*core.Kudo
  err := coll.Find(selector).All(&kudos)
  if err != nil {
    r.logger.Printf("error: %v\n", err)
    return nil, err
  return kudos, nil

// Delete deletes a kudo from mongo according to the query criteria provided.
func (r MongoRepository) Delete(kudo *core.Kudo) error {
  session := r.session.Copy()
  defer session.Close()
  coll := session.DB("").C(collectionName)

  return coll.Remove(bson.M{"repoId": kudo.RepoID, "userId": kudo.UserID})

// Update updates an kudo.
func (r MongoRepository) Update(kudo *core.Kudo) error {
  session := r.session.Copy()
  defer session.Close()
  coll := session.DB("").C(collectionName)

  return coll.Update(bson.M{"repoId": kudo.RepoID, "userId": kudo.UserID}, kudo)

// Create kudos in the database.
func (r MongoRepository) Create(kudos ...*core.Kudo) error {
  session := r.session.Copy()
  defer session.Close()
  coll := session.DB("").C(collectionName)

  for _, kudo := range kudos {
    _, err := coll.Upsert(bson.M{"repoId": kudo.RepoID, "userId": kudo.UserID}, kudo)
    if err != nil {
      return err

  return nil

// Count counts documents for a given collection
func (r MongoRepository) Count() (int, error) {
  session := r.session.Copy()
  defer session.Close()
  coll := session.DB("").C(collectionName)
  return coll.Count()

// NewMongoSession dials mongodb and creates a session.
func newMongoSession() (*mgo.Session, error) {
  mongoURL := os.Getenv("MONGO_URL")
  if mongoURL == "" {
    log.Fatal("MONGO_URL not provided")
  return mgo.Dial(mongoURL)

func newMongoRepositoryLogger() *log.Logger {
  return log.New(os.Stdout, "[mongoDB] ", 0)

func NewMongoRepository() core.Repository {
  logger := newMongoRepositoryLogger()
  session, err := newMongoSession()
  if err != nil {
    logger.Fatalf("Could not connect to the database: %v\n", err)

  return MongoRepository{
    session: session,
    logger:  logger,

Add the Go Backend

Before you can create HTTP handlers, you’ll need to write code to handle incoming request payloads.

Create ./kudo-oos/pkg/kudo/service.go and insert the code below.

package kudo

import (


type GitHubRepo struct {
  RepoID      int64  `json:"id"`
  RepoURL     string `json:"html_url"`
  RepoName    string `json:"full_name"`
  Language    string `json:"language"`
  Description string `json:"description"`
  Notes       string `json:"notes"`

type Service struct {
  userId string
  repo   core.Repository

func (s Service) GetKudos() ([]*core.Kudo, error) {
  return s.repo.FindAll(map[string]interface{}{"userId": s.userId})

func (s Service) CreateKudoFor(githubRepo GitHubRepo) (*core.Kudo, error) {
  kudo := s.githubRepoToKudo(githubRepo)
  err := s.repo.Create(kudo)
  if err != nil {
    return nil, err
  return kudo, nil

func (s Service) UpdateKudoWith(githubRepo GitHubRepo) (*core.Kudo, error) {
  kudo := s.githubRepoToKudo(githubRepo)
  err := s.repo.Create(kudo)
  if err != nil {
    return nil, err
  return kudo, nil

func (s Service) RemoveKudo(githubRepo GitHubRepo) (*core.Kudo, error) {
  kudo := s.githubRepoToKudo(githubRepo)
  err := s.repo.Delete(kudo)
  if err != nil {
    return nil, err
  return kudo, nil

func (s Service) githubRepoToKudo(githubRepo GitHubRepo) *core.Kudo {
  return &core.Kudo{
    UserID:      s.userId,
    RepoID:      strconv.Itoa(int(githubRepo.RepoID)),
    RepoName:    githubRepo.RepoName,
    RepoURL:     githubRepo.RepoURL,
    Language:    githubRepo.Language,
    Description: githubRepo.Description,
    Notes:       githubRepo.Notes,

func NewService(repo core.Repository, userId string) Service {
  return Service{
    repo:   repo,
    userId: userId,

Define Go HTTP Handlers

Your REST API exposes the kudo resource to support clients like your SPA. A normal SPA will expose endpoints so clients can create, update, delete, and list resources. For instance, when the user logs in, a request is made to fetch all the kudos for the authenticated user via GET /kudos.

 # Fetches all open source projects favorited by the user
GET /kudos
# Fetches a favorited open source project by id
GET /kudos/:id
# Creates (or favorites)  a open source project for the logged in user
POST /kudos
# Updates  a favorited open source project
PUT /kudos/:id
# Deletes (or unfavorites) a favorited open source project
DELETE /kudos/:id

To support this, you need to add new file named ./kudo-oos/pkg/http/handlers.go and define your HTTP handlers using the fabulous httprouter library.

package http

import (


type Service struct {
  repo   core.Repository
  Router http.Handler

func New(repo core.Repository) Service {
  service := Service{
    repo: repo,

  router := httprouter.New()
  router.GET("/kudos", service.Index)
  router.POST("/kudos", service.Create)
  router.DELETE("/kudos/:id", service.Delete)
  router.PUT("/kudos/:id", service.Update)

  service.Router = UseMiddlewares(router)

  return service

func (s Service) Index(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
  service := kudo.NewService(s.repo, r.Context().Value("userId").(string))
  kudos, err := service.GetKudos()

  if err != nil {

func (s Service) Create(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
  service := kudo.NewService(s.repo, r.Context().Value("userId").(string))
  payload, _ := ioutil.ReadAll(r.Body)

  githubRepo := kudo.GitHubRepo{}
  json.Unmarshal(payload, &githubRepo)

  kudo, err := service.CreateKudoFor(githubRepo)

  if err != nil {

func (s Service) Delete(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
  service := kudo.NewService(s.repo, r.Context().Value("userId").(string))

  repoID, _ := strconv.Atoi(params.ByName("id"))
  githubRepo := kudo.GitHubRepo{RepoID: int64(repoID)}

  _, err := service.RemoveKudo(githubRepo)
  if err != nil {

func (s Service) Update(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
  service := kudo.NewService(s.repo, r.Context().Value("userId").(string))
  payload, _ := ioutil.ReadAll(r.Body)

  githubRepo := kudo.GitHubRepo{}
  json.Unmarshal(payload, &githubRepo)

  kudo, err := service.UpdateKudoWith(githubRepo)
  if err != nil {

Verify JSON Web Tokens (JWTs) with Go

This is the most crucial component of your REST API server. Without this middleware, any user can perform CRUD operations against the database.

In the event that no valid JWT is provided in the HTTP authorization header, the API call is aborted and an error returned to the client.

Create ./kudo-oos/pkg/http/middlewares.go and paste in the following code:

package http

import (

  jwtverifier "github.com/okta/okta-jwt-verifier-golang"

func OktaAuth(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    accessToken := r.Header["Authorization"]
    jwt, err := validateAccessToken(accessToken)
    if err != nil {
    ctx := context.WithValue(r.Context(), "userId", jwt.Claims["sub"].(string))
    h.ServeHTTP(w, r.WithContext(ctx))

func validateAccessToken(accessToken []string) (*jwtverifier.Jwt, error) {
  parts := strings.Split(accessToken[0], " ")
  jwtVerifierSetup := jwtverifier.JwtVerifier{
    Issuer:           "{DOMAIN}",
    ClaimsToValidate: map[string]string{"aud": "api://default", "cid": "{CLIENT_ID}"},
  verifier := jwtVerifierSetup.New()
  return verifier.VerifyIdToken(parts[1])

func JSONApi(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/json")
    h.ServeHTTP(w, r)

func AccsessLog(h http.Handler) http.Handler {
  return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("%s: %s", r.Method, r.RequestURI)
    h.ServeHTTP(w, r)

func Cors(h http.Handler) http.Handler {
  corsConfig := cors.New(cors.Options{
    AllowedHeaders: []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "Authorization"},
    AllowedMethods: []string{"POST", "PUT", "GET", "PATCH", "OPTIONS", "HEAD", "DELETE"},
    Debug:          true,
  return corsConfig.Handler(h)

func UseMiddlewares(h http.Handler) http.Handler {
  h = JSONApi(h)
  h = OktaAuth(h)
  h = Cors(h)
  return AccsessLog(h)

As you can see, the middleware OktaAuth uses okta-jwt-verifier-golang to validate the user’s access token.

Define Your Go REST API Entry Point

Open up ./kudo-oos/pkg/cmd/main.go and add the following code to spin up your Go webserver.

package main

import (

  web "github.com/{YOUR_GITHUB_USERNAME}/kudo-oos/pkg/http"

func main() {
  httpPort := os.Getenv("PORT")

  repo := storage.NewMongoRepository()
  webService := web.New(repo)

  log.Printf("Running on port %s\n", httpPort)
  log.Fatal(http.ListenAndServe(httpPort, webService.Router))

Run the Go +Vue SPA

There are many ways to run backend and frontend apps. The simplest way (for development purposes) is to just use good old fashioned Make.

A Makefile contains build instructions for your website. It’s like an old-school version of gulp, grunt, and the more hip Node tools. To get started, create a file named Makefile in the root of your project folder and copy in the following code.

setup: run_services
    @go run ./cmd/db/setup.go

    @docker-compose up --build -d

    @MONGO_URL=mongodb://mongo_user:mongo_secret@ PORT=:4444 go run cmd/main.go

    @/bin/bash -c "cd $GOPATH/src/github.com/klebervirgilio/kudo-oos/pkg/http/web/app && yarn serve"

Create a Dockerfile

Next, you’ll want to create a Dockerfile. This file tells Docker how to run your application and spares you the effort of deploying a real MongoDB instance for testing purposes.

All you need to do here is create a file named docker-compose.yml and copy in the following code.

version: '3'
    image: mongo
    restart: always
     - "27017:27017"
      MONGO_INITDB_ROOT_PASSWORD: mongo_secret

Your app is now ready to test! Run the following commands to get going.

make setup
make run_server
make run_client

Your Go webserver should be listening on and your SPA should be serving files from http://localhost:8080. Visit http://localhost:8080 to play around with your new app!

#vuejs #golang #javascript

What is GEEK

Buddha Community

How to build a Single Page App using  Go  and Vue.js
Chloe  Butler

Chloe Butler


Pdf2gerb: Perl Script Converts PDF Files to Gerber format


Perl script converts PDF files to Gerber format

Pdf2Gerb generates Gerber 274X photoplotting and Excellon drill files from PDFs of a PCB. Up to three PDFs are used: the top copper layer, the bottom copper layer (for 2-sided PCBs), and an optional silk screen layer. The PDFs can be created directly from any PDF drawing software, or a PDF print driver can be used to capture the Print output if the drawing software does not directly support output to PDF.

The general workflow is as follows:

  1. Design the PCB using your favorite CAD or drawing software.
  2. Print the top and bottom copper and top silk screen layers to a PDF file.
  3. Run Pdf2Gerb on the PDFs to create Gerber and Excellon files.
  4. Use a Gerber viewer to double-check the output against the original PCB design.
  5. Make adjustments as needed.
  6. Submit the files to a PCB manufacturer.

Please note that Pdf2Gerb does NOT perform DRC (Design Rule Checks), as these will vary according to individual PCB manufacturer conventions and capabilities. Also note that Pdf2Gerb is not perfect, so the output files must always be checked before submitting them. As of version 1.6, Pdf2Gerb supports most PCB elements, such as round and square pads, round holes, traces, SMD pads, ground planes, no-fill areas, and panelization. However, because it interprets the graphical output of a Print function, there are limitations in what it can recognize (or there may be bugs).

See docs/Pdf2Gerb.pdf for install/setup, config, usage, and other info.


#Pdf2Gerb config settings:
#Put this file in same folder/directory as pdf2gerb.pl itself (global settings),
#or copy to another folder/directory with PDFs if you want PCB-specific settings.
#There is only one user of this file, so we don't need a custom package or namespace.
#NOTE: all constants defined in here will be added to main namespace.
#package pdf2gerb_cfg;

use strict; #trap undef vars (easier debug)
use warnings; #other useful info (easier debug)

#configurable settings:
#change values here instead of in main pfg2gerb.pl file

use constant WANT_COLORS => ($^O !~ m/Win/); #ANSI colors no worky on Windows? this must be set < first DebugPrint() call

#just a little warning; set realistic expectations:
#DebugPrint("${\(CYAN)}Pdf2Gerb.pl ${\(VERSION)}, $^O O/S\n${\(YELLOW)}${\(BOLD)}${\(ITALIC)}This is EXPERIMENTAL software.  \nGerber files MAY CONTAIN ERRORS.  Please CHECK them before fabrication!${\(RESET)}", 0); #if WANT_DEBUG

use constant METRIC => FALSE; #set to TRUE for metric units (only affect final numbers in output files, not internal arithmetic)
use constant APERTURE_LIMIT => 0; #34; #max #apertures to use; generate warnings if too many apertures are used (0 to not check)
use constant DRILL_FMT => '2.4'; #'2.3'; #'2.4' is the default for PCB fab; change to '2.3' for CNC

use constant WANT_DEBUG => 0; #10; #level of debug wanted; higher == more, lower == less, 0 == none
use constant GERBER_DEBUG => 0; #level of debug to include in Gerber file; DON'T USE FOR FABRICATION
use constant WANT_STREAMS => FALSE; #TRUE; #save decompressed streams to files (for debug)
use constant WANT_ALLINPUT => FALSE; #TRUE; #save entire input stream (for debug ONLY)

#DebugPrint(sprintf("${\(CYAN)}DEBUG: stdout %d, gerber %d, want streams? %d, all input? %d, O/S: $^O, Perl: $]${\(RESET)}\n", WANT_DEBUG, GERBER_DEBUG, WANT_STREAMS, WANT_ALLINPUT), 1);
#DebugPrint(sprintf("max int = %d, min int = %d\n", MAXINT, MININT), 1); 

#define standard trace and pad sizes to reduce scaling or PDF rendering errors:
#This avoids weird aperture settings and replaces them with more standardized values.
#(I'm not sure how photoplotters handle strange sizes).
#Fewer choices here gives more accurate mapping in the final Gerber files.
#units are in inches
use constant TOOL_SIZES => #add more as desired
#round or square pads (> 0) and drills (< 0):
    .010, -.001,  #tiny pads for SMD; dummy drill size (too small for practical use, but needed so StandardTool will use this entry)
    .031, -.014,  #used for vias
    .041, -.020,  #smallest non-filled plated hole
    .051, -.025,
    .056, -.029,  #useful for IC pins
    .070, -.033,
    .075, -.040,  #heavier leads
#    .090, -.043,  #NOTE: 600 dpi is not high enough resolution to reliably distinguish between .043" and .046", so choose 1 of the 2 here
    .100, -.046,
    .115, -.052,
    .130, -.061,
    .140, -.067,
    .150, -.079,
    .175, -.088,
    .190, -.093,
    .200, -.100,
    .220, -.110,
    .160, -.125,  #useful for mounting holes
#some additional pad sizes without holes (repeat a previous hole size if you just want the pad size):
    .090, -.040,  #want a .090 pad option, but use dummy hole size
    .065, -.040, #.065 x .065 rect pad
    .035, -.040, #.035 x .065 rect pad
    .001,  #too thin for real traces; use only for board outlines
    .006,  #minimum real trace width; mainly used for text
    .008,  #mainly used for mid-sized text, not traces
    .010,  #minimum recommended trace width for low-current signals
    .015,  #moderate low-voltage current
    .020,  #heavier trace for power, ground (even if a lighter one is adequate)
    .030,  #heavy-current traces; be careful with these ones!
#Areas larger than the values below will be filled with parallel lines:
#This cuts down on the number of aperture sizes used.
#Set to 0 to always use an aperture or drill, regardless of size.
use constant { MAX_APERTURE => max((TOOL_SIZES)) + .004, MAX_DRILL => -min((TOOL_SIZES)) + .004 }; #max aperture and drill sizes (plus a little tolerance)
#DebugPrint(sprintf("using %d standard tool sizes: %s, max aper %.3f, max drill %.3f\n", scalar((TOOL_SIZES)), join(", ", (TOOL_SIZES)), MAX_APERTURE, MAX_DRILL), 1);

#NOTE: Compare the PDF to the original CAD file to check the accuracy of the PDF rendering and parsing!
#for example, the CAD software I used generated the following circles for holes:
#CAD hole size:   parsed PDF diameter:      error:
#  .014                .016                +.002
#  .020                .02267              +.00267
#  .025                .026                +.001
#  .029                .03167              +.00267
#  .033                .036                +.003
#  .040                .04267              +.00267
#This was usually ~ .002" - .003" too big compared to the hole as displayed in the CAD software.
#To compensate for PDF rendering errors (either during CAD Print function or PDF parsing logic), adjust the values below as needed.
#units are pixels; for example, a value of 2.4 at 600 dpi = .0004 inch, 2 at 600 dpi = .0033"
use constant
    HOLE_ADJUST => -0.004 * 600, #-2.6, #holes seemed to be slightly oversized (by .002" - .004"), so shrink them a little
    RNDPAD_ADJUST => -0.003 * 600, #-2, #-2.4, #round pads seemed to be slightly oversized, so shrink them a little
    SQRPAD_ADJUST => +0.001 * 600, #+.5, #square pads are sometimes too small by .00067, so bump them up a little
    RECTPAD_ADJUST => 0, #(pixels) rectangular pads seem to be okay? (not tested much)
    TRACE_ADJUST => 0, #(pixels) traces seemed to be okay?
    REDUCE_TOLERANCE => .001, #(inches) allow this much variation when reducing circles and rects

#Also, my CAD's Print function or the PDF print driver I used was a little off for circles, so define some additional adjustment values here:
#Values are added to X/Y coordinates; units are pixels; for example, a value of 1 at 600 dpi would be ~= .002 inch
use constant
    CIRCLE_ADJUST_MINY => -0.001 * 600, #-1, #circles were a little too high, so nudge them a little lower
    CIRCLE_ADJUST_MAXX => +0.001 * 600, #+1, #circles were a little too far to the left, so nudge them a little to the right
    SUBST_CIRCLE_CLIPRECT => FALSE, #generate circle and substitute for clip rects (to compensate for the way some CAD software draws circles)
    WANT_CLIPRECT => TRUE, #FALSE, #AI doesn't need clip rect at all? should be on normally?
    RECT_COMPLETION => FALSE, #TRUE, #fill in 4th side of rect when 3 sides found

#allow .012 clearance around pads for solder mask:
#This value effectively adjusts pad sizes in the TOOL_SIZES list above (only for solder mask layers).
use constant SOLDER_MARGIN => +.012; #units are inches

#line join/cap styles:
use constant
    CAP_NONE => 0, #butt (none); line is exact length
    CAP_ROUND => 1, #round cap/join; line overhangs by a semi-circle at either end
    CAP_SQUARE => 2, #square cap/join; line overhangs by a half square on either end
    CAP_OVERRIDE => FALSE, #cap style overrides drawing logic
#number of elements in each shape type:
use constant
    RECT_SHAPELEN => 6, #x0, y0, x1, y1, count, "rect" (start, end corners)
    LINE_SHAPELEN => 6, #x0, y0, x1, y1, count, "line" (line seg)
    CURVE_SHAPELEN => 10, #xstart, ystart, x0, y0, x1, y1, xend, yend, count, "curve" (bezier 2 points)
    CIRCLE_SHAPELEN => 5, #x, y, 5, count, "circle" (center + radius)
#const my %SHAPELEN =
#Readonly my %SHAPELEN =>
    rect => RECT_SHAPELEN,
    line => LINE_SHAPELEN,
    curve => CURVE_SHAPELEN,
    circle => CIRCLE_SHAPELEN,

#This will repeat the entire body the number of times indicated along the X or Y axes (files grow accordingly).
#Display elements that overhang PCB boundary can be squashed or left as-is (typically text or other silk screen markings).
#Set "overhangs" TRUE to allow overhangs, FALSE to truncate them.
#xpad and ypad allow margins to be added around outer edge of panelized PCB.
use constant PANELIZE => {'x' => 1, 'y' => 1, 'xpad' => 0, 'ypad' => 0, 'overhangs' => TRUE}; #number of times to repeat in X and Y directions

# Set this to 1 if you need TurboCAD support.
#$turboCAD = FALSE; #is this still needed as an option?

#CIRCAD pad generation uses an appropriate aperture, then moves it (stroke) "a little" - we use this to find pads and distinguish them from PCB holes. 
use constant PAD_STROKE => 0.3; #0.0005 * 600; #units are pixels
#convert very short traces to pads or holes:
use constant TRACE_MINLEN => .001; #units are inches
#use constant ALWAYS_XY => TRUE; #FALSE; #force XY even if X or Y doesn't change; NOTE: needs to be TRUE for all pads to show in FlatCAM and ViewPlot
use constant REMOVE_POLARITY => FALSE; #TRUE; #set to remove subtractive (negative) polarity; NOTE: must be FALSE for ground planes

#PDF uses "points", each point = 1/72 inch
#combined with a PDF scale factor of .12, this gives 600 dpi resolution (1/72 * .12 = 600 dpi)
use constant INCHES_PER_POINT => 1/72; #0.0138888889; #multiply point-size by this to get inches

# The precision used when computing a bezier curve. Higher numbers are more precise but slower (and generate larger files).
#$bezierPrecision = 100;
use constant BEZIER_PRECISION => 36; #100; #use const; reduced for faster rendering (mainly used for silk screen and thermal pads)

# Ground planes and silk screen or larger copper rectangles or circles are filled line-by-line using this resolution.
use constant FILL_WIDTH => .01; #fill at most 0.01 inch at a time

# The max number of characters to read into memory
use constant MAX_BYTES => 10 * M; #bumped up to 10 MB, use const

use constant DUP_DRILL1 => TRUE; #FALSE; #kludge: ViewPlot doesn't load drill files that are too small so duplicate first tool

my $runtime = time(); #Time::HiRes::gettimeofday(); #measure my execution time

print STDERR "Loaded config settings from '${\(__FILE__)}'.\n";
1; #last value must be truthful to indicate successful load


#use Package::Constants;
#use Exporter qw(import); #https://perldoc.perl.org/Exporter.html

#my $caller = "pdf2gerb::";

#sub cfg
#    my $proto = shift;
#    my $class = ref($proto) || $proto;
#    my $settings =
#    {
#        $WANT_DEBUG => 990, #10; #level of debug wanted; higher == more, lower == less, 0 == none
#    };
#    bless($settings, $class);
#    return $settings;

#use constant HELLO => "hi there2"; #"main::HELLO" => "hi there";
#use constant GOODBYE => 14; #"main::GOODBYE" => 12;

#print STDERR "read cfg file\n";

#our @EXPORT_OK = Package::Constants->list(__PACKAGE__); #https://www.perlmonks.org/?node_id=1072691; NOTE: "_OK" skips short/common names

#print STDERR scalar(@EXPORT_OK) . " consts exported:\n";
#foreach(@EXPORT_OK) { print STDERR "$_\n"; }
#my $val = main::thing("xyz");
#print STDERR "caller gave me $val\n";
#foreach my $arg (@ARGV) { print STDERR "arg $arg\n"; }

Download Details:

Author: swannman
Source Code: https://github.com/swannman/pdf2gerb

License: GPL-3.0 license


Aria Barnes

Aria Barnes


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

Luna  Mosciski

Luna Mosciski


8 Popular Websites That Use The Vue.JS Framework

In this article, we are going to list out the most popular websites using Vue JS as their frontend framework.

Vue JS is one of those elite progressive JavaScript frameworks that has huge demand in the web development industry. Many popular websites are developed using Vue in their frontend development because of its imperative features.

This framework was created by Evan You and still it is maintained by his private team members. Vue is of course an open-source framework which is based on MVVM concept (Model-view view-Model) and used extensively in building sublime user-interfaces and also considered a prime choice for developing single-page heavy applications.

Released in February 2014, Vue JS has gained 64,828 stars on Github, making it very popular in recent times.

Evan used Angular JS on many operations while working for Google and integrated many features in Vue to cover the flaws of Angular.

“I figured, what if I could just extract the part that I really liked about Angular and build something really lightweight." - Evan You

#vuejs #vue #vue-with-laravel #vue-top-story #vue-3 #build-vue-frontend #vue-in-laravel #vue.js

Top VueJS App Development Company in USA

AppClues Infotech is the best & most reliable VueJS App Development Company in USA that builds high-quality and top-notch mobile apps with advanced methodology. The company is focused on providing innovative & technology-oriented solutions as per your specific business needs.

The organization’s VueJS developers have high experience and we have the capability of handling small to big projects. Being one of the leading mobile app development company in USA we are using the latest programming languages and technologies for their clients.

Key Elements:

· Total year of experience - 8+

· Employees Strength - 120+

· Hourly Rate - $25 – $45 / hr

· Location - New York, USA

· Successfully launched projects - 450+

VueJS Development Services by AppClues Infotech

· Custom VueJS Development

· Portal Development Solutions

· Web Application Development

· VueJS Plugin Development

· VueJS Ecommerce Development

· SPA (Single Page App) Development

· VueJS Migration

Why Hire VueJS Developers from AppClues Infotech?

· Agile & Adaptive Development

· 8+ Years of Average Experience

· 100% Transparency

· Guaranteed Bug-free VueJS Solution

· Flexible Engagement Models

· On-Time Project Delivery

· Immediate Technical Support

If you have any project ideas for VueJS app development then share your requirements with AppClues Infotech to get the best solution for your dream projects.

For more info:
Share Yoru Requirements: https://www.appcluesinfotech.com/contact-us/
Email: info@appcluesinfotech.com
Call: +1-978-309-9910

#top vue.js development company #vue.js app development company #best vue js development company #hire top vue js developers #hire top vue.js developers in usa #vue js development company usa

NBB: Ad-hoc CLJS Scripting on Node.js


Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.


Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.


Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).


Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
#js {:columns 216, :rows 47}
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
$ ls


Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.


NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.


To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"


Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink


(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))


Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
   (println "Doing stuff which takes a while")
   (sleep 1000)

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while

Also see API docs.


Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.


See the examples directory for small examples.

Also check out these projects built with nbb:


See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.



  • babashka >= 0.4.0
  • Clojure CLI >=
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript