DEV Community

Masayoshi Mizutani
Masayoshi Mizutani

Posted on • Updated on

How to build Web App with Go + gin-gonic + Vue

This article describes how to build and develop Web application with Go + gin-gonic (Web Application Framework in Go) + Vue.

(Edited) Sample code repository: https://github.com/m-mizutani/web-app-go

Steps

Configure webpack

At first, install yarn packages

$ yarn init
$ yarn add -D @babel/cli @babel/core @babel/preset-env babel-loader webpack webpack-cli webpack-dev-server html-webpack-plugin vue-loader vue-template-compiler css-loader vue-style-loader sass-loader
$ yarn add babel-polyfill vue  node-sass axios
Enter fullscreen mode Exit fullscreen mode

After that, create webpack.config.js file.

const path = require('path');
const VueLoaderPlugin = require("vue-loader/lib/plugin");

module.exports = {
  mode: "development",
  entry: ["babel-polyfill", path.resolve("src", "js", "index.js")],
  output: {
    filename: "bundle.js",
    path: path.join(__dirname, "static/js/"),
    publicPath: "/js"
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: "vue-loader"
      },
      {
        test: /\.js$/,
        loader: "babel-loader"
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          // Creates `style` nodes from JS strings
          'vue-style-loader',
          // Translates CSS into CommonJS
          'css-loader',
          // Compiles Sass to CSS
          'sass-loader',
        ],
      }
    ]
  },
  resolve: {
    extensions: [".js", "json", "jsx", "vue"],
    alias: {
      vue$: "vue/dist/vue.esm.js"
    }
  },
  devServer: {
    contentBase: "static",
    proxy: {
      "/api": "http://localhost:9080"
    }
  },
  plugins: [new VueLoaderPlugin()]
};
Enter fullscreen mode Exit fullscreen mode

Additoinaly, put following setting into package.json.

  "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --optimize-minimize"
  },
Enter fullscreen mode Exit fullscreen mode

Add web assets

Required following files:

  • src/css/main.scss
  • src/js/index.js
  • src/js/app.vue
  • static/index.html

main.scss

body {
  font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif;
}
Enter fullscreen mode Exit fullscreen mode

index.js

import '../css/main.scss'

import _ from 'lodash';
import "babel-polyfill";
import Vue from "vue";

import App from "./app.vue";

new Vue({
    el: "#app",
    render: h => h(App)
});
Enter fullscreen mode Exit fullscreen mode

app.vue

<template>
  <div>
    <div>MyApp</div>
    <button v-on:click="showMessage">This is test</button>
    <div>{{message}}</div>
  </div>
</template>
<script>
import axios from "axios";
const appData = {
  message: ""
};
export default {
  data() {
    return appData;
  },
  methods: {
    showMessage: showMessage
  }
};
function showMessage() {
  axios.get("/api/v1/hello").then(res => {
    console.log(res);
    appData.message = res.data.message;
  });
}
</script>
<style>
</style>
Enter fullscreen mode Exit fullscreen mode

index.html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width" />
    <title>MyApp</title>
  </head>
  <body>
    <div id="app"></div>
    <script src="/js/bundle.js"></script>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Add go module

Initialize go module.

$ go mod init github.com/m-mizutani/web-app-go
Enter fullscreen mode Exit fullscreen mode

After that, add main.go.

package main

import (
    "fmt"
    "os"

    "github.com/gin-contrib/static"
    "github.com/gin-gonic/gin"
    "github.com/sirupsen/logrus"
)

var logger = logrus.New()

var logLevelMap = map[string]logrus.Level{
    "trace": logrus.TraceLevel,
    "debug": logrus.DebugLevel,
    "info":  logrus.InfoLevel,
    "warn":  logrus.WarnLevel,
    "error": logrus.ErrorLevel,
}

type arguments struct {
    LogLevel       string
    BindAddress    string
    BindPort       int
    StaticContents string
}

func runServer(args arguments) error {
    level, ok := logLevelMap[args.LogLevel]
    if !ok {
        return fmt.Errorf("Invalid log level: %s", args.LogLevel)
    }
    logger.SetLevel(level)
    logger.SetFormatter(&logrus.JSONFormatter{})

    logger.WithFields(logrus.Fields{
        "args": args,
    }).Info("Given options")

    r := gin.Default()

    r.Use(static.Serve("/", static.LocalFile(args.StaticContents, false)))
    r.GET("/api/v1/hello", func(c *gin.Context) {
        c.String(200, `{"message":"hello, hello, hello"}`)
    })

    if err := r.Run(fmt.Sprintf("%s:%d", args.BindAddress, args.BindPort)); err != nil {
        return err
    }

    return nil
}

func main() {
    args := arguments{
        LogLevel: "info",
        BindAddress: "0.0.0.0",
        BindPort: 9080,
        StaticContents: "./static",
        }

    if err := runServer(args); err != nil {
        logger.WithError(err).Fatal("Server exits with error")
    }
}
Enter fullscreen mode Exit fullscreen mode

Development

Run go server

$ go run .
Enter fullscreen mode Exit fullscreen mode

air command with .air.conf like following is recommended for hot reloading.

[build]
include_ext = ["go", "tpl", "tmpl", "html"]
exclude_dir = ["src", "tmp", "node_modules"]
delay = 1000 # ms
stop_on_error = true
log = "air_errors.log"
Enter fullscreen mode Exit fullscreen mode

And run air

$ air -c .air.conf
Enter fullscreen mode Exit fullscreen mode

Start webpack development server

$ npm run start
Enter fullscreen mode Exit fullscreen mode

Open browser

Open http://localhost:8080 to confirm Web UI.

Deploy

$ npm run build
$ go build -o sercer
$ cp -r server static /path/to/server
Enter fullscreen mode Exit fullscreen mode

Top comments (3)

Collapse
 
fabiansilva profile image
Fabian Silva

thanks for your post, I'm learning go and it seems good to start with.

Can please upload the code to some repo? thanks.

Collapse
 
megaproaktiv profile image
Gernot Glawe

Learning go? Maybe try go–on–aws.com?

Collapse
 
mizutani profile image
Masayoshi Mizutani

Thank you for your comment. I added sample code repository URL (github.com/m-mizutani/web-app-go) to head of the post.