LoginSignup
10
11

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-09-03

Sinatra+Vue.jsでSPAを作っていきます。
SinatraやVue.jsが初めてという方は
sinatra+vue+webpackで作成したアプリをHerokuで公開する(初心者向け) - Qiita
こちらも合わせてどうぞ。

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

フロントエンドの準備

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

$ npm install -g vue-cli

vue templateを使います。

$ vue init isuke/vuejs-template#v0.8.0 sinatara-vue-sample

isuke/vuejs-templateは著者が、公式のvuejs-templates/webpack-simpleをもとに作ったvue.jsのテンプレートです。
vuejs-templates/webpack-simpleとくらべて以下の違いがります。

  • babelは使わずにcoffeescriptを使う
  • scssは使わずにstylusを使う
  • vue-routerが入っている
  • axiosが入っている

基本的には同じなのでbabelが使いたい方などはvuejs-templates/webpack-simpleを使ってもらっても大丈夫です。

$ yarn # npm installでも可
$ npm run dev

http://localhost:8080/ をブラウザで開いてみましょう。
一行もコードを書かずにこれだけでwebページができていることがわかると思います。
[Bye]リンクをクリックしてページ遷移ができていることも確認してみてください。

サーバーサイドの作成

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

$ bundle init
Gemfile
# frozen_string_literal: true

source "https://rubygems.org"

ruby '2.4.1'

gem 'rack-proxy'
gem 'sinatra'
gem 'sinatra-contrib'
$ bundle install

rack-proxyという見慣れないものがありますが、これは後で説明します。

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

jsonが返ってきました。
次のステップに進みましょう。

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

フロントはnpm run devでlocalhost:8080
サーバーはbundle exec rackupでlocalhost:9292
にそれぞれアクセスできるようになりました。
これをくっつけましょう。

先程のconfig.rurack-proxyをつかって書き換えます。

config.ru
require './server'
require 'rack-proxy'

class AppProxy < Rack::Proxy
  def rewrite_env(env)
    env['HTTP_HOST'] = 'localhost:8080'
    env
  end
end

run Rack::URLMap.new(
 '/api' => Server,
  '/' => AppProxy.new
)

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

$ npm run dev
$ bundle exec rackup

ここでトップページが見れたらOKです。
なぜlocalhost:9292でトップページが見れたのかというと、先程のconfig.ruの設定によりlocalhost:9292がlocalhost:8080にマップされたからですね。

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

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

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">
module.exports = {
  name: 'bye'
  data: ->
    companies: []
  methods:
    load: ->
      axios.get('/api/companies.json')
        .then (responce) =>
          @companies = responce.data
}
</script>

<style lang="stylus">
.bye {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;

  h1 {
    font-weight: normal;
  }

  a {
    color: #42b983;
  }
}
</style>

[load]ボタンを押してデータが表示されていれば成功です。

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

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

  .bye {
    font-family: 'Avenir', Helvetica, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-align: center;
    color: #2c3e50;
    margin-top: 60px;
+   background-color: red;

    h1 {
      font-weight: normal;
    }

    a {
      color: #42b983;
    }
  }

ブラウザを更新せずに反映されたら成功です。
Hot Module Replacementが動作しています。

Productionモードで動かす

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

まずnpm run buildを実行してsrcディレクトリの中をコンパイルします。
コンパイルした結果はdistに吐かれます。

$ npm run build

次にURLが

  • /apiで始まる場合はsinatra server
  • /distで始まる場合はdistディレクトリ
  • /の場合はindex.html

を返すようにconfig.ruを書き換えます。

config.ru
require './server'
require 'rack-proxy'

class Index
  def call(env)
    [
      200,
      { 'Content-Type' => 'text/html' },
      [File.read('./index.html')]
    ]
  end
end

class AppProxy < Rack::Proxy
  def rewrite_env(env)
    env['HTTP_HOST'] = 'localhost:8080'
    env
  end
end

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

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

$ APP_ENV=production bundle exec rackup 

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

参考

10
11
2

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
10
11