search
LoginSignup
1
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

posted at

updated at

段階的にフロントエンド開発 with Vue

段階的にフロントエンド開発 with Vue

by tomlla
1 / 39

この投稿は Shinjuku.rb の発表資料です


@tomlla or @tomlla_92

singlion.jpg


これまでの @tomlla のあらすじ

2012〜
ネットワーク機器開発 c, sh, php, python
target: Linux 2.6系 x86,arm

2014〜
java8 + PlayFramework1 社内システムの開発
(GulpでビルドしてVue+coffeeをやってた)

2016〜
rails(coffee+jquery)
不動産系ベンチャー

2017 〜
java + spring(vue, vue+typescript)
広告出稿系システム

2018.04〜
rails ← いまのジョブはこれ♪


ちなみに 今の案件こんな感じです

  • k8s on GCP
  • CloudSQL
  • ruby 2.5.1, rails 5.2.1 (最近上げた)
  • circleci
  • vuejs(with vue-cli-service)
  • 1万ユーザーくらいの国内向けSaaS
  • IEは対応しない

個人的な課題感

サーバーサイドレンダリングだけだと...

  1. form系
    • 入力フォームでLive Validationしたいよね?
    • ネストした配列を含むフォームのバリデーションつらくない?
    • ユーザーの入力値, バリデーションエラーをサーバー側で再レンダリングするのつらくない?
  2. 大量/大容量のサブリソース
    • 「500ms以下で返せた!やったー?」
    • ↑TTFB後のサブリソース読み込みのこと考えてる?

1.form系問題への取り組み


js object → DOMへの反映

バイディングまじでありがたい 😍

<script>
new Vue({
  data: {
    host: "....",
    allowIPs: [],
  },
  computed: {
    validationErrors() { ... },
  }
});
</script>

<template>
  <input :value="host" />
  <div v-if="hasValidationError" class="error" >
    {{ validationErrors["host"] }}  
  </div>
  <ul>
    <li v-for="(ip, i) in allowIPs" :key="i" >
      <input :value="ip" />
      <div v-if="hasValidationError" class="errors">
        {{ validationErrors["allowIPs"][i] }}
      </div>
    </li>
  </ul>
</template>

サーバーへのpush

  • axiosをつかっています
  • CSRFトークンはrailsのviewsでhtmlに埋め込んでおいたのを使う
axios.defaults.headers.common["X-CSRF-Token"] = document.querySelector(...);
axios.post('/foo/bar', {
  host: this.host,
  allow_ips: this.allowIPs
}
.then(response => {...})
.catch(err=> {...});
  • ActiveRecordやActiveModelのValidationErrorも整形してレスポンスとして返す

メリット:
ユーザーの入力はブラウザに残るので
バリデーションエラーの際、サーバー側で画面再構築しなくてよい😉


まずここまでが第一段階でした


この時点での状況

  • npmやwebpack使わない
  • vueを使いたいページで CDNからvueを読み込み(scriptタグ)
  • 適当なところにidをつけてvue componentをマウント

お手軽!


そしてbinding最高!


  • 自分でDOMごりごり構築しなくてよくなった
  • api で投げるときもDOMではなくjs objectの値をつかえばok!

この段階のDXへの不満

  • unit testできない
  • VueのSFCが使えない
    • scoped cssがつかえない
  • ページごとに使うVue/Axiosのバージョンがばらばらになりやすい..
  • pug/stylus使いたい

加えて...


サブリソース読み込み開始時間をもっとはやくしたい


2. 大量/大容量サブリソース読み込みへの対処


課題をもういちど

あるページのサーバーサイドのレスポンスが500ms以内だとして...

  • そのあとに, CSS, js, img, web-font,などの読み込みが始まる
  • FontAwesomeとか普通に読み込むとかなり大きい

そもそも実際には...

  • 雑につくって放置してデータが増えるとサーバーサイドレスポンスが500msを超える.
    (雑に機能追加して気づかぬうちにN+1など)

  • そのあとにサブリソース読み込みが行われる

↓ということで

一旦htmlを返したあとに、apiから必要コンテンツを取得する方式へ


具体的にどういう構成にしたか


この段階で使いはじめたフロントエンドエコシステム

  • vue cli v3 および vue-cli-service
  • vue-router
  • webpack
  • webpack-dev-server
  • webpack-manifest-plugin
  • html-webpack-plugin

※ vue cli v3のvue-cli-serviceを利用したいためwebpackerは利用せず


サーバーサイド(rails)

  • 既存のページはそのまま
  • 新規 layoutを作成して 改善対象ページだけ新規layoutを使う
    • 外枠のみrailsで返す
    • メインコンテンツはapiで渡す
    • またはgonで渡す

※認証動作はrailsで行い、認可された後のページを今回の改善対象としています


サーバーサイド(rails)

重要だったポイント:

  • webpackでビルドすると複数のファイルが出来上がる
    • ※設定によっていろいろ
  • 今回の設定でビルドされたファイル名にはhashがついている
  • rails側のlayout内で必要なファイルのビルド後のURLを出力する必要がある。

どうするか

案1: webpack-manifest-plugin
もとのファイル名 -> ビルド後のファイル名(フルパス)のmappingをjson出力してくれる

案2: html-webpack-plugn
必要なjs,cssなどを読み込むlinkタグ,scriptタグが含まれたhtmlを生成してくれる


選ばれたのは


petbottle_tea.png


html-webpack-plugn


  • rails起動時にhtml-webpack-pluginの出力するhtmlを読み込む。
    • <head> に配置するlink/scriptタグと、
    • <body> の最下部に配置するlink/scriptタグがある。
  • webpack.rbというクラスを用意しクラスインスタンス変数内に保存
  • scriptタグlinkタグなどをlayoutファイル内の適切な位置に出力

ただし, やっていることがかなりざつなので

できればwebpack manifest pluginを使う方式にしたい

😅😅😅


ブラウザ側の動き

  • vue-routerでパスに対して特定のVue Componentをマウント
  • componentマウント時にメインコンテンツをrailsサーバーから取得
  • 旧layout <=> 新layout のページ遷移では通常のサーバーサイドレンダリング
  • 新layout <=> 新layout のページ遷移ではcompnentの差し替えだけ行う(SPA的動き)

デプロイ時

$ npm run build (or yarn build)
$ RAILS_ENV=production rails assets:precompile
$ RAILS_ENV=production rails s

ずるいけどBefore/After


Before

before.png


After

after.png


まとめ

★ 最近もとめられるUXを満たすためには、
サーバーサイドエコシステムだけだとかなり労力がいる。

★ 先に画面返して、重い処理(DBアクセス)は必要なタイミングで呼び出す方が良いっすよね

結果、webpackはじめフロントエンドエコシステムにどっぷり使うことになるかとは思うんですが


補足: 開発時どうやっているか


起動するプロセスとアクセス先

  • rails + webpack-dev-serverの2つを起動
    • 全部入りdocker-compose.yamlも用意している
  • 画面動作確認は webpack-dev-server側へアクセス
  • webpack-dev-serverの設定でrails側APIに対するリクエストはrailsへプロキシ

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
What you can do with signing up
1
Help us understand the problem. What are the problem?