Edited at

Sinatra+Vue.jsでSPA(Hot Module Replacementつき) Take 2

More than 1 year has passed since last update.

Sinatra+Vue.jsでSPAを作っていきます。

以前の記事で「webpack-dev-serverのproxy使えば?」とコメント頂きましたので、それを受けて全面的に書き直しました。(Thank you @nak1114)

完成したコードはこちらで見ることができます。


フロントエンドの準備

yarnを使うので、インストールしていない人はインストールしてください。

vue-cliを使うのでインストールします。

$ yarn global add vue-cli

vue templateを使います。

$ vue init isuke/vuejs-template#v1.0.0 sinatara-vue-sample

isuke/vuejs-templateは著者が、公式のvuejs-templates/webpack-simpleをもとに作ったvue.jsのテンプレートです。

大分改造してあるので原型がおぼろげです。

vue initしたら指示に従って以下のコマンド実行します。

$ yarn install

$ yarn run dev

http://localhost:8080/ をブラウザで開いてみましょう(といか勝手に開きます)。

一行もコードを書かずにこれだけでwebページができていることがわかると思います。

[Bye]リンクをクリックしてページ遷移ができていることも確認してみてください。


サーバーサイドの作成

ここからsinatraを使っていきます。

$ bundle init


Gemfile

# frozen_string_literal: true

source "https://rubygems.org"

ruby '2.4.1'

gem 'sinatra'
gem 'sinatra-contrib'


$ bundle install --path=vendor/bundle

sinatraのコードを書いていきます。


server.rb

require 'sinatra/base'

require "sinatra/reloader"

class Server < Sinatra::Base
configure :development do
register Sinatra::Reloader
end

get '/companies.json' do
companies = []
1.upto(50) do |i|
companies << {
id: i,
name: "Company #{i}"
}
end
companies.to_json
end
end



config.ru

require './server'

run Server


何の変哲もない APIが一つあるだけです。

立ち上げて、確認してみましょう。

$ bundle exec rackup

http://localhost:9292/companies.json

jsonが返ってきました。

次のステップに進みましょう。


フロントとサーバーの連携

フロントはnpm run devでlocalhost:8080

サーバーはbundle exec rackupでlocalhost:9292

にそれぞれアクセスできるようになりました。

これをくっつけましょう。

webpack.config.cofffeeに以下の行を追加します。


webpack.config.cofffee

  else

config = merge baseConfig,
output:
filename: 'build.js'
devtool: '#eval-source-map'
devServer:
contentBase: 'dist'
historyApiFallback: true
noInfo: true
+ proxy:
+ "/api":
+ target: "http://localhost:9292"
+ pathRewrite: {"^/api" : ""}
performance:
hints: false

module.exports = config


サーバーを2つとも立ち上げて http://localhost:8080 を見てみましょう。

$ bundle exec rackup

$ yarn dev

ここでトップページが見れたらOKです。

さて、これでフロントからAPIが叩けるようになったので、ちょっと試してみましょう。

Bye.vueを以下のように書き換えます。

<template lang="pug">

.bye
button(@click="load") load
ul(v-for="company in companies")
li {{company.name}}
router-link(:to="{ name: 'top'}") TOP
</template>

<script lang="coffee">
export default
data: ->
companies: []
methods:
load: ->
axios.get('/api/companies.json')
.then (responce) =>
@companies = responce.data
</script>

[load]ボタンをおしてデータが表示されればOKです。

ついでにHot Module Replacementが動作しているかもためしてみましょう。

Compnayデータが表示された状態でBye.vueのstyleを適当に変えてみてください。

  .bye

-webkit-font-smoothing: antialiased
-moz-osx-font-smoothing: grayscale
text-align: center
margin-top: 60px
+ background-color: red

h1
font-weight: normal
a
color: #42b983

ブラウザを更新せずに反映されたら成功です。

Hot Module Replacementが動作しています。


Productionモードで動かす

最後にProductionでの動かし方です。

まずyarn run buildを実行してsrcディレクトリの中をコンパイルします。

コンパイルした結果はdistに吐かれます。

$ yarn run build

次に、静的ファイル配信用のサーバーを作ります。


static.rb

require 'sinatra/base'

class Static < Sinatra::Base
configure :production do
set :public_dir, File.join(settings.root, 'dist')
end

get '/' do
send_file File.join(settings.public_dir, 'index.html')
end
end


distディレクリをpublicとして公開するディレクトリに指定しています。

また、/にアクセスしたときに、'dist/index.html'を返しています。

static.rbを使うようにconfig.ruを改良しましょう。


cofig.rb

+ require './static'

require './server'

+ if ENV["APP_ENV"] == "production"
+ run Rack::URLMap.new(
+ '/' => Static,
+ '/api' => Server,
+ )
+ else
run Server
+ end


あとは環境変数をつけて実行してあげるだけです。

$ APP_ENV=production bundle exec rackup 

以上です。お疲れ様でした。