LoginSignup
12
11

More than 3 years have passed since last update.

Go + gin-gonic + Vue で作るWebアプリの始め方

Posted at

この記事では Goとgin-gonic (Go の Web Application Framework) および webpack と Vue を使ってWebアプリを作る際の初期環境の構築方法について説明します。自分自信、webpackやVueのプロではないので、もっといい方法などあればコメント歓迎です。なおこの工程でできる完成品は https://github.com/m-mizutani/web-app-go に置いてあります。

構築手順

webpack周りの設定

最初にyarnのパッケージを諸々追加します。 yarn init するとパッケージの内容についていろいろ聞かれるのでよしなに入力します。

$ 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

そのあと、 webpack.config.js を作成します。スタイルシートにはSCSSを使うことを想定しています。 ./static がデプロイ用ファイルの置き場、./src が元のJavaScriptやスタイルシートを格納するディレクトリです。

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()]
};

最後の方に書いてあるとおり、 /api/* に対してはgoで書いたserverにproxyさせます。

さらに、npm からコマンド実行できるように package.json に以下の項目を追加しておきます。

  "scripts": {
    "start": "webpack-dev-server",
    "build": "webpack --optimize-minimize"
  },

Web関連のコードを追加

以下のファイルを初期ファイルとして配置します。 "This is test" というボタンをクリックするとAjaxでJSONをAPIサーバから取得して、その中の message という項目を表示するというシンプルなものです。

  • 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;
}

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)
});

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>

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>

Goのサーバを書く

Goのモジュールを初期化します。パッケージ名は github.com/m-mizutani/web-app-go という想定ですので必要に応じて置き換えます。

$ go mod init github.com/m-mizutani/web-app-go

そのあと 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")
    }
}

開発

Goサーバを動かす

go run . でも起動しますが、開発のためにhot reloadができると便利なので
air を使います。 .air.conf という設定ファイルを用意します。以下サンプルです。

[build]
include_ext = ["go"]
exclude_dir = ["src", "tmp", "node_modules"]
delay = 1000 # ms
stop_on_error = true
log = "air_errors.log"

ファイルを作成したら以下の通り実行します。

$ air -c .air.conf

Webpack dev server を動かす

こちらはデフォルトでホットリロードに対応してくれているので、そのまま webpack-dev-server を起動します。 package.json の script の項目を記述していれば、以下のコマンドで起動します。

$ npm run start

サーバが起動したら http://localhost:8080 を開くことで

デプロイ

Goのバイナリ + ./static 以下のファイルを対象サーバにコピーしたり、Docker image 化してpushしたりとすることで、デプロイできます。

12
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
11