Top Banner
プロダクトに 1 から Vue.js を取り入れた話 マーケティング事業の開発現場でリアルに使われるJS事情
69

プロダクトに 1 から Vue.js を導入した話

Jan 21, 2018

Download

Technology

Shohei Okada
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: プロダクトに 1 から Vue.js を導入した話

プロダクトに 1 からVue.js を取り入れた話

マーケティング事業の開発現場でリアルに使われるJS事情

Page 2: プロダクトに 1 から Vue.js を導入した話

岡田 正平(おかだしょうへい)@okashoi

• 開発グループ ソリューションユニット所属

• 2015年にウィルゲートに新卒入社(3年目)

• サーバサイドエンジニア

• PHP / Laravel

• Vue.js をチームに導入した立場のお話をします

2

自己紹介

Page 3: プロダクトに 1 から Vue.js を導入した話

宮西 由貴(みやにしゆうき)

• 開発グループ ソリューションユニット所属

• 2016年にウィルゲートに新卒入社(2年目)

• フロントエンド勉強中

• Vue.js の導入を受けたメンバーの立場からお話をします

3

自己紹介

Page 4: プロダクトに 1 から Vue.js を導入した話

4

ウィルゲートの事業

Page 5: プロダクトに 1 から Vue.js を導入した話

• 前半パート「チームに導入した話」@岡田

• 後半パート「実際に使った話」@宮西

5

構成

Page 6: プロダクトに 1 から Vue.js を導入した話

前半パート:チームに導入した話

Page 7: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入のためにやったこと

3. 良かったこと

4. 学んだこと

5. 今後の展望

7

アジェンダ

Page 8: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入のためにやったこと

3. 良かったこと

4. 学んだこと

5. 今後の展望

8

アジェンダ

Page 9: プロダクトに 1 から Vue.js を導入した話

• 4人チーム(2017年4月1日時点)

• 全員がサーバサイド

• 社内システム開発がメイン

• ロジックの堅牢性が重視される

• 画面はほとんどが動きが無い

• JS は jQuery ベース

• 非同期処理をするのは稀

9

背景 | Vue.js 導入前のチーム状況

Page 10: プロダクトに 1 から Vue.js を導入した話

• 2017年4月から新規プロダクトの開発が始まる

• web コンサルティングのノウハウをシステム化

• 「動きのある」画面が必要になってくる

• 画面操作に応じて Ajax 通信でデータを取得

• 画面操作に応じてグラフを動的に描画

➢ チームとして、リッチな画面をつくる力を付ける必要がある(課題)

10

背景 | きっかけ

Page 11: プロダクトに 1 から Vue.js を導入した話

その一方で

• web アプリケーションフレームワークに Laravel を使ってきた

• その Laravel が 5.3 より Vue.js を公式採用

→ これを受けて個人的な興味から触ってみる

→ いい感触を得た

• データの操作と表示の更新を分離

• 小さく始められる

11

背景 | きっかけ

Page 12: プロダクトに 1 から Vue.js を導入した話

その一方で

• web アプリケーションフレームワークに Laravel を使ってきた

• その Laravel が 5.3 より Vue.js を公式採用

→ これを受けて個人的な興味から触ってみる

→ いい感触を得た

• データの操作と表示の更新を分離

• 小さく始められる

➢ チームの課題を解決できるのでは? → Vue.js 導入へ

12

背景 | きっかけ

Page 13: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入のためにやったこと

3. 良かったこと

4. 学んだこと

5. 今後の展望

13

アジェンダ

Page 14: プロダクトに 1 から Vue.js を導入した話

• チュートリアルを作成

• 方針を整備

• メンバーへのアドバイス

14

導入のためにやったこと

Page 15: プロダクトに 1 から Vue.js を導入した話

• チュートリアルを作成

• 方針を整備

• メンバーへのアドバイス

15

導入のためにやったこと

Page 16: プロダクトに 1 から Vue.js を導入した話

16

チュートリアルを作成

Page 17: プロダクトに 1 から Vue.js を導入した話

• ハンズオン形式

• 30 分程度

• 【題材】行を動的に増減させられる表をつくる

• 過去に辛かった実装例を持ち出して Vue.js の威力を感じてもらう

• 基本的なプロパティ・ディレクティブの使い方やコンポーネントのつくり方を身につけられるもの

• 資料は公開した

• https://github.com/okashoi/vue-js-handson/

17

チュートリアルを作成

Page 18: プロダクトに 1 から Vue.js を導入した話

• チュートリアルを作成

• 方針を整備

• メンバーへのアドバイス

18

導入のためにやったこと

Page 19: プロダクトに 1 から Vue.js を導入した話

• ビルドシステム(gulp, webpack等)は使わない

• 小さく始めるため

• 一度に新しい概念を導入することによる混乱を避けるため

• Vue.js を強制しない

• メンバー間のスキルが不均一な状態

• Vue.js 導入によって開発にブレーキが掛かるのを懸念

• 「こういうところに使う」部分だけすりあわせておく

• 基本ルールを設け、それを Confluence 上に明文化

➢ あとは個別にフォローアップ(後述)

19

方針を整備

Page 20: プロダクトに 1 から Vue.js を導入した話

• チュートリアルを作成

• 方針を整備

• メンバーへのアドバイス

20

導入のためにやったこと

Page 21: プロダクトに 1 から Vue.js を導入した話

• はじめは、メンバーには席の横に付きながら一緒にロジックを構築していく

• slack や プルリクへのコメント で Tips を共有

• 「なぜこうするとよいか」をあわせて説明

21

メンバーへのアドバイス

Page 22: プロダクトに 1 から Vue.js を導入した話

• チュートリアルを作成

• 方針を整備

• メンバーへのアドバイス

22

導入のためにやったこと

Page 23: プロダクトに 1 から Vue.js を導入した話

• チュートリアルを作成

• 方針を整備

• メンバーへのアドバイス

➢ チームとして Vue.js を使っている状態に

23

導入のためにやったこと

Page 24: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入のためにやったこと

3. 良かったこと

4. 学んだこと

5. 今後の展望

24

アジェンダ

Page 25: プロダクトに 1 から Vue.js を導入した話

• 複雑な挙動の画面の実装を想定より早く、バグも少なく実装できた

• jQuery オンリーだったら実装困難だったかもしれない

• 詳細は後半の部で

• 新しいメンバーの受け入れがスムーズに進んだ

• チュートリアルを資料として残せた

• Vue.js 自体の学習しやすさも助けになっている

• 小さく始めたことでチームメンバーが自発的に学習していってくれた

• 「Vue.js の良さ」が伝わった結果

25

良かったこと

Page 26: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入のためにやったこと

3. 良かったこと

4. 学んだこと

5. 今後の展望

26

アジェンダ

Page 27: プロダクトに 1 から Vue.js を導入した話

• フロント設計の必要性を理解した

• 1,000行に及ぶ new Vue() とか。。。

• 「Vue.js を強制しなかった」ことが裏目に出た

• 人・時期によって使われ方がまちまち

• 「画面全体 Vue.js」vs.「一箇所の挙動だけ Vue.js」

• 規模に依らないことは Vue.js の利点だが、プロジェクト内では統一すべき

• npm 等のパッケージ管理ツールを使わないと辛い目を見がち

• モジュール(vue-〇〇 的なやつら)が使えなかったりする

• ちょっとしたハックをして使うこともある

27

学んだこと

Page 28: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入のためにやったこと

3. 良かったこと

4. 学んだこと

5. 今後の展望

28

アジェンダ

Page 29: プロダクトに 1 から Vue.js を導入した話

• 「フロントの設計」を身につける

• 状態の管理、ロジックの切り分け、コンポーネントへの分け方...

• ビルドシステムの導入

• Laravel の Vue.js 公式採用の真価を発揮(Laravel Mix)

• パッケージ管理, ES6記法, bundle化, .vue ファイル 等の恩恵

29

今後の展望

Page 30: プロダクトに 1 から Vue.js を導入した話

後半パート:実際に使った話

Page 31: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入前と導入後のコード比較

1. 新規プロダクトで開発した機能

2. 導入前の状態

3. 導入後の状態

3. まとめ

1. 導入してよかった点

2. 今後できたらいいこと

31

アジェンダ

Page 32: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入前と導入後のコード比較

1. 新規プロダクトで開発した機能

2. 導入前の状態

3. 導入後の状態

3. まとめ

1. 導入してよかった点

2. 今後できたらいいこと

32

アジェンダ

Page 33: プロダクトに 1 から Vue.js を導入した話

• 社内ツールをメインに開発

• 新規プロダクトの開発が決定

• 今までに比べてリッチな画面が求められる

• Vue.jsの導入が決定

• 開発開始(2017年06月~)

• 1次フェーズの開発が完了(2017年10月)

33

Vue.js導入前後のできごと(時系列順)

Page 34: プロダクトに 1 から Vue.js を導入した話

• 社内ツールをメインに開発

• 新規プロダクトの開発が決定

• 今までに比べてリッチな画面が求められる

• Vue.jsの導入が決定

• 開発開始(2017年06月~)

• 1次フェーズの開発が完了(2017年10月)

34

Vue.js導入前後のできごと(時系列順)

Page 35: プロダクトに 1 から Vue.js を導入した話

• jQueryを駆使して画面を作成できる

• 処理を再利用できていない

• JS側に大量のHTMLタグをベタ書きしている

• 状態の管理が複雑になっている

• 要素にどんな状態が存在するのかわかりにくい

• 要素の「状態」を見て処理を分けている

35

これまでの私のJSレベル

Page 36: プロダクトに 1 から Vue.js を導入した話

• jQueryを駆使して画面を作成できる

• 処理を再利用できていない

• JS側に大量のHTMLタグをベタ書きしている

• 状態の管理が複雑になっている

• 要素にどんな状態が存在するのかわかりにくい

• 要素の「状態」を見て処理を分けている

36

これまでの私のJSレベル

Page 37: プロダクトに 1 から Vue.js を導入した話

「状態」の管理がピタゴラ装置

37

頑張るJSがそこに在る

// クリック禁止状態だった場合は何もせずに終了

if ($(e.target).css(‘cursor’) == ‘not-allowed‘) { return false; }

// メッセージを表示し、編集ボタンを無効化

if (!$('.js-btn-update-target-areas').prop('disabled')) {

$('.js-message-target-areas-changed').prop('hidden', false);

$('a.js-open-modal-update-modification-order').css('cursor', 'not-allowed');

}

// 更新を可能にする

$('.js-btn-update-target-areas').prop('disabled', false);

Page 38: プロダクトに 1 から Vue.js を導入した話

「状態」の管理がピタゴラ装置

38

頑張るJSがそこに在る

// クリック禁止状態だった場合は何もせずに終了

if ($(e.target).css(‘cursor’) == ‘not-allowed‘) { return false; }

// メッセージを表示し、編集ボタンを無効化

if (!$('.js-btn-update-target-areas').prop('disabled')) {

$('.js-message-target-areas-changed').prop('hidden', false);

$('a.js-open-modal-update-modification-order').css('cursor', 'not-allowed');

}

// 更新を可能にする

$('.js-btn-update-target-areas').prop('disabled', false);

Page 39: プロダクトに 1 から Vue.js を導入した話

• 社内ツールをメインに開発

• 新規プロダクトの開発が決定

• 今までに比べてリッチな画面が求められる

• Vue.jsの導入が決定

• 開発開始(2017年06月~)

• 1次フェーズの開発が完了(2017年10月)

39

Vue.js導入前後のできごと(時系列順)

もしVue.js導入前に実装したら…

vsVue.js導入後の実装では…

Page 40: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入前と導入後のコード比較

1. 新規プロダクトで開発した機能

2. 導入前の状態

3. 導入後の状態

3. まとめ

1. 導入してよかった点

2. 今後できたらいいこと

40

アジェンダ

Page 41: プロダクトに 1 から Vue.js を導入した話

• 値の編集が可能な表

• 送信前に値のバリデーションを行う

• 選択した条件でデータを絞り込む機能

• グラフ、表が複数存在する画面

• 期間を指定するとグラフ・表の内容が変化

41

開発した機能

Page 42: プロダクトに 1 から Vue.js を導入した話

• 値の編集が可能な表

• 送信前に値のバリデーションを行う

• 選択した条件でデータを絞り込む機能

• グラフ、表が複数存在する画面

• 期間を指定するとグラフ・表の内容が変化

42

開発した機能

Page 43: プロダクトに 1 から Vue.js を導入した話

43

値の編集が可能な表

Page 44: プロダクトに 1 から Vue.js を導入した話

44

値の編集が可能な表

重複禁止 / 150文字以内 正の整数のみ許可

Page 45: プロダクトに 1 から Vue.js を導入した話

• ボタン押下時の処理にバリデーションを大量に記述

• 表の要素をすべて取得

• $.eachで1要素ずつ確認

45

Vue.js導入前

$.each(selectedKeywords, function (index, selectedElemet) {// 要素の入力チェックif (isInput != isEmpty(selectedElemet.hoge)) {

// 略}

// 要素の重複チェックif (selectedElemet.hoge in keywordListWithDuplication) {

// 略} else {

// 略}

// 以下略});

Page 46: プロダクトに 1 から Vue.js を導入した話

• v-modelを使ってユーザの入力を双方向バインディング

• 編集後の値を使った処理も簡単

• バリデーション

• 値を使った計算結果の表示

46

Vue.js導入後

<tr v-for="(element, index) in data"><td><input type=text v-model.trim="element.value1"></td><td><input type=number v-model.trim="element.value2"></td>

</tr>

Page 47: プロダクトに 1 から Vue.js を導入した話

• v-modelを使ってユーザの入力を双方向バインディング

• 編集後の値を使った処理も簡単

• バリデーション

• 値を使った計算結果の表示

47

Vue.js導入後

methods: {// elementChangedメソッド: 要素に0以下の値が入力された場合// 自動で0に修正する// 小数の場合は小数部分を切り捨てるelementChanged: function(element) {

element.value = Math.floor(element.value);if (element.value < 0) {

element.value = 0;}

}}

Page 48: プロダクトに 1 から Vue.js を導入した話

• 値の編集が可能な表

• ボタンを押下した際に値のバリデーションを行う

• 選択した条件でデータを絞り込む機能

• グラフ、表が複数存在する画面

• 期間を指定するとグラフ・表の内容が変化

48

開発した機能

Page 49: プロダクトに 1 から Vue.js を導入した話

49

選択した条件でデータを絞り込む機能

Page 50: プロダクトに 1 から Vue.js を導入した話

50

選択した条件でデータを絞り込む機能

絞り込み機能

Page 51: プロダクトに 1 から Vue.js を導入した話

• データをJS側で絞り込んだ後、表を再描画

• 表の再描画時に大量のHTMLをベタ書き

51

Vue.js導入前①

tableCheckBoxId = 'goal' + goalInfo['id'];tableCheckBox = '<td class="css-table-goal-checkbox"><label class="cr-styled"><input id="'

+ tableCheckBoxId+ '" class="js-modal-checkbox-goal" data-goal-name="'+ escape_html(goalInfo['name'])+ '" name="selected_goal_ids[]" type="checkbox" value="'+ goalInfo['id']+ '"><i class="fa"></i></label></td>';

tableId = '<td><div>' + goalInfo['id_at_hoge'] + '</div></td>';

Page 52: プロダクトに 1 から Vue.js を導入した話

• JS側でデータを変更したら画面側は動的に変化

52

Vue.js導入後①

Page 53: プロダクトに 1 から Vue.js を導入した話

• 絞り込み条件に対するバリデーションをいたるところに記載

• 絞り込むボタンを押下した際にチェックが走る

53

Vue.js導入前②

// -----------------------------------// 絞り込み機能// -----------------------------------

// 要素1の絞り込み指定範囲内のものだけを表示$('.js-button-check-condition1').on('click', function(e) {

// バリデーションと絞り込み処理});

// 要素2の絞り込み指定範囲内のものだけを表示$('.js-button-check-condition2').on('click', function(e) {

// バリデーションと絞り込み処理});

Page 54: プロダクトに 1 から Vue.js を導入した話

• 役割を分けて処理を記述できる

• watch:リアルタイムなバリデーション

• methods: データの絞り込み処理

• computed: データを使った計算

• filter: 表示用に値を整形(例:1000円 → 1,000円)

54

Vue.js導入後②

watch: {filterConditions: {

handler: function (conditions) {// 非負値のみ許可if (conditions.hoge.lower < 0) {

conditions.hoge.lower = 0}// 以下略

},deep: true

}}

Page 55: プロダクトに 1 から Vue.js を導入した話

• 値の編集が可能な表

• ボタンを押下した際に値のバリデーションを行う

• 選択した条件でデータを絞り込む機能

• グラフ、表が複数存在する画面

• 期間を指定するとグラフ・表の内容が変化

55

開発した機能

Page 56: プロダクトに 1 から Vue.js を導入した話

56

グラフ、表が複数存在する画面

Page 57: プロダクトに 1 から Vue.js を導入した話

• グラフの数だけ、似たような処理を記述

• 初期のグラフ表示用の設定

• グラフのデータが変わった時の処理

• 変更があった時に直し漏れが発生する危険性

• コピペが大量発生

• コード量が多くて直す箇所が分かりにくい

57

Vue.js導入前

Page 58: プロダクトに 1 から Vue.js を導入した話

58

Vue.js導入前

// パターンに紐付く データおよび軸 の設定をそれぞれ行う// 追加でテーブルへの表示もこちらで行うswitch (patternId) {

// ほげのグラフcase patternIds['hoge'] :

_createHogeDatasets();config.options.scales = hogeScales;break;

// ふがのグラフcase patternIds['fuga'] :

_createFugaDatasets();config.options.scales = fugaScales;break;

Page 59: プロダクトに 1 から Vue.js を導入した話

• グラフの作成にはChart.jsを使用

• vue-chartjsというVue.js用のプラグインを使用した

• vue-chartjsにはグラフ用のコンポーネントがある

59

Vue.js導入後

http://vue-chartjs.org/

Page 60: プロダクトに 1 から Vue.js を導入した話

• グラフの種類によってコンポーネント化

• データが異なる同じ種類のグラフに対応

• グラフの更新は、データをコンポーネントに渡すだけ

60

Vue.js導入後

//------------------// 円グラフ//------------------Vue.component('pie-chart', {

extends: VueChartJs.Pie,mixins: [VueChartJs.mixins.reactiveProp],props: ['options'],mounted: function () {

this.renderChart(this.chartData, this.options);}

});

Page 61: プロダクトに 1 から Vue.js を導入した話

61

Vue.js導入後

<div class="row"><div class="col-md-6 col-sm-6 col-xs-6 item">

<pie-chart:title="hogeTitle":height="150":chart-data="hogeDatacollection"

></pie-chart>

</div><div class="col-md-6 col-sm-6 col-xs-6 item">

<pie-chart:title="fugaTitle":height="150":chart-data="fugaDatacollection"

></pie-chart>

</div></div>

Page 62: プロダクトに 1 から Vue.js を導入した話

1. 背景

2. 導入前と導入後のコード比較

1. 新規プロダクトで開発した機能

2. 導入前の状態

3. 導入後の状態

3. まとめ

1. 導入してよかった点

2. 今後できたらいいこと

62

アジェンダ

Page 63: プロダクトに 1 から Vue.js を導入した話

• データの変更があった際の画面への反映が簡単

• 導入前:JS側でデータ変更→画面側に反映させる処理 が必要

• 導入後:JS側でデータ変更→自動で画面側に反映される

• コードが読みやすくなった

• データ処理と表示処理が分離されている

• データ処理の内部でも処理が用途に分かれている(computed, method, filtersなど)

• コンポーネントによって共通部分を再利用することができた

63

導入してよかった点

Page 64: プロダクトに 1 から Vue.js を導入した話

• データの変更があった際の画面への反映が簡単

• 導入前:JS側でデータ変更→画面側に反映させる処理 が必要

• 導入後:JS側でデータ変更→自動で画面側に反映される

• コードが読みやすくなった

• データ処理と表示処理が分離されている

• データ処理の内部でも処理が用途に分かれている(computed, method, filtersなど)

• コンポーネントによって共通部分を再利用することができた

64

導入してよかった点

Page 65: プロダクトに 1 から Vue.js を導入した話

• データの変更があった際の画面への反映が簡単

• 導入前:JS側でデータ変更→画面側に反映させる処理 が必要

• 導入後:JS側でデータ変更→自動で画面側に反映される

• コードが読みやすくなった

• データ処理と表示処理が分離されている

• データ処理の内部でも処理が用途に分かれている(computed, method, filtersなど)

• コンポーネントによって共通部分を再利用することができた

65

導入してよかった点

Page 66: プロダクトに 1 から Vue.js を導入した話

• データの変更があった際の画面への反映が簡単

• 導入前:JS側でデータ変更→画面側に反映させる処理 が必要

• 導入後:JS側でデータ変更→自動で画面側に反映される

• コードが読みやすくなった

• データ処理と表示処理が分離されている

• データ処理の内部でも処理が用途に分かれている(computed, method, filtersなど)

• コンポーネントによって共通部分を再利用することができた

66

導入してよかった点

Page 67: プロダクトに 1 から Vue.js を導入した話

• データの変更があった際の画面への反映が簡単

• 導入前:JS側でデータ変更→画面側に反映させる処理 が必要

• 導入後:JS側でデータ変更→自動で画面側に反映される!

• コードが読みやすくなった

• データ処理と表示処理が分離されている

• データ処理の内部でも処理が用途に分かれている(computed, method など)

• コンポーネントによって共通部分を再利用することができた

67

導入してよかった点

仕様の変更や修正にも強いコードになった

Page 68: プロダクトに 1 から Vue.js を導入した話

• 導入直後のコードのリファクタリング

• 導入直後コードはVue.jsの恩恵を受けきれていない

• まだまだVue.jsで記述できる箇所がある

• 共通部分をまとめる

• 現状:ページ単位で共通処理がまとまっている

• 今後:ページを跨いで共通部分をまとめる

• グラフのコンポーネント など

68

今後やりたいこと

Page 69: プロダクトに 1 から Vue.js を導入した話

一緒に働くメンバーを募集しています!