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などのリポジトリのアカウントを持っていること
使用するツールやライブラリ
使用するツールやライブラリ類は以下のようになります。開発時はなるべく最新版を使用するようにしていますが、日々アップデートが行われますので記載した内容は最新版ではない可能性があります。
-
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
を使うための環境変数を設定します。既に設定済みの場合は適時読み替えて下さい。
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サイトのホスティングなどを行います。
ローカル環境用のenvファイルを作成
プロジェクトのルートディレクトリに.env.development
を作成します。
$ touch .env.development
$ tree -a
.
└── .env.development
開発時にローカルのAPIサーバーがポート8081
で起動するように指定します。
使用中の場合は別のポート番号を指定することも可能です。
PORT=8081
本番環境か開発環境かどうかの判定に使用する環境変数GO_RUN_ENV
にdevelopment
を設定しておきます。GO_RUN_ENV
は任意の環境変数名ですので変更することも可能です。
APIサーバーを起動する前に毎回環境変数を設定するのは面倒なので、以下のように.bash_profile
へ設定するのが良いと思います。
GO_RUN_ENV='development'
export GO_RUN_ENV
環境変数を反映させます。
$ source ~/.bash_profile
server.goの作成
server.go
のファイルを作成します。
次に、dep
の初期化を行ってGopkg.toml
やGopkg.lock
ファイルを作成します。
$ touch server.go
$ dep init
$ tree -a
.
├── .env.development
├── Gopkg.lock
├── Gopkg.toml
├── server.go
└── vendor
dep init
コマンド実行直後のGopkg.toml
は以下のようになっています。
[prune]
go-tests = true
unused-packages = true
server.go
には、APIへのリクエストがあったら、ベースURLをconnpass APIのドメインへ置き換え、Pathとクエリ文字列をそのまま付け替えてGETリクエストを行います。そして、connpass APIからのレスポンス(JSON)をそのまま返すAPIサーバーを書きます。
また、後ほど出てきますがyarn build
で生成した/dist
以下のディレクトリの静的ファイルへのパスを設定します。
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.toml
にgodotenv
とecho
のバージョンを明示的に指定しています。
### 追記 ###
[[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
が実行されます。
[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
の記載したポート番号と一致させます。
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
API_ENDPOINT: '"http://localhost:8081"'
})
config/prod.env.js
には本番環境のURLを記述します。ここではconnpass-search.herokuapp.com
となっていますが、ご自身で取得したHeroku
アプリケーションのURLを指定して下さい。
module.exports = {
NODE_ENV: '"production"',
API_ENDPOINT: '"https://connpass-search.herokuapp.com"'
}
どちらもAPI_ENDPOINT
の行を追加する時は、前の行の末尾に半角カンマを入れ忘れないように注意して下さい。
本番環境の場合、アプリケーション配置時にHeroku
側で自動でyarn build
とdep ensure
を実行するため、/dist
と/vendor
ディレクトリをリポジトリへアップロードしないように.gitignore
へ記述します。
# /dist/ は元々存在すると思います
/dist/
/vendor/
package.json
ファイルの中から"scripts"
を探し、"postinstall": "yarn build"
を追記します。(前の行の末尾に,
を付け忘れないようにして下さい)
これにより、アプリケーション配置時にHeroku
側で自動でyarn build
が実行され、/dist
以下にビルドされたファイルが配置されます。
"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ストアを使用するための設定を記述します。
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ストアを指定します。
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検索の判定を行なったり、キーワードへの都道府県名追加などが必要なため、リクエストを投げる前に状態をチェックしてパラメータを構築しています。
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
$ 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.json
のdependencies
だけでなく、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.js
とgo
を動作させる必要があるため、それぞれの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 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言語の方は学習を始めたばかりなので、色々出来ることを増やしていきたいと思います。シンプルな構文とオートフォーマットのおかげで学びやすそうな気がしています。