エンジニアドリブンで始める新規サービス開発のススメ

f:id:kumamon_engineer:20190228085445j:plain


ITプロパートナーズのパートナーズ事業部エンジニアチームのリーダーをしている三宅(@miyakey7)です。

今回はITプロパートナーズで、初めてエンジニア主体でサービスの企画から開発までを担った話をしたいと思います。

 

開発したサービスはSNSのつながりを活用した、ソースコード共有サービス「ReviewMe」です!

review-me.tech

サービスの始め方

体制

2018年度下半期が始まる10月、事業部長直下にエンジニア2人と、19卒でエンジニアとして入社するインターン1人の、4人体制でこのプロジェクトは始まりました。

プロジェクトの目的は、本来の業務(ITプロパートナーズメインサイトの開発)とは別に、業務時間を使って新しい取り組み(サービスの開発)に挑戦しよう、ということです。

開発段階では業務委託のデザイナーさんも加わり5人体制になりました。

プロダクトオーナー

普段は事業部長がプロダクトオーナーとしてタスクやサービスの方向を決めるのに対し、今回はエンジニアがプロダクトオーナーになります。

これにより、以下のようなことも今回はエンジニアで決定しました。

  1.  サービスの各種目標数値(KPI設定)
  2.  必要な機能の選定と実装
  3.  システム以外の施策

サービス内容の決定

当然、サービス内容もエンジニアが中心で決めます。今回は以下の軸をベースに開発するサービスを決定しました。

  • エンジニアの助けになるもの
  • ソースコードを使ったもの
  • SNSの特性を活かせるもの

これらを元に「最短の期間で最小の機能」を作っていきました。

結果として

  • エンジニアのアウトプットの第一歩になる簡単な投稿
  • ソースコードが主体の投稿一覧
  • SNSにシェアすることでコードのOGP画像が表示される

という機能を中心に作成しました。

 

詳しくはもう一人のエンジニアでもある、ちゃんなか(@channaka0531)の記事にまとまっています。サービスの方向性決定に言及した内容になっています!

note.mu

サービス名の決定と商標取得

PULLREQ時代

サービス名ももちろんエンジニアが決めます!

今回は商標も取る予定でした。

最初に付けた名前は「PULLREQ(プルリク)」。エンジニアならすぐにイメージが出来る言葉であり、サービス内容を端的に表した素敵な名前でした。

しかし、皆さんご存知の通り、GitHubのPULL REQUEST機能の略称から来ているこの言葉。識別性の観点から、商標を取ることは出来ませんでした。。。(正確には取れる見込みが薄いとのこと)

 

画像も出来てました..お蔵入りがもったいないのでここに貼っておきます..。

f:id:kumamon_engineer:20190228091556p:plain

 

※ちなみに商標調査は代行でお願いすると1回で数万円程度、登録申請代行で内容にもよりますが最小で15万円以上、申請から取得までは時期によって違うらしいですが10ヶ月程かかるそうです!(結構かかりますね..)  

サービス名決定

200を超える名前案をエンジニア3人で出し尽くしました。

その結果、偶然後ろを通った今回のプロジェクトに全く関わっていないエンジニアの一声

「ReviewMe(レビューミー)」

 

f:id:kumamon_engineer:20190228134448p:plain

コレで決まりました!意外なところに答えは落ちているものです。

 

開発期間

ReviewMeはデザイン含め、その全てを「1ヶ月」で作りました。

実際にエンジニアが手を動かしたのは2週間程度です!

 

このスピード感はエンジニアだけで詳細の仕様を口頭+Slackで詰めれた事で実現できたのだと思います。もちろん上長への報告はありますが、プロダクトオーナーである自責が開発を進める上で、大きく影響を与えていたと感じます。

サービスの技術選定

 最短の期間を目指していたため、慣れ親しんだ環境を最優先に選定しました。

サーバー

AWS EC2(Amazon Linux)

RDB

Amazon Aurora(Mysql

サーバーサイド

・Laravel 5.7

フロントエンド

・Vue.js

jQuery(少しだけ)

その他ツール

git/GitHub

一度、サイトのオープンソース化も考えましたが、一旦はprivateで開発しております。

docker

ローカル環境は全てdockerでまとめました。

backlog

スクラム開発のタスク管理として利用しました。

IFTTT

IFTTTの機能によりReviewMeでシェアしたツイートなどを収集できます。更にその内容をSlackに通知することも出来ます。

Slack

コミュニケーションツールはSlackです。多くの議論の結果がSlackに残っています。

RealtimeBoard

ビジネスフレームワーク用に利用しました!詳細は次に書いております!

 

ビジネスフレームワークの利用

リーンキャンバス 

今回はサービスの強み、弱み、価値を明確にするためにリーンキャンバスを利用しました。リーンキャンパスは端的に表すこと、時間をかけすぎないことが重要で、頭の整理に役立ちます。その内容をチームで共有できるので、非常に効果的です。

以下はその時使った枠組みになります!

f:id:kumamon_engineer:20190228094917j:plain

こちら実際の進め方としてはRealtimeBoardの機能を使い、オンライン上でテキストを埋めていきました!URLで共有出来、お互いの反映がリアルタイムで反映されるので便利でした。

realtimeboard.com

ユーザーヒアリング活動

 twitter

twitter上のユーザーの意見を迅速に取得しながら開発改善を行っています!

目標時間は要望ツイートから24時間以内です!

以下はエディタの言語選択にElixirが無いという意見を頂き、対応致しました!

f:id:kumamon_engineer:20190228100238p:plain

使っていて気になる点、要望があればツイートしていただくと幸いです!

もくもく会(ProLabo)

f:id:kumamon_engineer:20190228101903p:plain

弊社イベントスペースではエンジニアが主体で運営しているもくもく会(ProLabo)が月に1回開かれています。

毎回100人を超える応募を頂き、多くのエンジニアやデザイナーが参加していただけています。

itpropartners.connpass.com


今回初期ユーザーとユーザーヒアリングの対象をProLabo参加者に限定しました。

協力してくださった皆さん本当にありがとうございます!

ProLaboは駆け出しのエンジニアや、普段は別の仕事をしながら休日はプログラミングを勉強している方達もたくさん参加しており、そういった人達に使ってもらい意見を直接聞かせてもらいました。

ユーザーFB内容の一部
  • スキルカテゴリが目立つところに欲しい
  • 検索がない

  • ポートフォリオ的に使いたい

などの貴重な意見を貰い、機能開発に役立てることが出来ました!

 

広報活動

今回はじめてPRTimesに載せるプレスリリースの内容を考えました。

普段は何気なく読んでいる記事ですが、実際に自分のサービスで書くとなると、表現一つ取ってもサービスの方向性とずれてないか気になります。

記事で表現する際に再度サービスと向き合い、コレって何のためにあるんだっけと考えるきっかけが起き、自分の作ったサービスですが理解が深まるといった経験ができました。

prtimes.jp

 

 

家族に誇れるサービスを

弊社が掲げるバリューの一つに「家族に誇れるサービスを」というものがあります。これは、提供するサービスに誇りを持ち続けられるように、お客様の声に耳を傾けサービスを改善し続けるべきだということ、どんなに規模が拡大しても、一人一人がお客様への提供価値を考え続けるチームでいること、そして「自分の家族に心から薦められるサービスである」 ということをクオリティの基準にする、というバリューです。

 

私達は全てのサービス開発において、このバリューを大切にしながらを作ることを心掛けています。もちろん今回も同じで、サービスを作る側として立ち返る際の大事な指標になりますし、個人的にとても共感の強いバリューの1つです。

 

サービスの終わり方

もちろん、今は考えていませんがサービスが終わる時を考えることも時には必要かもしれません。サービスを生み出したなら、エンジニアはその最後まで見届けたいというのが私の本音です。(もちろん色んな理由でこれが難しい事は理解しています。)

 

意思決定の方法は以下の点で考えています。

・サービスに誇りを持って、お客様に価値を提供出来ているか

・サービスの成長性/継続性

・コスト面

上から順に重要な指標として置いています。

 

最後が来ないに越した事はありませんが、もし終わらせるなら自分で決断したいと思っています。それがサービスを生むということであり、使ってもらってる人達への責任だと考えます。

 

そしてReviewMeは絶対終わらせないように頑張ります!!

 

最後に

今回エンジニア主体でサービスの企画から開発までを行なったことで、これまで以上にビジネス的視点を持って開発に取り組めるようになりました。

その点において、本来やらない開発以外の実務の経験(広報、サービス名検討、商標取得、ビジネスフレームワーク、KPI設定)は非常に有意義なもので、そこから得た学びをサービスに役立てることが出来たと感じています!

また新規でミニマムなサービス開発においては、エンジニアドリブンはエンジニアにとってもサービスにとっても良い開発手段だと思いました!

 

少人数でまだまだ未熟な開発体制ですが、これからサービスと共に最高のプロダクトチームへと成長できるよう頑張ります。

今後はサービスをグロースさせていくことに注力していくことになります。

エンジニアとしてサービスを開発するだけでなく、サービスをグロースするための視点を養えるチャンスだと思います。そういった経験や視点の話もこれから書いていけたらいいなと考えています!

 

弊社ではサービスにコミットする経験やフェーズに興味のあるエンジニアを絶賛募集中です!僕たちと一緒にReviewMeを作りませんか?

興味ある方は是非フラットにお話し出来ればと思います!

 

www.wantedly.com

 

www.wantedly.com

 

【Nuxt.js/Vue.js】スタートアップ導入事例 LTイベントに参加しました!

f:id:marron-web-engineer:20190202124120p:plain

こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターンの栗岡です!

普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。

今回は、1月30日に弊社渋谷オフィスで行われたNuxt.js/Vue.jsで開発しているスタートアップ企業によるLTイベントのレポートを行います!

弊社のエンジニアの米川も登壇しました!

re-build.connpass.com

続きを読む

Vue.jsの開発コードネームが〇〇オタ仕様だという話と、次のコードネームを予想してみる

  • Vue 2.6 が2/4に正式リリース
  • そもそも開発コードネームとは
  • ここでVue.jsの過去のコードネームを見てみましょう
  • となれば予想したくなりますよね
  • 次バージョン(2.7.0)は「N」始まりです。
  • おわりに

 

 

intee 担当エンジニアの五藤です。

弊社では、フロントエンドの処理ではVue.jsを採用することが多いです。

 

そんなVue.jsですが、最近新バージョンがリリースされました。

 

Vue 2.6 が2/4に正式リリース

 

medium.com

 

今回注目すべきはここです。

 

— today we are excited to announce the release of Vue 2.6 “Macross”!

 

開発コードネームが Macross ??

 

しかもリリース記事には何やらそれっぽい戦闘機の画像が。ちゃんと可変ギミックもありそう

 

そもそも開発コードネームとは

ソフトウェアやライブラリの開発で、いわゆる正式名称やバージョン番号とは別に、愛称のような物を付けるケースがあります。

有名どころでは、Android OSの「Lolipop」「KitKat」のようなお菓子縛りや、MacOS では「Mavericks」「Sierra」など、カリフォルニアの地名が付けられています。

 開発コードをつける背景としては

  • 正式名称が決まるまでの仮の通称
  • 開発時、バージョン数字で呼ぶよりも識別しやすい(OSSの場合は、たいてい複数のバージョンを平行して開発するため、var2.0ではこの機能があってvar2.1ではこうする〜みたいな話が入り乱れます)
  • ユーザー側に愛着を持ってもらう

などなどです。

ここでVue.jsの過去のコードネームを見てみましょう

version 開発コードネーム 日本語名称 アニメ初出年 制作会社
v2.6 Macross 超時空要塞マクロス 1982年 タツノコプロ
v2.5 Level E レベルE 2011年 Studioピエロ✕david production
v2.4 Kill la Kill キルラキル 2013年 TRIGGER
v2.3 JoJo's Bizarre Adventure ジョジョの奇妙な冒険 1993年 A.P.P.P
v2.2 Initial D 頭文字D 1998年 スタジオコメットぎゃろっぷ
v2.1 Hunter X Hunter HUNTER✕HUNTER 1999年 スタジオディーン日本アニメーション
v2.0 Ghost in the Shell GHOST IN THE SHELL / 攻殻機動隊 1995年 Production I.G
v1.0 Evangelion 新世紀エヴァンゲリオン 1995年 タツノコプロGAINAX
v0.12.0 Dragon Ball ドラゴンボール 1986年 東映動画
v0.11.0 Cowboy Bebop カウボーイビバップ 1998年 サンライズ
v0.12.0 Blade Runner - 1982年 -
v0.12.0 Animatrix アニマトリックス 2003年 スクウェアUSA、STUDIO 4℃マッドハウス

 ・・・予想以上にアニオタだぞこれ!?   

海外アニメファンの評価が高い「攻殻機動隊」「カウボーイビバップ」「ドラゴンボール」辺りを押さえつつ、2010年台の「キルラキル(2013-2014)」「レベルE(2011)」あたりを混ぜてみたりと、結構なこだわりようです。

そして命名にはルールがあり、Animatrix から Macross まで、綺麗に先頭の頭文字がアルファベット順に並んでいます。 (頭文字Dのイニシャルが「D」ではなくて「I」扱いなのは若干納得がいかない)

ちなみに最初期は
Animatrix(超有名SF映画マトリックス」のアニメスピンオフ作品)
Blade Runner(カルト的な人気を誇る古典SF映画)」

と、どちらかといえばSF路線の名前をつけていたけど、少しずつ吹っ切れてきた模様。

 

また、Vue.jsの作者である Evan Youの個人サイトのプロフィールには

evanyou.me

 

Outside of programming and helping my wife take care of our two kids, I enjoy video games, karaoke, sushi and collecting watches.

プログラミングと育児以外では 、ビデオゲームやカラオケ、寿司、時計の収集が趣味です。

とあります。ものすごくアニメが好き!というのを全面に押し出しているわけではないですが、コードネームの並びを見る限りは、結構なアニメ好きなのが見て取れます。

(なお、後述の予想サイトには、Kazuponさんを始めとしたContributorも次Verの予想を書き込んでいるため、コードネームはEvan氏が一人で決めている可能性が高いです。)

 

となれば予想したくなりますよね

アルファベット順、というルールがある以上、予想したくなるのが人の常、ということで、次バージョンのコードネームの予想を議論するサイトもすでに出来ていたりします。

 

github.com

 

最新の2.6に対するissueでは「Macross」と「Monster」が2大予想になっていたので、見事的中していた模様。

 

次バージョン(2.7.0)は「N」始まりです。

折角なので本ブログでも次バージョンを予想してみます。

大本命:NARUTO

大本命は、忍者をフューチャーした世界観と、圧倒的なアクション作画で海外から圧倒的な支持を得ているこの作品。海外においては、アニメ好き=NARUTO好き、と言っても過言ではありません。
過去のコードネームで「DRAGON BALL」「攻殻機動隊」などの超有名作品をしっかりと押さえていることを考えると非常に可能性は高いです。
という雰囲気すらします。むしろ、この先Vue.jsのシェアが伸びてきた場合、Vue.jsのコードネームに採用される=超有名アニメとして認められる 、というコンセンサスが社会的に形成されることも十分考えられるので、むしろ、
「この流れでNARUTOを外していいのか?」
という雰囲気すら感じられます。

微妙に何を言っているのかわかりませんが、2.7.0はかなりの可能性で「NARUTO」が採用されると言って間違いがないと思います。

次点:機動戦艦ナデシコ(Mobile Buttleship Nadeshiko)

エヴァンゲリオンで一般層を巻き込んだ空前のアニメブームが起きていた90年代後半時代に、重厚なSF設定と軽妙なシナリオで人気を博した名作です。唯一対抗馬になりそうなのはこれくらいでしょうか。

有力な要素

  • 直近で「レベルE」「キルラキル」「マクロス」など、アニメファン以外も知っているような超有名作品ではない作品を出してきており、「私はこんな作品も知ってるよ!」という路線で考えた場合は非常に有力

懸念点

  • 前バージョンがマクロスだったので、同じロボット系SFアニメを連載することを避けるのではないか
  • 海外での知名度がそれほど高くない

 個人的には好きなんですけどね、ナデシコ

大穴:風の谷のナウシカ(Nausicaa of the Valley of The Wind)

言わずとしれたジブリアニメの雄ですね。

 

有力な要素

  • コードネームを考える中で「ジブリアニメから1回は採用したい」と考えている場合はかなり有力。(他のタイトルは、「千と千尋の神隠し(Spirited Away)」など作品名に修飾語が多く、イニシャルを意識しづらいものが多い)

懸念点

  • 海外での評価はそれほど高くない(いわゆる海外アニメ人気の文脈において、日本のそれほど王道的な立ち位置ではない)

ジブリアニメ自体は非常に有力なのですが、
NARUTO」か「ナウシカ」の2択だと、NARUTOを選ぶような気がするんですよね・・・。
これが「NARUTO」と「ナデシコ」の2択だと、ナデシコを選ぶ可能性がありそうに感じてしまうのは、なんとなくアニメファンの業みたいなものを感じます。

 

 

以上、Vue.jsのコードネーム界隈の話でした!
フロントエンド界隈では確固たる地位を得たVue.jsですが、本筋とは別に、こんな楽しみ方も提供していることを知ってもらえれば幸いです!

 

続きを読む

毎月恒例!#ProLabo(プロラボ)渋谷もくもく会@渋谷1月12日(土)に開催しました! 

こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターン栗岡です!

普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。

今回は、1月12日に弊社渋谷オフィスで開催されたもくもく会をレポートします!

続きを読む

Nuxt.js + QiitaAPIで開発したWebアプリケーションをFirebaseにデプロイする

こんにちは。

ITプロパートナーズでエンジニアの米川(@keiuwk0614)です。

 

普段は、自社プロダクトである中途向けの転職サービスGraspy(https://graspy.jp/)の開発をしています。フロントエンドはNuxt.js、サーバサイドはLaravelを使用し開発しています。

今回は、初学者向けにNuxtのプロジェクト作成から、外部APIを呼び出して簡単なWebアプリケーションを開発し、Firebaseのホスティングにデプロイするまでを紹介していきたいと思います。

f:id:itpro_yonekawa:20181212172913p:plain

 

 

実行環境

  • node v10.3.0
  • yarn 1.9.4
  • nuxt 2.0.0
  • firebase CLI 5.0.1

 1. Nuxtプロジェクト作成

1-1. プロジェクト作成

プロジェクトを作成するディレクトリに移動し、公式ドキュメント(インストール - Nuxt.js)にならい下記コマンドを実行します。

※今回はyarnを使用

yarnが入っていない方は yarnを使ってみた - Qiita  を参照してください。

$ yarn create nuxt-app <my-project> 

 いくつか質問されます 。

    ※今回は、UI frameworkにbulma、rendering modeはUniversal、axios moduleを使用するのでyesで選択してください。

? Project name nuxt-firebase
? Project description My tiptop Nuxt.js project
? Use a custom server framework none
? Use a custom UI framework bulma
? Choose rendering mode Universal
? Use axios module yes
? Use eslint no
? Use prettier no
? Author name kei yonekawa
? Choose a package manager yarn

選択後、全ての依存関係がインストールされプロジェクトが作成されます。

 

1-2.  起動

作成したプロジェクトのディレクトリに移動し、下記コマンドを実行します。

$ yarn run dev

デフォルトで3000番ポートが開きます。 http://localhost:3000 でアクセスし下記画面が表示されれば成功です。

f:id:itpro_yonekawa:20181211235205p:plain

デフォルトのポート番号を変更したい場合は、package.jsonのdevの引数にポートを指定するか、

"scripts": {
"dev": "nuxt --port 3333",
}

nuxt.confing.js内に設定することで変更できます。

module.exports = {
server: {
port: 8888,
},
// その他設定
}

 

2. axiosでQiita APIを呼び出す

2-1. 使用するQiita API

今回使用するのは、GET /api/v2/items という記事の一覧を作成日時の降順で返却するAPIを使用します。詳細は下記のAPI仕様書をご確認ください。

qiita.com

 

2-2. ayncData内でqiita apiを呼び出す

 その前にasyncDataには次のような機能があります。

 

ページコンポーネントがロードされる前に毎回呼び出される

・サーバサイドレンダリングや、ページ遷移前にも呼び出される

・contextを引数にとる

・asyncDataの結果は、dataとマージされる

 

asyncDataと似たようなメソッドに、fetchというメソッドもあります。

fetchもasyncDataもほぼほぼ機能は同じですが、asyncDataの場合はdataとマージされるため、必ずプロパティをreturnする必要があります。取得したデータをvuexに入れて使用する場合はfetchを使用し、ページコンポーネント内で使用する場合はasyncDataを使用するのが良さそうです。

 

それでは、プロジェクト作成時にデフォルトで生成されたpages/index.vueを編集します。今回は、apiで取得した結果をそのままページコンポーネント内で使用するため、asyncData内でapiを呼び出します。

<script>
// axios
import axios from 'axios';
// qiita api URL
const BASE_URL = 'https://qiita.com/api/v2/';

export default {
async asyncData(context) {
try {
const response = await axios.get(BASE_URL + 'items', {
params: {
page: 1,
per_page: 10,
}
});
return {
articleList: response.data,
};
} catch (error) {
console.log(error);
}
}
}
</script>

/api/v2/itemsAPIには次のパラメータが設定できます。

  • page ページ番号 (1から100まで)
  • per_page 1ページあたりに含まれる要素数 (1から100まで)
  • query 検索クエリ

今回は、10件のデータを取得してくるように固定で設定します。

何かキーワード検索したい場合は、queryというパラメータに検索したいキーワードを設定することも可能です。

params: {
page: 1,
per_page: 10,
query: 'Nuxt.js',
}

 

2-3. apiのレスポンス結果を画面に表示

2-2ではasyncData内でapiを呼び、レスポンス結果をarticleListに設定してreturnしています。先ほども述べたように、asyncDataの結果はdataとマージされるため、pages/index.vueでarticleListを展開していきます。

articleListをv-forでループし、記事のタイトル、記事URL、アイコン画像、ユーザーID、いいね数を表示します。

レスポンスには他にも本文、タグ、更新日など様々あります。必要に応じカスタマイズしてください。

まずは、下記のコードをコピペでOKです。

<template>
<section>
<article
v-for="(article, index) in articleList"
:key="index"
class="box media">
<figure class="media-left">
<p class="image is-64x64">
<img :src="article.user.profile_image_url">
</p>
</figure>
<div class="media-content">
<div class="content">
<p>
<
strong><nuxt-link :to="article.url">{{ article.title}}</nuxt-link></strong> <br>
{{ article.user.id }}<br>
<small>Like · {{ article.likes_count }}</small>
</p>
</div>
</div>
</article>
</section>
</template>

 

ブラウザに戻り、上記コードコピペしていれば次のような画面が表示されていると思います。

 

 

f:id:itpro_yonekawa:20181212234848p:plain

 

これで一旦、Qiita APIを呼び出し記事の一覧を表示するところまでは完了になります。

コンポーネントの切り出し、デザイン等は各自でカスタマイズして貰えればと思います。

 

3. Firebase Hostingにデプロイ

3-1. Firebaseの準備

Firebase Console(https://console.firebase.google.com/?hl=ja)にアクセスし、googleアカウントでログインします。

f:id:itpro_yonekawa:20181213001128p:plain

プロジェクト、ロケーションの設定、規約に同意しプロジェクトを作成を押下します。

自動でFirebaseの管理画面に遷移します。

f:id:itpro_yonekawa:20181213001208p:plain

 

3-2. Firebase Hostingにデプロイ

3-2-1. Firebase CLIをインストール

先ほど作成したプロジェクトのディレクトリで、Firebase CLIをインストールしFirebaseコマンドを使用できるようにします。

$ yarn global add firebase-tools
3-2-2. firebaseにログイン

下記のコマンドを実行し、firebaseにログインします。

このコマンドを実行するとローカルコンピュータがFirebaseアカウントに接続され、プロジェクトへのアクセス権が付与されます。

$ firebase login
 3-2-3. firebaseのホスティングの初期設定

下記コマンドを実行し、ホスティングの初期設定を行います。

$ firebase init hosting

先ほど作成したfirebaseプロジェクトを選択します。

? Select a default Firebase Project for this directory: nuxt-tutorial(nuxt-tutorial-491c1)

公開ディレクトリはdistにします。

? What do you want to use as your public directory ? dist

SPAとして公開するか聞かれますが、今回はasyncDataを使用しSSRしているのでNoを入力します。

? Configure as a single-page app (rewrite all urls to /index.html)? No

プロジェクト直下にfirebase.jsonと.firebasercというファイルが自動で作られます。

 

 3-2-4. firebase デプロイ

 下記コマンドを実行します。

 dist/ 配下に静的ファイルが生成されます。

$ yarn build

本番環境に公開します。

$ firebase deploy

無事にデプロイできましたでしょうか。

firebase Hostingのダッシュボードでデプロイが成功したか、デプロイ先のドメインが分かります。

f:id:itpro_yonekawa:20181225171535p:plain

 

 

筆者がデプロイしたものは下記のURLからご確認頂けます。

https://nuxt-tutorial-491c1.firebaseapp.com/

 

 

今回作成したコードは、githubに公開していますので全体を見たい人はこちらを参考にしてください。

GitHub - keiyonekawa0614/nuxt-firebase: nuxt + qiita API + firebase hosting sample

 

ちょっと応用してキーワード検索できるものも作ってみました。

daryl-f5622.firebaseapp.com

こちらもgithubソースコードを公開しておりますので、参考にしてみてください。

GitHub - keiyonekawa0614/nuxt-tutorial: Web service to search qiita articles.


 

 最後に

ITプロパートナーズでは、Laravel、vue.js、Nuxt.jsで開発に挑戦したいエンジニア・デザイナーを絶賛募集中です。少しでも興味のある方は、DMでもGraspy、Wantedlyでもお気軽にご連絡頂けますと嬉しいです。お待ちしております。

 

 

サービスの管理画面で Vue + element.ui を活用する(table編)

ITプロパートナーズの新卒採用サービス「intee」のエンジニアの五藤です。

intee.jp

inteeの技術スタックは、バックエンドがPHP(CakePHP3)、フロントエンドがVue.jsを採用しています。 ユーザーが見る画面はもちろんの事、弊社スタッフが利用する管理画面に関しても、新しく実装する画面に関してはほとんどVueを使って管理画面を構築しています。

「何で管理画面のフロントエンドをリッチにする必要が?」

って思われるかもしれませんが、管理オペレーションが複雑になってくると、

  • 一度に複数のユーザーに対して操作したり、複数のレコードを追加する際にいちいち画面遷移したくない
  • 複雑なリレーションのデータ登録を、モーダルなどを用いて効率的にやりたい

などなど、オペレーション最適化の面で、リッチなフロントエンドを提供するメリットは意外と多く、営業サイドから 「この画面をVueを使ってサクサク使えるようにしてほしい」 という要望を受けることもしばしばだったります。

そんな中で、UI/コンポーネントライブラリとして愛用しているのが、Element です!

Element

各種フォーム部品やモーダルやアラート、簡単なグラフ表示などの、リッチな画面を作るのに必要なコンポーネントが揃っているニクいやつです。しかも、Vueのコンポーネントとして実装されているため、

<el-tag type="success">Elementに用意されてるめっちゃきれいなタグUI</el-tag>

という感じに、HTMLライクな書き方で簡単にコンポーネントを配置できるのも嬉しいところです。

今回は、その中でも、管理画面の画面設計の中核を占める <el-table> の使い方や、実装上のポイントについてまとめます!

tableコンポーネントてどんなの?

スクリーンショット 2018-11-28 10.07.36.pngelement-ui公式 より引用 )

簡単に言うと、管理画面でよくある、「データ一覧をテーブル形式で表示する」事ができるコンポーネントです。 これだけ書くと凄くシンプルなので、elementのtableのすごい所をガンガン紹介します!

el-tableを使うと捗るポイント

データ投入が簡単で、いい感じに表示してくれる

データ設定の方法は簡単で、配列形式のデータをVueのdata属性に格納して、<el-table> のプロパティとして指定するだけ。

(データ側)

data: {
          tableData: [{
            date: '2016-05-03',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }, {
            date: '2016-05-02',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }, {
            date: '2016-05-04',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }, {
            date: '2016-05-01',
            name: 'Tom',
            address: 'No. 189, Grove St, Los Angeles'
          }]
        }

(コンポーネント)

<el-table :data="tableData">

これだけで、tableDataプロパティに格納した配列データを、<el-table>内で使用することが出来ますし、el-dataの値を切り替えれば、リアルタイムでテーブル上の値も更新されます。

また、dataに格納する値は、

<el-table :data="tableData">

      <!-- 日付データを表示するカラム -->     
      <el-table-column
        prop="date"
        label="Date"
        width="180">
      </el-table-column>

      <!-- 名前データを表示するカラム -->
      <el-table-column
        prop="name"
        label="Name"
        width="180">
      </el-table-column>

<el-table>

という感じで、table側で自由に各カラムを抽出、表示できます。 dataに設定された全カラムが勝手に出力されるのではなく、コンポーネント側で出したい情報を自由にピックできる のがポイントで、実際の想定シーンとしては、

  • dataプロパティには、サーバーサイド側の参照APIをまるっと格納させ、<el-table>側で、必要なデータを必要な形でレイアウトする

というやり方で、 汎用的なAjaxの戻り値を、そのまま<el-table>にぶちこめる のが実装上は凄く楽だったりします。

各カラムの表示内容が、タグベースで柔軟に設定できる

各カラムに表示する値は、HTML形式で動的に設定可能で、更に言うと、他のelementのコンポーネントを配置することも出来ます。

[いろんなタグを配置してみるとこんな感じ]

f:id:itpro_goto:20181203220644p:plain
いろんなタグを配置してみた

こんな感じで、画像やアイコン、タグ、ボタンなどを各カラムにポチポチ配置して、可読性の高い画面をデザイナー抜きで簡単に作ることが出来ちゃいます。 もちろんボタンに導線を作ることもできるので、

  • ボタンを押すとチェックリストにチェックが付く
  • ボタンを押すとモーダルを表示してデータ編集ができる

といった処理を組むことも簡単です。 ちなみにモーダルもelementで用意されています。

http://element.eleme.io/#/en-US/component/dialog

いたれりつくせりですね。

・・・どうですか?管理画面に<el-table>使いたくなりませんか?

実際に使う上でのtips

<el-table>の素晴らしさがわかったところで、実際に作っていく上でのポイントをいくつか書いていきます。

基本的なデータフロー

前項でも述べましたが、<el-table>に格納するデータは、Ajaxの戻り値をそのまま格納するのがわかりやすいので、 「データを取得する共通処理」を一つの共通メソッドにまとめておき、表示・更新したいタイミングで呼び出す のが基本的な実装パターンになります。以下はデータ読み込み処理のコード例です。

// レコード取得を実施
getModels:function(){
  var that = this
  this.isLoading = true // (1)ローディング表示をON
  $.ajax({ // jQuery ajax使ってますが他のライブラリでも対して変わらないはず
    url:this.apiUrl,
    type:'GET',
    data:this.condition // (2)GETパラメータをプロパティ
  }).done(function(data){
    // API戻り値をtableDataに格納
    that.tableData = data.models 
    that.isLoading = false
  })
},

いくつかポイントを上げると、

  • APIを呼び出すタイミングでローディング用のプロパティをONにし、読み込み後にOFFにすることでローディングを実装
    • ローディングステータスは<el-table v-loading="loading"> という感じで、v-loadingディレクティブにbindすることで、プロパティと同期できます。
  • 検索クエリとページネーションはプロパティにまとめておくと、そのまま渡せる(検索ボックス側でthis.conditionを編集する作りにすると、検索側と読み込み側が疎結合になるので扱いやすい

という感じです。

データ表示の基本2タイプ

表示カラムは<el-table-column> を使うといいましたが、2つの記法があります。

el-table-column::prop で簡単カラム指定

<el-table-column prop="full_name" label="氏名">
</el-table-column>

propプロパティに直接Objectのキーを指定すると、文字列としてデータが表示されます。

template slot-scope="scope" で細かく指定

もう少しリッチに各カラムのデータを書きたい場合は、このように書きます。

<el-table-column label="タグ一覧">
  <template slot-scope="scope">
       <el-tag v-for="tag in scope.row.tags" :key="tag.id" type="success">{{tag.name}}<el-tag>    
  </temlate>    
</el-table-column>

ポイントとしては

  • <template slot-scope="scope"> で囲んだ中に、そのカラムで表示したいHTMLを配置
  • scope.row.[カラム名] で各レコードの情報が参照できる

です。このやり方を使うと、カラムの中で自由にレコード情報を表示ことができるため、 先程あげたような

f:id:itpro_goto:20181203220644p:plain

  • 画像を貼り付けたり
  • カラム内で改行して複数の情報を表示したり
  • アクションボタンを配置したり

とかなり応用が効くようになります。

テーブルの行番号を取得したい。

行番号は scope.$index で取得できます。

<el-table-column width="50" fixed>
  <template slot-scope="scope" label="No">
    {{ scope.$index}}
  </template>
</el-table-column>

発展パターンとして、ページネーションを実装している場合のレコード番号は、

<el-table-column width="50" fixed>
  <template slot-scope="scope" label="No">
    {{ getRecordSequence(scope.$index)}}
  </template>
</el-table-column>

というふうに外部メソッドにscope.$index を投げて、

getRecordSequence(index){
  if(!this.paginate.page || !this.paginate.perPage){
    return index + 1
  }
  return (this.paginate.page - 1) * this.paginate.perPage + index + 1
},

こんな感じで、ページネーションの値と組み合わせて算出したりもします。

ページネーション

<el-table> はページングのための特別な仕組みを持たないため、

  • dataプロパティに「ページ情報」と「総ページ数」を用意しておき、API更新のタイミングで同期する
  • 画面側のページング表示、操作は<el-paginate> コンポーネントを別途配置して、こちらもAPI更新と紐付ける

というやり方で実装します。

データ構造

data:{
  condition:{
    page: 1, // 現在のページ数(conditionに含めることでクエリパラメータとして渡される
  },
  pageCount: 1, //ページ数を取得
},
methods: {
  getModels:function(){
    var that = this
    $.ajax({ // jQuery ajax使ってますが他のライブラリでも対して変わらないはず
      url:this.apiUrl,
      type:'GET',
      data:this.condition 
  }).done(function(data){
    that.tableData = data.models 
    that.isLoading = false
    that.pageCount = data.paginate.pageCount //総ページ情報を更新
    that.paginate = data.paginate //現在ページ情報を更新
  })
},
            }

ページネーション部品

<el-pagination
  @current-change = "getModels"
  :current-page.sync="condition.page"
  :page-count="pageCount">
</el-pagination>

通化のパターン

いろいろな画面で<el-table>を使うようになってくると、必要な処理を共通化したい!と思う人もいるかも知れません。結論からいうと、共通化はcomponentよりもmixinで行うのが個人的にはおすすめです。 mixin側で、

  • APIとの通信処理
  • 取得したレコード一覧や検索条件、ページネーションを保持するためのdataオブジェクト

を共通化して持っておくと、このパターンのテーブル表示を量産する上では役に立ちます。 こんな感じでしょうか。

// 管理画面の汎用テーブルプラグイン

var dataTableMixin = {
    data:{
        getUrl: '/get', // データ取得用のAPI。必要に応じて実装側でオーバーライドする。
        models: [], // 取得されたレコード配列を保持
        // 検索条件を保持。値を変更することで、レコード取得APIにリクエストクエリとして渡される
        condition:{
            page: 1, // ページ情報も検索条件の一つとして保持する
        },
        pageCount: 1, // APIから返却された総ページ数の値を保持
        isLoading: false // ローディング状態を保持
    },
    mounted:function(){
        this.getModels()
    },
    methods:{
        // ページネーション切り替え
        changeCurrentPage: function(page){
           this.condition.page = page
           this.getModels()
        },

        // レコード取得を実施
        getModels:function(){
            var that = this
            this.isLoading = true
            $.ajax({ // jQuery ajax使ってますが他のライブラリでも対して変わらないはず
                url:this.getUrl,
                type:'GET',
                data:this.condition
            }).done(function(data){
                that.models = data.models
                that.isLoading = false
                // ページネーション関連情報をセット
                that.pageCount = data.paginate.pageCount
                that.paginate = data.paginate
                that.afterGet()
            })
        },
        // レコード取得後に独自処理を追加するためのフックメソッド
        afterGet:function(){
            return //OVERRIDE ME
        },
    }
}

いかがでしたでしょうか?ぜひ管理画面もリッチな <el-table> をご活用ください!

毎月恒例!#ProLabo(プロラボ)もくもく会を@渋谷11月25日(土)に開催しました! 

こんにちは! ITプロパートナーズ(https://itpropartners.jp/)インターン栗岡です!

普段は、Laravelで自社サービスの開発をしたり、新卒採用関係の業務をやっています。

今回は、11月25日に弊社渋谷オフィスで開催されたもくもく会をレポートします!

続きを読む