Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

QAエンジニアがVue.jsと戯れてみた 2

More than 1 year has passed since last update.

QAエンジニアがVue.jsと戯れてみた に続くまさかの(?)第二弾です。

前回はローカルでごちゃごちゃいじった内容を紹介しただけでしたが、今回は Vue.jsとGoで作ったWebアプリをHerokuへアプケーションを配置して動作するところまでやりたいと思います。

Webサイトの内容は、connpass.comのAPIをお借りしてのイベント検索サイトで、APIへのリクエストはGoが行い、検索画面をVue.jsで作成するといったものになります。

リポジトリ

とりあえず、ソースはこちらになります。
https://github.com/takayamag/connpass-search

前提条件

  • macOS High Sierra 10.13.5
  • Homebrew がインストール済みであること
  • Git がインストール済みであること
  • Herokuのアカウントを持っていること
  • GitHubなどのリポジトリのアカウントを持っていること

Homebrew公式サイト

使用するツールやライブラリ

使用するツールやライブラリ類は以下のようになります。開発時はなるべく最新版を使用するようにしていますが、日々アップデートが行われますので記載した内容は最新版ではない可能性があります。

  • Go: 1.10.3

    • Goの依存関係管理ツール: dep: 0.4.1
    • echo: 3.3.5
    • godotenv: 1.2.0
  • node: 10.5.0

    • テンプレート作成: vue-cli: 3.0.0-rc.3
    • ビルドツール: webpack
    • パッケージ
      • axios: 0.18.0
      • element-ui: 2.4.1
      • es6-promise: 4.2.4
      • lodash-es: 4.17.10
      • moment: 2.22.2
      • vue: 2.5.2
      • vue-router: 3.0.1
      • vuex: 3.0.1
  • heroku (heroku-cli): 7.5.7

プロジェクトのディレクトリパス

この記事では、以下のパスをアプリケーションのルートパスとします。

${HOME}/go/src/projects/connpass-search

後ほど出てきますが、Goのパッケージ管理にdepを使用しています。
このdepを実行するために、プロジェクトのディレクトリは${GOPATH}/src/以下に配置しています。

そうしないと、dep initを実行した時にinit failed: unable to detect the containing GOPATHというエラーが発生します。

Go言語

Go言語のインストール

ここではbrewを使用してGo言語をインストールしています。既にインストール済みであればスキップして下さい。

$ brew install go
$ go version
go version go1.10.3 darwin/amd64

Go用の環境変数

Goを使うための環境変数を設定します。既に設定済みの場合は適時読み替えて下さい。

~/.bash_profile
export GOROOT=/usr/local/opt/go/libexec
export GOPATH=$HOME/go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin

環境変数を反映させます。

$ source ~/.bash_profile

depのインストール

Goのパッケージ管理はdepを使用します。ここではbrewからインストールしています。

$ brew install dep
$ dep version
dep:
 version     : v0.4.1
 build date  : 2018-01-27
 git hash    : 37d9ea0
 go version  : go1.9.3
 go compiler : gc
 platform    : darwin/amd64

プロジェクトディレクトリの作成

$ mkdir ${HOME}/go/src/projects
$ mkdir connpass-search
$ cd connpass-search

GoとEchoによるAPIサーバーの作成

まず、BackendとなるAPIサーバーを作成します。

GoのWeb Frameworkであるechoを使用して、Routing、CORS(Cross-Origin Resource Sharing)、Staticサイトのホスティングなどを行います。

echo - github

ローカル環境用のenvファイルを作成

プロジェクトのルートディレクトリに.env.developmentを作成します。

$ touch .env.development

$ tree -a
.
└── .env.development

開発時にローカルのAPIサーバーがポート8081で起動するように指定します。
使用中の場合は別のポート番号を指定することも可能です。

connpass-search/.env.development
PORT=8081

本番環境か開発環境かどうかの判定に使用する環境変数GO_RUN_ENVdevelopmentを設定しておきます。GO_RUN_ENVは任意の環境変数名ですので変更することも可能です。

APIサーバーを起動する前に毎回環境変数を設定するのは面倒なので、以下のように.bash_profileへ設定するのが良いと思います。

~/.bash_profile
GO_RUN_ENV='development'
export GO_RUN_ENV

環境変数を反映させます。

$ source ~/.bash_profile

server.goの作成

server.goのファイルを作成します。
次に、depの初期化を行ってGopkg.tomlGopkg.lockファイルを作成します。

$ touch server.go
$ dep init

$ tree -a
.
├── .env.development
├── Gopkg.lock
├── Gopkg.toml
├── server.go
└── vendor

dep initコマンド実行直後のGopkg.tomlは以下のようになっています。

connpass-search/Gopkg.toml
[prune]
  go-tests = true
  unused-packages = true

server.goには、APIへのリクエストがあったら、ベースURLをconnpass APIのドメインへ置き換え、Pathとクエリ文字列をそのまま付け替えてGETリクエストを行います。そして、connpass APIからのレスポンス(JSON)をそのまま返すAPIサーバーを書きます。

また、後ほど出てきますがyarn buildで生成した/dist以下のディレクトリの静的ファイルへのパスを設定します。

connpass-search/server.go
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "os"

    "github.com/joho/godotenv"
    "github.com/labstack/echo"
    "github.com/labstack/echo/middleware"
)

func main() {
    // Echo instance
    e := echo.New()

    // Middleware
    e.Use(middleware.Logger())
    e.Use(middleware.Recover())
    e.Use(middleware.Gzip())

    // CORS restricted
    e.Use(middleware.CORSWithConfig(middleware.CORSConfig{
        AllowOrigins: []string{"*"},
        AllowHeaders: []string{echo.HeaderOrigin, echo.HeaderContentType, echo.HeaderAccept},
        AllowMethods: []string{echo.GET},
    }))

    // yarn buildで生成された静的ファイルへのパスを設定する
    e.Static("/", "dist")

    // Routes
    // ローカルAPIへのアクセスをconnpass APIへフォワードする
    connpassAPI := e.Group("/api/v1")
    {
        connpassAPI.GET("/event/", ConnpassAPIRequest())
    }

    // 開発時は以下の環境変数の設定が必要
    // GO_RUN_ENV='development'
    // export GO_RUN_ENV
    if os.Getenv("GO_RUN_ENV") == "" {
        // Start server on Production
        e.Logger.Fatal(e.Start(":" + os.Getenv("PORT")))
    } else {
        // .env.development: For Development
        // .env.test: For Test
        err := godotenv.Load(fmt.Sprintf(".env.%s", os.Getenv("GO_RUN_ENV")))
        if err != nil {
            log.Fatal("Error loading .env file")
        } else {
            // Start server on TEST or Development
            e.Logger.Fatal(e.Start(":" + os.Getenv("PORT")))
        }
    }
}

// ConnpassAPIRequest handles API call
func ConnpassAPIRequest() echo.HandlerFunc {
    return func(c echo.Context) error {

        baseURL := "https://connpass.com"

        // リクエストURLのPathとクエリ文字列を取得する
        path := c.Request().URL.RequestURI()

        // ベースURLをconnpass APIのドメインへ変更し、URLのPathとクエリ文字列を付け替える
        url := baseURL + path

        resp, err := http.Get(url)
        if err != nil {
            return err
        }
        defer resp.Body.Close()
        byteArray, _ := ioutil.ReadAll(resp.Body)

        // connpass APIからのレスポンスを文字列で呼び出し元へ返す
        return c.String(http.StatusOK, string(byteArray))
    }
}

os.Getenv("GO_RUN_ENV")developmentの文字列が取得出来たら.env.developmentからポート番号を読み取り、空文字だったらHeroku上で取得出来るランダムなポート番号がAPIサーバーへ割り当てられるという処理になっています。

depを使用した依存関係管理

dep ensureを実行して依存関係のあるパッケージをインストールします。
ローカルで実行する時のパッケージはconnpass-search/vendor以下に保存されます。

ここではGopkg.tomlgodotenvechoのバージョンを明示的に指定しています。

Gopkg.toml
### 追記 ###
[[constraint]]
  name = "github.com/joho/godotenv"
  version = "1.2.0"

[[constraint]]
  name = "github.com/labstack/echo"
  version = "3.3.5"
### 追記 ###

[prune]
  go-tests = true
  unused-packages = true

$ dep ensure

# vendor以下にパッケージがダウンロードされる
$ tree -d -L 4
.
└── vendor
    ├── github.com
    │   ├── dgrijalva
    │   │   └── jwt-go
    │   ├── joho
    │   │   └── godotenv
    │   ├── labstack
    │   │   ├── echo
    │   │   └── gommon
    │   ├── mattn
    │   │   ├── go-colorable
    │   │   └── go-isatty
    │   └── valyala
    │       ├── bytebufferpool
    │       └── fasttemplate
    └── golang.org
        └── x
            ├── crypto
            └── sys

Heroku用の設定を追加

Heroku上でも依存関係にあるパッケージを出来るようにするためにGopkg.tomlへ以下の設定を追記します。root-packageは筆者のものですので、別途自分用のリポジトリを作成して指定して下さい。

この設定により、アプリケーション配置時にHeroku側で自動でdep ensureが実行されます。

Gopkg.toml
[metadata.heroku]
  root-package = "github.com/takayamag/connpass-search"
  go-version = "go1.10.3"
  install = [ ".", "./cmd/..." ]
  ensure = "true"

APIサーバーの起動

作成したAPIサーバーを.env.developmentで指定したポート番号8081を使用して起動します。

$ go run server.go

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.dev
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8081

ちなみに、COMMAND+Cで停止出来ます。

Vue.js

次にFrontEndのVue.jsを作成していきます。コードを全て載せると記事がかなり長くなってしまうので端折っていきます。

node.jsが必要になるので、ここではbrewを使ったインストール方法を記載します。

brew install node
$ node --version
v10.5.0

次に、パッケージ管理のためにyarnをインストールします。npmを使用する場合は適時読み替えて下さい。

$ brew install yarn
$ yarn --version
1.7.0

RC版ですが、Vue-CLI 3.0を使用します。

$ yarn global add @vue/cli
$ vue -V
3.0.0-rc.3

ここではconnpass-searchという名前のアプリケーションにしたいと思います。
質問には以下のように答えていきます。

$ cd ${HOME}/go/src/projects
$ vue init webpack connpass-search

アプリケーションのディレクトリconnpass-searchは作成済みなので、Target directory exists. Continue?と聞かれますがYesと入力します。

また、ESLint、unit tests、test runner、e2eはこの記事では触れないため任意です。

? Target directory exists. Continue? Yes
? Project name connpass-search
? Project description A Vue.js project
? Author author@example.com
? Vue build standalone
? Install vue-router? Yes
? Use ESLint to lint your code? Yes
? Pick an ESLint preset Standard
? Set up unit tests Yes
? Pick a test runner jest
? Setup e2e tests with Nightwatch? Yes
? Should we run `npm install` for you after the project has been created? (recommended) yarn

   vue-cli · Generated "connpass-search".


# Installing project dependencies ...
# ========================

yarn install v1.7.0
info No lockfile found.
[1/5] 🔍  Validating package.json...
[2/5] 🔍  Resolving packages...
⠁ (node:67593) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
warning jest > jest-cli > istanbul-api > istanbul-lib-hook@1.2.1: 1.2.0 should have been a major version bump
warning nightwatch > proxy-agent > socks-proxy-agent > socks@1.1.10: If using 2.x branch, please upgrade to at least 2.1.6 to avoid a serious bug with socket data flow and an import issue introduced in 2.1.0
warning webpack-bundle-analyzer > bfj-node4@5.3.1: Switch to the `bfj` package for fixes and new features!
[3/5] 🚚  Fetching packages...
[4/5] 🔗  Linking dependencies...
[5/5] 📃  Building fresh packages...
success Saved lockfile.
✨  Done in 28.14s.


Running eslint --fix to comply with chosen preset rules...
# ========================

yarn run v1.7.0
$ eslint --ext .js,.vue src test/unit test/e2e/specs --fix
✨  Done in 1.77s.

# Project initialization finished!
# ========================

To get started:

  cd connpass-search
  npm run dev

Documentation can be found at https://vuejs-templates.github.io/webpack

以下のようにディレクトリやファイルが配置されます。

$ cd connpass-search
$ tree -a -L 1
.
├── .babelrc
├── .editorconfig
├── .env.development
├── .eslintignore
├── .eslintrc.js
├── .gitignore
├── .postcssrc.js
├── Gopkg.lock
├── Gopkg.toml
├── README.md
├── build
├── config
├── index.html
├── package.json
├── server.go
├── src
├── static
├── test
└── vendor

パッケージのインストール

yarn installを実行します。

$ yarn install
# または、yarn

開発サーバーの起動

パッケージのインストール完了後、yarn devで開発サーバーを起動すると、http://localhost:8080にアクセス出来るようになります。

Welcome to Your Vue.js Appと書かれているページが開けばOKです。

$ yarn dev

ちなみに、COMMAND+Cで停止出来ます。

パッケージの追加

以下のコマンドでインストールしたパッケージはnode_modules以下に保存されます。

$ yarn add axios
$ yarn add element-ui
$ yarn add lodash-es
$ yarn add moment
$ yarn add vuex
$ yarn add es6-promise

開発時はローカル上のAPIサーバーを参照するようにconfig/dev.env.jsを以下のように記述します。ポート番号は8081でなくても良いですが.env.developmentの記載したポート番号と一致させます。

connpass-search/config/dev.env.js
module.exports = merge(prodEnv, {
  NODE_ENV: '"development"',
  API_ENDPOINT: '"http://localhost:8081"'
})

config/prod.env.jsには本番環境のURLを記述します。ここではconnpass-search.herokuapp.comとなっていますが、ご自身で取得したHerokuアプリケーションのURLを指定して下さい。

connpass-search/config/prod.env.js
module.exports = {
  NODE_ENV: '"production"',
  API_ENDPOINT: '"https://connpass-search.herokuapp.com"'
}

どちらもAPI_ENDPOINTの行を追加する時は、前の行の末尾に半角カンマを入れ忘れないように注意して下さい。

本番環境の場合、アプリケーション配置時にHeroku側で自動でyarn builddep ensureを実行するため、/dist/vendorディレクトリをリポジトリへアップロードしないように.gitignoreへ記述します。

connpass-search/.gitignore
# /dist/ は元々存在すると思います
/dist/
/vendor/

package.jsonファイルの中から"scripts"を探し、"postinstall": "yarn build"を追記します。(前の行の末尾に,を付け忘れないようにして下さい)

これにより、アプリケーション配置時にHeroku側で自動でyarn buildが実行され、/dist以下にビルドされたファイルが配置されます。

connpass-search/package.json
"scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "unit": "jest --config test/unit/jest.conf.js --coverage",
    "e2e": "node test/e2e/runner.js",
    "test": "npm run unit && npm run e2e",
    "lint": "eslint --ext .js,.vue src test/unit test/e2e/specs",
    "build": "node build/build.js",
    "postinstall": "yarn build"
  },

src/main.jsにはElementUIとVuexストアを使用するための設定を記述します。

connpass-search/src/main.js
import 'es6-promise/auto'
import Vue from 'vue'
import App from './App'
import router from './router'
import store from './store'

// Element のライブラリを使用する
// http://element.eleme.io/#/en-US
import ElementUI from 'element-ui'
import 'element-ui/lib/theme-chalk/index.css'
import ElementUIJaLocale from 'element-ui/lib/locale/lang/ja'
Vue.use(ElementUI, { ElementUIJaLocale })

Vue.config.productionTip = false

/* eslint-disable no-new */
new Vue({
  el: '#app',
  store,
  router,
  components: { App },
  template: '<App/>'
})

モジュール化したVuexストアを指定します。

connpass-search/src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import event from '@/store/modules/event'

Vue.use(Vuex)

const mode = process.env.NODE_ENV !== 'production'

export default new Vuex.Store({
  modules: {
    event
  },
  strict: mode,
  plugins: []
})

connpassApi.jsではAPIサーバーへのリクエストを行なっています。

複数キーワードをカンマで区切ったり、AND/OR検索の判定を行なったり、キーワードへの都道府県名追加などが必要なため、リクエストを投げる前に状態をチェックしてパラメータを構築しています。

connpass-search/src/api/connpassApi.js
import axios from 'axios'

// APIのENDPOINTのURLをDev環境とProd環境とで切り替えられるようにする
const API_BASE_PATH = process.env.API_ENDPOINT

export default {
  getItems (params, searchMode, prefecture) {
    // connpass API リファレンスによると、複数キーワードは以下のように指定する必要があるため
    // 「name=value1,value2...」の指定が出来るように「params.keyword」を整形する
    // 指定方法: パラメータを複数指定する場合は、 name=value1&name=value2&... または name=value1,value2...
    let temp = []
    // キーワード検索文字列を半角スペース区切りで配列に格納する
    if (params.keyword !== '') {
      /* eslint no-irregular-whitespace: ["error", {"skipRegExps": true}] */
      temp = params.keyword.replace(/ /g, ' ').split(' ')
    }
    // connpass APIには都道府県を受け入れるパラメータが無いため
    // 苦肉の策でキーワード検索のパラメータとして都道府県名を追加する
    if (prefecture !== '') {
      temp.push(prefecture)
    }

    // 半角カンマ区切りのキーワード検索のパラメータを作成する
    let keywords = temp.join(',')

    // 検索結果の何件目から出力するかを指定
    let startItem = params.start
    if (params.start > 1) {
      startItem = (params.start - 1) * params.count + 1
    }

    // axiosのGETリクエストのパラメータをセットする
    let queryString = {
      count: params.count,
      start: startItem,
      ym: params.ym,
      order: params.order,
      format: params.format
    }

    // connpass APIの仕様に合わせてAND検索とOR検索でパラメータ名を変更する
    let defaultSearchKey = 'keyword'
    if (searchMode === 2) { // OR検索
      defaultSearchKey += '_or'
    }
    queryString[defaultSearchKey] = keywords

    return axios.get(`${API_BASE_PATH}/api/v1/event/?`, {
      params: queryString
    })
  }
}

省略した内容

Vue.jsのファイル群は以下のようになります。環境設定部分を除いて説明を省略しているので、必要でしたらソースの方をご覧下さい。

GitHub:
https://github.com/takayamag/connpass-search/tree/master/src

connpass-search/src
$ tree
.
├── App.vue
├── api
│   └── connpassApi.js
├── components
│   ├── EventList.vue
│   ├── HelloWorld.vue
│   ├── InputKeyword.vue
│   ├── PaginationModule.vue
│   ├── SearchPage.vue
│   ├── SelectPrefecture.vue
│   ├── SelectResultOrder.vue
│   ├── SelectSearchMode.vue
│   └── SelectTargetMonth.vue
├── main.js
├── router
│   └── index.js
└── store
    ├── index.js
    ├── initialState
    │   └── itemList.js
    ├── modules
    │   └── event.js
    └── mutation-types.js

FrontEndとBackEndの構築が完了すると、以下のコマンドでアプリケーションが動作するようになるはずです。

開発環境のアプリケーションの起動

BackEnd

$ go run server.go

   ____    __
  / __/___/ /  ___
 / _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.5
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
                                    O\
⇨ http server started on [::]:8081

FrontEnd

$ yarn dev
yarn run v1.7.0
$ webpack-dev-server --inline --progress --config build/webpack.dev.conf.js

[ DONE ] Compiled successfully in 9050ms                                                                                                                                      
[ I ] Your application is running here: http://localhost:8080

ブラウザーを起動してhttp://localhost:8080を開くと、以下のような画面が開くと思います。なお、APIサーバーへ正しく接続出来ていないとLoadingが終わりません。

開発環境の画面

APIサーバーへ正しく接続出来ていると、以下のようにechoのログがリアルタイムで出力されていきます。

{"time":"2018-07-02T15:57:14.591144845+09:00","id":"","remote_ip":"::1","host":"localhost:8081","method":"GET","uri":"/api/v1/event/?&count=10&start=1&ym=201807&order=2&format=json&keyword=%E6%9D%B1%E4%BA%AC%E9%83%BD","status":200, "latency":3369362874,"latency_human":"3.369362874s","bytes_in":0,"bytes_out":88099}

Herokuへアプリケーションを配置する

ここでは、開発したアプリケーションをHeroku上で動作するように設定を行なっていきます。Herokuのアカウントが必要ですので必要に応じて取得して下さい。

Heroku:
https://jp.heroku.com

また、Heroku CLIを使用するのでbrewでインストールします。

$ brew install heroku
heroku version
heroku/7.5.7 darwin-x64 node-v10.5.0

Herokuへログインします。

$ heroku login

Email: hoge@example.com
Password: ***********
Logged in as hoge@example.com

次に、Heroku上へアプリケーションを作成します。ここで指定するアプリケーション名は{アプリケーション名}.herokuapp.comとアプリケーションのドメイン名にもなりますので、他と被らないようにする必要があります。

$ heroku create connpass-search
Creating ⬢ connpass-search... done
https://connpass-search.herokuapp.com/ | https://git.heroku.com/connpass-search.git

Herokuのリモートリポジトリをセットします。

heroku git:remote --app connpass-search
set git remote heroku to https://git.heroku.com/connpass-search.git

Herokuの環境変数をセットします。YARN_PRODUCTION=falseとすると
package.jsondependenciesだけでなく、devDependenciesもインストールされるのですが、余計な依存関係も含まれてしまいます。ここでは深追いせずにこの設定で進めたいと思います。

$heroku config:set YARN_PRODUCTION=false
# $ heroku config:set NPM_CONFIG_PRODUCTION=false YARN_PRODUCTION=false

$ heroku config
=== connpass-search Config Vars
YARN_PRODUCTION: false

Heroku上でnode.jsgoを動作させる必要があるため、それぞれのbuildpackを設定します。

$ heroku buildpacks:add heroku/go --app connpass-search
$ heroku buildpacks:add heroku/nodejs --app connpass-search

$ heroku buildpacks
=== connpass-search Buildpack URLs
1. heroku/nodejs
2. heroku/go

全ての準備が整ったら、Herokuのmasterブランチにアプリケーションをpushします。

Go app detectedのあとにdep ensureが行われ、Node.js app detectedの後にyarn buildが行われてパッケージがインストールされているのがポイントです。

また、事前にProcfileを作成してpushしなくても、今回の場合はHeroku側で自動で作成されるようです。

$ git push heroku master
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Delta compression using up to 4 threads.
Compressing objects: 100% (8/8), done.
Writing objects: 100% (8/8), 1.09 KiB | 1.09 MiB/s, done.
Total 8 (delta 6), reused 0 (delta 0)
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Go app detected
remote: -----> Using go1.10.3
remote: -----> Fetching any unsaved dependencies (dep ensure)
remote: -----> Running: go install -v -tags heroku . ./cmd/...
remote: warning: "./cmd/..." matched no packages
remote: github.com/takayamag/connpass-search/vendor/github.com/joho/godotenv
remote: github.com/takayamag/connpass-search/vendor/github.com/mattn/go-isatty
remote: github.com/takayamag/connpass-search/vendor/github.com/mattn/go-colorable
remote: github.com/takayamag/connpass-search/vendor/github.com/valyala/bytebufferpool
remote: github.com/takayamag/connpass-search/vendor/github.com/labstack/gommon/color
remote: github.com/takayamag/connpass-search/vendor/github.com/valyala/fasttemplate
remote: github.com/takayamag/connpass-search/vendor/github.com/labstack/gommon/log
remote: github.com/takayamag/connpass-search/vendor/golang.org/x/crypto/acme
remote: github.com/takayamag/connpass-search/vendor/github.com/dgrijalva/jwt-go
remote: github.com/takayamag/connpass-search/vendor/github.com/labstack/gommon/bytes
remote: github.com/takayamag/connpass-search/vendor/github.com/labstack/gommon/random
remote: github.com/takayamag/connpass-search/vendor/golang.org/x/crypto/acme/autocert
remote: github.com/takayamag/connpass-search/vendor/github.com/labstack/echo
remote: github.com/takayamag/connpass-search/vendor/github.com/labstack/echo/middleware
remote: github.com/takayamag/connpass-search
remote: -----> Node.js app detected
remote:
remote: -----> Creating runtime environment
remote:
remote:        NPM_CONFIG_LOGLEVEL=error
remote:        YARN_PRODUCTION=false
remote:        NODE_VERBOSE=false
remote:        NODE_ENV=production
remote:        NODE_MODULES_CACHE=true
remote:
remote: -----> Installing binaries
remote:        engines.node (package.json):  >= 6.0.0
remote:        engines.npm (package.json):   >= 3.0.0
remote:        engines.yarn (package.json):  unspecified (use default)
remote:
remote:        Resolving node version >= 6.0.0...
remote:        Downloading and installing node 10.5.0...
remote:        Bootstrapping npm >= 3.0.0 (replacing 6.1.0)...
remote:        npm 6.1.0 installed
remote:        Resolving yarn version 1.x...
remote:        Downloading and installing yarn (1.8.0)...
remote:        Installed yarn 1.8.0
remote:
remote: -----> Restoring cache
remote:        Loading 2 from cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (not cached - skipping)
remote:
remote: -----> Building dependencies
remote:        Installing node modules (yarn.lock)
remote:        yarn install v1.8.0
remote:        [1/4] Resolving packages...
remote:        [2/4] Fetching packages...
remote:        (node:928) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
remote:        info fsevents@1.2.4: The platform "linux" is incompatible with this module.
remote:        info "fsevents@1.2.4" is an optional dependency and failed compatibility check. Excluding it from installation.
remote:        [3/4] Linking dependencies...
remote:        [4/4] Building fresh packages...
remote:        $ yarn build
remote:        yarn run v1.8.0
remote:        $ node build/build.js
remote:        Hash: 50cb2aba39cc8c0025da
remote:        Version: webpack 3.12.0
remote:        Time: 42966ms
remote:        Asset       Size  Chunks                    Chunk Names
remote:        static/fonts/element-icons.6f0a763.ttf      11 kB          [emitted]
remote:        static/js/vendor.4c427f2baffeaa920370.js    1.08 MB       0  [emitted]  [big]  vendor
remote:        static/js/app.2096c43b7ebeae96d4aa.js    20.3 kB       1  [emitted]         app
remote:        static/js/manifest.2ae2e69a05c33dfc65f8.js  857 bytes       2  [emitted]         manifest
remote:        static/css/app.c81c3399898dd225f98ecdc43d897614.css     190 kB       1  [emitted]         app
remote:        static/css/app.c81c3399898dd225f98ecdc43d897614.css.map     275 kB          [emitted]
remote:        static/js/vendor.4c427f2baffeaa920370.js.map    4.61 MB       0  [emitted]         vendor
remote:        static/js/app.2096c43b7ebeae96d4aa.js.map    91.4 kB       1  [emitted]         app
remote:        static/js/manifest.2ae2e69a05c33dfc65f8.js.map    4.97 kB       2  [emitted]         manifest
remote:        index.html  509 bytes          [emitted]
remote:
remote:        Build complete.
remote:
remote:        Tip: built files are meant to be served over an HTTP server.
remote:        Opening index.html over file:// won't work.
remote:
remote:        Done in 45.19s.
remote:        Done in 68.19s.
remote:
remote: -----> Caching build
remote:        Clearing previous node cache
remote:        Saving 2 cacheDirectories (default):
remote:        - node_modules
remote:        - bower_components (nothing to cache)
remote:
remote: -----> Pruning devDependencies
remote:        Skipping because YARN_PRODUCTION is 'false'
remote:
remote: -----> Build succeeded!
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 86.3M
remote: -----> Launching...
remote:        Released v12
remote:        https://connpass-search.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/connpass-search.git
   2961417..f1d1742  master -> master

deployが完了したらHeroku上のアプリケーションにアクセスしてみます。
なお、アプリケーションがスリープしていると起動に時間がかかります。また、月当たりの無料時間分を使い切るとアクセス出来なくなります。
https://connpass-search.herokuapp.com/

Heroku上の画面

おまけ: よく使うHerokuのコマンド

# 環境変数の状態を確認する
$ heroku config
=== connpass-search Config Vars
YARN_PRODUCTION: false

# buildpackの状態を確認する
$ heroku buildpacks
=== connpass-search Buildpack URLs
1. heroku/go
2. heroku/nodejs

# プロセスや無料で使える残り時間の状態を確認する
$ heroku ps
Free dyno hours quota remaining this month: 540h 40m (98%)
For more information on dyno sleeping and how to upgrade, see:
https://devcenter.heroku.com/articles/dyno-sleeping

=== web (Free): connpass-search (1)
web.1: up 2018/07/05 16:12:14 +0900

# Bashを実行する
$ heroku run bash

Running bash on ⬢ connpass-search... up, run.7276 (Free)
~ $ ls -alt # Unix系のコマンドが使用できる

# 自動作成された`Procfile`ファイル
~ $ cat Procfile
web: connpass-search

~ $ exit # 終了する時は`exit`コマンドを実行する

アプリケーションのログは以下のコマンドでリアルタイムで確認することが出来ます。
(IPアドレスとポート番号はマスクしていますが、あまり意味が無いような気もする)

$ heroku logs --tail --app connpass-search

2018-07-02T07:04:28.720034+00:00 heroku[web.1]: State changed from down to starting
2018-07-02T07:04:36.621153+00:00 heroku[web.1]: Starting process with command `connpass-search`
2018-07-02T07:04:38.521698+00:00 app[web.1]:
2018-07-02T07:04:38.521726+00:00 app[web.1]: ____    __
2018-07-02T07:04:38.521728+00:00 app[web.1]: / __/___/ /  ___
2018-07-02T07:04:38.521730+00:00 app[web.1]: / _// __/ _ \/ _ \
2018-07-02T07:04:38.521732+00:00 app[web.1]: /___/\__/_//_/\___/ v3.3.5
2018-07-02T07:04:38.521734+00:00 app[web.1]: High performance, minimalist Go web framework
2018-07-02T07:04:38.521736+00:00 app[web.1]: https://echo.labstack.com
2018-07-02T07:04:38.521737+00:00 app[web.1]: ____________________________________O/_______
2018-07-02T07:04:38.521739+00:00 app[web.1]: O\
2018-07-02T07:04:38.521809+00:00 app[web.1]: ⇨ http server started on [::]:XXXXX
2018-07-02T07:04:40.253924+00:00 heroku[web.1]: State changed from starting to up
2018-07-02T07:04:40.821638+00:00 heroku[router]: at=info method=GET path="/" host=connpass-search.herokuapp.com request_id=8b349f4d-0299-447d-ae90-548016a5812b fwd="XXX.XXX.XXX.XXX" dyno=web.1 connect=1ms service=5ms status=200 bytes=640 protocol=https
2018-07-02T07:04:40.819568+00:00 app[web.1]: {"time":"2018-07-02T07:04:40.819433446Z","id":"8b349f4d-0299-447d-ae90-548016a5812b","remote_ip":"XXX.XXX.XXX.XXX","host":"connpass-search.herokuapp.com","method":"GET","uri":"/","status":200, "latency":3703807,"latency_human":"3.703807ms","bytes_in":0,"bytes_out":523}
2018-07-02T07:04:42.828767+00:00 heroku[router]: at=info method=GET path="/static/js/vendor.b660bebb9ffa3dd22816.js" host=connpass-search.herokuapp.com request_id=2d1555a0-a8a8-4468-a89b-4972a98698c7 fwd="XXX.XXX.XXX.XXX" dyno=web.1 connect=0ms service=70ms status=200 bytes=308786 protocol=https
2018-07-02T07:04:42.826670+00:00 app[web.1]: {"time":"2018-07-02T07:04:42.826590301Z","id":"2d1555a0-a8a8-4468-a89b-4972a98698c7","remote_ip":"XXX.XXX.XXX.XXX","host":"connpass-search.herokuapp.com","method":"GET","uri":"/static/js/vendor.b660bebb9ffa3dd22816.js","status":200, "latency":68898772,"latency_human":"68.898772ms","bytes_in":0,"bytes_out":1107200}
2018-07-02T07:04:43.425552+00:00 heroku[router]: at=info method=GET path="/static/js/manifest.2ae2e69a05c33dfc65f8.js" host=connpass-search.herokuapp.com request_id=bb8d93a3-d3aa-400d-8a7d-c40678d675ba fwd="XXX.XXX.XXX.XXX" dyno=web.1 connect=0ms service=16ms status=200 bytes=795 protocol=https
2018-07-02T07:04:43.435036+00:00 heroku[router]: at=info method=GET path="/static/js/app.3367294b908d753c3e7d.js" host=connpass-search.herokuapp.com request_id=79f90bbe-cb00-43b9-87e8-bb0dd9ad67ed fwd="XXX.XXX.XXX.XXX" dyno=web.1 connect=0ms service=3ms status=200 bytes=7186 protocol=https
2018-07-02T07:04:43.442224+00:00 heroku[router]: at=info method=GET path="/static/css/app.c81c3399898dd225f98ecdc43d897614.css" host=connpass-search.herokuapp.com request_id=4d612002-1f93-45cc-919e-ddc072e2664a fwd="XXX.XXX.XXX.XXX" dyno=web.1 connect=1ms service=14ms status=200 bytes=37087 protocol=https
2018-07-02T07:04:43.420165+00:00 app[web.1]: {"time":"2018-07-02T07:04:43.420069781Z","id":"bb8d93a3-d3aa-400d-8a7d-c40678d675ba","remote_ip":"XXX.XXX.XXX.XXX","host":"connpass-search.herokuapp.com","method":"GET","uri":"/static/js/manifest.2ae2e69a05c33dfc65f8.js","status":200, "latency":12042852,"latency_human":"12.042852ms","bytes_in":0,"bytes_out":857}
2018-07-02T07:04:43.433123+00:00 app[web.1]: {"time":"2018-07-02T07:04:43.433050134Z","id":"79f90bbe-cb00-43b9-87e8-bb0dd9ad67ed","remote_ip":"XXX.XXX.XXX.XXX","host":"connpass-search.herokuapp.com","method":"GET","uri":"/static/js/app.3367294b908d753c3e7d.js","status":200, "latency":2001191,"latency_human":"2.001191ms","bytes_in":0,"bytes_out":21367}
2018-07-02T07:04:43.436573+00:00 app[web.1]: {"time":"2018-07-02T07:04:43.436509396Z","id":"4d612002-1f93-45cc-919e-ddc072e2664a","remote_ip":"XXX.XXX.XXX.XXX","host":"connpass-search.herokuapp.com","method":"GET","uri":"/static/css/app.c81c3399898dd225f98ecdc43d897614.css","status":200, "latency":11308082,"latency_human":"11.308082ms","bytes_in":0,"bytes_out":189725}
2018-07-02T07:04:47.812564+00:00 app[web.1]: {"time":"2018-07-02T07:04:47.81247741Z","id":"aa3ff33c-3de2-4f2c-820e-41d366815573","remote_ip":"XXX.XXX.XXX.XXX","host":"connpass-search.herokuapp.com","method":"GET","uri":"/api/v1/event/?&count=10&start=1&ym=201807&order=2&format=json&keyword=%E6%9D%B1%E4%BA%AC%E9%83%BD","status":200, "latency":1359262979,"latency_human":"1.359262979s","bytes_in":0,"bytes_out":88099}
2018-07-02T07:04:47.814885+00:00 heroku[router]: at=info method=GET path= "/api/v1/event/?&count= 10&start= 1&ym= 201807&order= 2&format= json&keyword=%E6%9D%B1%E4%BA%AC%E9%83%BD" host=connpass-search.herokuapp.com request_id=aa3ff33c-3de2-4f2c-820e-41d366815573 fwd="XXX.XXX.XXX.XXX" dyno=web.1 connect=0ms service=1361ms status=200 bytes=19624 protocol=https

まとめ

Vue.jsと戯れてはみたのですが、そのVue.jsの部分はほとんどカットするという謎の記事になりました。

苦労したのはローカルで開発しているVue.jsとGoの組み合わせのアプリケーションを、そのままの内容でHerokuへDeployして実行出来るようにすることです。

それを両立させる構成と設定が決まるまでにかなり多くの時間を使ったような気がしますが、ちゃんと動いた時は喜びもひとしおでしたね。

Vue.jsはガチなプログラマーじゃなくても動きのあるWebサイト作成にチャレンジしやすいのが良いですね。本格的にやるのならVue.jsを学ぶ過程で「知りたい」と思うことの多くが解説されている「基礎から学ぶ Vue.js」をオススメします。

基礎から学ぶ Vue.js
https://www.amazon.co.jp/dp/4863542453

また、Go言語の方は学習を始めたばかりなので、色々出来ることを増やしていきたいと思います。シンプルな構文とオートフォーマットのおかげで学びやすそうな気がしています。

takayamag
おそらくどこにでもいそうなQAエンジニア。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away