文学部歴史学科出身の社会人がエンジニアになるまでやった事/やらなかった事
早いものでエンジニアとして働き始めてから今月でもう1年です。
1年前は時給1,000円ちょっとのバイトと派遣をやっていました。
先日ようやく正社員としてプロエンジニアになれたので、この機会に文学部出身のぼくが勉強し始めてからの3年半でやった事/やらなかった事を備忘録的に残していきたいと思います。
対象読者
- 文系だけどIT業界ではたらきたい学生
- これからプログラミングを勉強してIT業界への転職を考えている社会人
- すでにプログラミングを勉強中の社会人(←エラい)
- 未来の自分
ただの備忘録ではありますが、これからIT業界を目指す誰かの参考になれば嬉しいです。
サマリー
エンジニア以前
タイトルにもある通り大学では文学部歴史学科に所属しており、1行もコードを書いたことがありませんでした。
また最初の仕事も観光・宿泊業だったのでITに全く縁がありませんでした。
「会社のHPとかあればカッコいいなー」「ネットで集客できれば便利だなー」くらいのモチベーションで勉強し始めたのがきっかけです
沼への入口
エンジニアコミュニティの門を叩く
当時僕がいた京都にはCamphor-という学生ITコミュニティがあり(今もある)、そこのエンジニアを紹介してもらったのが沼への入口です。
(余談ですが、初めてエンジニアに会うのに予備知識が無いのは流石に失礼かと思いdotinstallでHTMLとCSSを勉強していきました)
このコミュニティに迎えてもらったおかげで素晴らしいメンターに巡り会えただけでなく、優秀なエンジニアを定点観測することで彼/彼女らが日頃どの程度のInput/Outputを行なっているのかを学ぶことができました。
「現在の地点」でInput/Outputに差が出るのは経験の差なので仕方ないですが、「半年後の地点」でInput/Outputの成長度合いに差が出るのは別の理由があるはずです。優秀なメンバーの「成長度合い」を学習のペースメーカーとして利用できた点で、始めにコミュニティに所属できたのは大きかったかなと思います。
0ヶ月目~: dotinstallでの自己学習
前述のエンジニアコミュニティに顔を出す前の予習としてスタート。やれるとこまでやって質問を1つ持って行こうと決めていたので、HTMLとCSSを修了し、「ローカルサーバーを立てる」章でつまづくまで進めました。
dotinstallには大抵の技術のいろはが揃ってるので、今でも新しい技術を身につけたあとに、タイトルだけ眺めて要点を抑えられてるか確認するため利用しています
この時学んだ事:
- HTML/CSS
- 黒い画面の触り方
2ヶ月目~: Wordpressでサイト制作
「Webサイトを作るにはWordpressを勉強すれば大丈夫」と聞いたので本を買ってブログサイトを作りました。
カスタムテンプレートを自作することで動的にサイトを組むという概念に触れられ、コピペでjQueryも使ってみたりしました。書籍だけでは当然情報不足なのですが、幸いにもWordpressの情報は日本語でも死ぬほどネットに落ちているためそちらも参考にしました。
この延長で自社の会社情報サイトも制作することになり、入り口としては良かったのかなと思います。サイトの公開作業はエンジニアに丸投げしました。
この時学んだ事:
- Wordpressの使い方
- PHPでHello world
10ヶ月目~: Ruby on Rails (Viewだけ)
社内でRailsを使ったWebサービスを作ることになりましたが、人材が不足していたのでMVCのView部分だけ担当しました。自分でもRails Tutorialにチャレンジしたのですが、巨大な壁にはじき返されたのを覚えています。
また、表示に必要なデータを自分でも用意するためController部分も少しだけ触らせてもらいました。
この時学んだ事:
1年2ヶ月目~: Slack Bot
いわゆる"プログラム"的なものが作りたくてSlack Botを作りました。名目としては「業務効率化」のためでしたが実際はネタBotばかり作っていました。その時の記事がこちら。
この頃からJavaScriptで簡単なロジックを書いたりするのがだんだん楽しくなって来ました
この時学んだ事:
- JavaScript (ES5)
- Google Apps Script
- Coffee Script
- Herokuへのデプロイ
1年3ヶ月目~: クローラーの作成(コピペ)
業務でホテル予約サイトやAirbnbのデータを分析する機会があったのですが、MITの学生がクローラースクリプトを公開していたので(下記)そちらを参考にして(コピペして)自社向けのスクリプトを開発しました。
実行は手動で行わなければならずシンプルなCSVを出力するだけのものでしたが、自動で大量のデータを集めることができるのが面白く、いろんなサイトのクローラーを20種類くらい作成しました。DOMを解析したり、HTTP通信の仕組みを勉強できて楽しかったです。
この時学んだ事:
- Pythonの基礎の基礎
- HTTP通信の仕組み
- DOMの仕様
1年5ヶ月目~: Ruby on Rails
3回くらい挫折したTutorialをようやく終えて自分でもサービスを作りたくなってきました。初めてスクラッチからアプリケーションを作り、メンターにボコボコにレビューしてもらいながら一応のリリースまで持って行けて良かったです(すぐクローズしたけど)。
このときはRubyでクローラーも書きましたが、デプロイとインフラは相変わらずリードに丸投げ。
この時学んだ事:
2年2ヶ月目~: Vue.js (SFCだけ)
リードがRailsアプリにVue.jsおよびモダンJSの開発基盤を整えてくれたので、コンポーネントファイルのメンテだけ担当しました。世間的にはちょうどv2.0が出て来てVueが注目され始めたころです。RailsとAPIで通信してUIゴリゴリ動かすのめっちゃ楽しいやんけ、ってなりました。
この時学んだ事:
2年6ヶ月目~: Docker (エンジニアデビュー)
メンタル病んだりいろいろあって会社を離れたものの、手につく職も特になかったのでエンジニアデビュー。 事務作業の片手間でやってたプログラミングがどれだけ世間で通用するか分からなかったので、修行のつもりでWeb制作会社でWordpressのバイトをさせてもらいました。
Wordpress周りのタスクならそれなりにできるようになっていたので、新たにインフラに手を出したくなりDockerの勉強開始。
なんとなくでしか理解していなかったLinuxをもう一度勉強してDockerfile書いたり、docker-composeで複数のミドルウェアを組み合わせたりできるようになってエンジニアとしてレベルアップした気がします
この時学んだ事:
2年7ヶ月目~: モダンフロントエンド
環境の整ったRailsアプリでVueのコンポーネントを書いたことはありましたが、初めてゼロから環境構築するのはこの時が初めて。Webpack、Babel、ES6、Promiseやnpmの使い方などをザックリと理解して最低限のモダンフロントエンド開発環境をスクラッチで組めるようになりました。
この頃は狂ったようにRails + Vueのアプリ作って遊んでいました。だんだんRailsが面倒になってFirebaseのようなBaaSの使い方も覚えました。
この時学んだ事:
- モダンフロントエンド
- Firebase
- 高速なアプリ開発手法
2年7ヶ月目~: Perlでソシャゲ開発
バイトだけでは食べていけないので派遣に登録してソシャゲの下請けでPerlを書くように。
はじめての言語かつオレオレのフレームワークでしたが、MVCを理解してたのでなんとか仕事ができました。それなりの規模のサービスではありながら、実質3~4人で保守と新規開発を全部見てたので死ねました。
それまでORMしか触ったことがなかったので生SQLを書くときに死ぬほど怒られたし、DBやメモリのパフォーマンスなど気にしたこともないままコードを書いていたので本番障害も引き起こしてしまうなど、大規模サービスならではの経験ができて良かったです。(その節はご迷惑をおかけしました)
これがきっかけで「動けば良い」という思考から少し成長し、パフォーマンスやスケーラビリティを考慮した設計をするようになりました。
何十万行もあるクソコ温かみのあるコードベースから気合のgrepでバグを見つけ出すスキルも身につきました。
この時学んだこと:
- パフォーマンスへの意識
- 保守の大変さ
- バッチの運用方法
- CIの使い方
- チーム開発のいろは
- RDBMSの仕様
3年目~: React Nativeでモバイルアプリ開発
バイトと派遣を継続する傍ら、受託案件もいただけるようになりました。フロントエンドが足りていないとのことだったので「よっしゃVueやるぞー!」と意気込んだものの、アプリ開発もやってほしいとのことで泣く泣くReactおよびReact Nativeで開発することに。
社内はおろか周囲にもReduxやReact Nativeの知見を持った人がいなかったので、海外のチャットコミュニティや掲示板で情報収集しながら開発を進めるのはなかなか楽しい経験でした。レールのない世界でスケーラブルなアーキテクチャを模索するのは面白かったです。
まだ開発中でリリースまではいけてないのですが、Xcodeを触る中でモバイルアプリのパラダイムも学ぶことができてとても勉強になりました。
この時学んだこと:
- React
- React Native
- Redux
- Xcode
- Android Studio
3年2ヶ月~: データ分析と機械学習
バイト先まで片道2時間ほどかかっており、ゲームや読書で時間を潰すのも飽きたのでデータサイエンスを勉強し始めました。
そもそも数1Aの記憶すら怪しい文系マンなので、まずは数3Cまで勉強し直すところから。その後UdacityのData AnalystコースとCourseraのMachine Learningコースを受講しました。ライブラリを使えば簡単な画像判定ツールくらいは作れますが、スクラッチで実装しろと言われると厳しいレベルです。
3ヶ月ほど勉強してみましたが他のことに興味が移ったので学習はストップしています
この時学んだこと:
3年6ヶ月目: 現在とこれから
2018年3月1日よりmerpay, Inc.でフロントエンドチームの立ち上げに参画しています。
mercari本社はReactの会社なのですが、merpayではVue.jsを採用して会社全体で新たなチャレンジを行なっている最中です。 BFFサーバーとしてNuxt.jsも採用しているため、「フロントエンドチーム」と名乗りつつバックエンドに踏み込んだ仕事もできる魅力的な環境だと思います。
疑いの余地なく日本で最高のメンバーと最高にBoldな未来を創っていける職場なので、この場所でもっとディープにWeb技術全般を学習・検証していくつもりです。
エンジニアリングを始めてからの数年間、様々な経験を公私ともにさせてもらって本当に恵まれていました。 これからは積極的にイベント等に登壇してコミュニティに還元していきたいと思います。
やらなかった事
これまでで自分がやってきた事を書き終わったので、最後に自分が「やらなかった事」を簡単に紹介します。
ハッカソンに出る
ハッカソンは一度だけ出てもう良いかなって思いました。良くも悪くもいろんなレベルの人がいるので必ずしもプラスにならないのと、ハッカソン常連の仲良しコミュニティ感が肌に合わなかったです。技術力だけじゃなく参加回数や業界年数を加味したコミュニケーションを強いられてバチバチ勝負出来なかったので、やや消化不良気味でした。
魅力的な景品や、同レベル以上のライバルがいる事が保証されてるならアリだと思います。
勉強会を主催する
コミュニティに参加するのは大好きですが、勉強会の企画・運営はあえて避けていました。キャリアの浅いうちから外の人を巻き込んでしまって責任ばかり肥大すると、自分自身のフットワークを殺してしまうかなと思ったからです。
勉強会やイベントの運営ノウハウを学ぶのも大事なのでこの辺りはトレードオフですね。
本を読む
始めこそWordpressの教科書みたいな本を買いましたがそれ以来ほとんど買っていません。他にもRubyのクローラー本やインフラ関係の本を買いましたが、ほぼ流し読み。
情報が体系的にまとまってるのはありがたいですが、勉強したてのころは必要に応じて様々な情報に網羅的に目を通すのが僕には合っていました。普段からブラウザのタブを常に40個くらい開いて横断的に参照しているタイプなので、同程度の本を複数回し読みする運用はキビしかったです。
おかげで(?)海外のフォーラムを覗くのに抵抗がなくなりましたし、複数の著者(情報の提供者)の意見を統合して最終的な情報の良し悪しを判断するクセみたいなものがつきました。
逆にリーダブルコードのようなバイブル的なやつは読んどくべきだったかも、と最近反省しています。
最後に
エンジニアになる以前も営業、経営企画、経理、法務、労務、マーケ、CS等々いろいろやっていましたが、結局今の仕事が一番肌にあっている気がします。
IT業界の面白いところは、会社の枠を超えて業界全体で知識の共有とアップデートが文字通り秒単位で行われている点です。自分がどれだけ勉強しても天井が見えず、「もっともっと勉強してやろう」というモチベーションを他者から得られます。これは他の業界ではなかなか見られない現象です。
ようやくテックカンパニーに就職することはできましたが、チームではブッチギリで経験の浅いペーペーなので、遠慮なく先輩方のスキルを盗ませていただこうと思っています。
繰り返しにはなりますがぼくはコミュニティのお陰で様々な恵まれた経験をしてこられたと思っているので、今後はそこに恩返しもしつつ更に成長速度を加速させていきたいです。
以上!!年度末のエモい記事終了!!!!
おまけ
merpayの求人サイトが新しくなったので是非見てみてください。めちゃんこオシャレです。
弊社に興味ある方がいれば気軽に声かけてください。肉やりましょう。
Falcon Heavyの打ち上げは、紛れもなく僕のアポロだった
1969年7月20日 アポロ11号月面着陸
人類が初めて地球以外の天体に降り立ったこの日、全世界が熱狂した。
この「一人の人間にとっては小さな一歩」が灯した火は半世紀を経た今もなお、多くの人の心の中で輝き続けている。
ある者はその「一歩」を追って月への想いを焦がし、またある者は小惑星探査へと野望を抱き、そしてある者は火星へと夢を見た。
2018年2月7日 午前5時44分
「T-30」のアナウンスが流れた瞬間、僕の身体に電撃が走り全身の毛が逆立つのを感じた。
前の晩から興奮で眠れずとうに疲労の限界を迎えていたけれど、歴史的瞬間を前にして僕の脳からは猛烈な量のアドレナリンが分泌されていた。
25歳の冬、紛れもなく僕は「熱狂」していた。
はじめて宇宙に想いを馳せたのはおそらく9歳か10歳のころ。
小学生の僕が父とお風呂に入るときは必ず父が広い世界の話をしてくれた。ときには歴史の話だったり、物理の話だったり、地理の話だったり、社会のしくみの話だったり、そして宇宙の話だったり。
当時札幌に住んでいた僕は年に数回は青少年科学館に足を運び、プラネタリウムや天体模型に夢中になっていた。いつかの冬休みには4日間の宇宙講座に参加して、ロケットのしくみを勉強したり宇宙食を食べたりした記憶が今でも残っている。
それからしばらくの間、宇宙への想いを忘れていた僕がふたたび「それ」と出会ったのは大学1回生の夏休みのこと。
いわゆる「ブラックバイト」で消耗していた僕は、なけなしのバイト代をはたいて種子島に旅をすることに決めた。そのころから新海誠作品のファンだったこともあり、なんとなく「秒速5センチメートル」に出てきた風景に惹かれて南の島に逃げたくなったのだ。
せっかくの島旅なので北の端から南の端まで巡る計画を立て、宇宙センターの近くにも宿を取った。この時泊まった門倉荘という宿はどうやらJAXAの関係者がよく利用する宿だったようで、食堂の壁にも宇宙飛行士のサインがズラッと並ぶなどしていた。
結局、宇宙一色の町の雰囲気に押されるがまま宇宙センターの見学を申し込む形にはなったが、この時暇そうにしている僕に宇宙センター見学を勧めてくれた宿のおばちゃんには心から感謝している。
生まれて初めてロケットを見た
生まれて初めてロケットのエンジンを見た
生まれて初めてロケットの格納庫を見た
生まれて初めてロケットの発射台を見た
心の底から何かをカッコイイと思うのは、多分初めての経験で、胸の奥から熱いものが込み上げてくるのを感じた。人の手で組み上げられたものが大空の彼方まで飛んでいくのだという「現象」の衝撃が、確かな実感として心に刻み込まれた。
その日、宿に戻って食事をしてから種子島の夜道を2時間ほど散歩した。
思えばこの時が人生で初めてしっかりと自分の将来について考えた瞬間なんだと思う。それまでもぼんやりと「ここの高校に行きたい」「ここの大学に行きたい」「こんな仕事をしたい」などと考えたことはあったけれど、「何を成し遂げて死ぬのか」を明確にしたことはなかった。
宇宙センターでのことを思い出し、夜道を照らす星々の美しさに感謝し感激し、それまでの人生について振り返り、それまで訪れた様々な場所や出会った人々のことを思い出し、そしてなにより若くして命を落とした友人たちの生き様を振り返った時に、19歳の僕は「宇宙を見てから死のう」と決意した。
25歳の僕は、まだ夢を叶えていない。
この6年間でいろいろな回り道をしてきた。
短い間だが大学では歴史のロマンに魅せられて西洋史を専攻した(結局中退した)
経営者として経済的成功を勝ち取ろうとして会社を興し、テレビや新聞に取り上げてもらって浮かれていたりもした。当時は本気で億単位の金を40歳までに稼いで宇宙旅行に行こうと考えていたのだ。(結局メンタルが持たずに多くの人に迷惑をかけた)
そして現在は社会人になってから始めたプログラミングの面白さに魅せられ、技術力を高めつつ社会復帰することに身骨を砕いている。
いろいろやってきたが、多分これが一番性に合っていそうだし夢への近道なのだと最近は思っている。
結局のところ、僕は大富豪になって「宇宙観光」がしたいわけではなく、人類のフロンティアである宇宙開発に貢献し、歴史上誰もまだみたことのない世界を切り拓くことにワクワクするのだと。
去年の夏に、NASAのJPLで無人探査機の研究開発を行なっている小野雅裕さんの講演を拝聴する機会を得られた。
彼の立っている場所は、まさに僕の夢の番地だった。
技術者としてエンケラドスの氷の底を観測しようという小野さんが積み重ねてきた努力や熱意は僕が描く将来の自身のイメージそのもので、これから進む道が間違っていないのだという希望と勇気をもらえるとても素晴らしい瞬間だった。
人類がエウロパやタイタンの海を開拓していく瞬間に携わりたいと今では強く思うし、プロキシマ・ケンタウリbのような系外惑星まで衛星や探査機を届ける技術的な貢献がしたいと、空を見上げるたびに想っている。
2月7日の早朝、200万人が見つめる中でFalcon Heavy打ち上げのカウントダウンが始まった。
それまでもSpaceXのFalcon 9の打ち上げ中継を欠かさず見ていた僕だったが、この時の興奮はいつもの比ではなかった。
2004年にイーロン・マスクがFalcon Heavyの構想をぶち上げてから、多くの資金難、技術的困難、社会的バッシングがあった事を僕たちは知っている。
それら全てを笑い飛ばすかのようにFalcon Heavyは大空へと美しいを弧を描いた。
魔法のように地上へ戻ってくるロケットの姿を見て、全ての人が「これからはロケットも飛行機のように何度も再利用される時代がくるのだ」と考えるより先に肌で感じた。
火星に向けて射出されたロードスターとスターマンを見て、全ての人が「これは他の惑星に荷物や人を届けるためのロケットなのだ」と考えるより先に直感した。
この日、もう一つ個人的に思い出深かった事としては、打ち上げの瞬間を母親と一緒に見られたことだ。
ロケットやSpaceXのことはおろか宇宙のことなどほとんど何も知らない母が、この時ばかりは見たこともないくらい興奮し、「熱狂」していた姿がとても印象的だった。
人が空を見上げる時、そこには年齢も性別も国家も人種も壁なんて存在しない。
なにせあの冷戦時代のアメリカとソ連でさえ宇宙では手を取り合ったのだから(1975年7月17日 アポロ・ソユーズテスト計画)
2018年に全人類にそんな「空を見上げる」機会をプレゼントしてくれたイーロン・マスクとSpaceXのスタッフには賞賛の声を送っても送りつくせない。
打ち上げの成功を喜びあう彼らの笑顔と涙を、僕は一生忘れないだろう。
あのカウントダウンの瞬間からスターマンの中継が途切れる最後の瞬間まで、彼らが与えてくれた感動と希望の灯火を胸にこれからも夢に向かって歩んで行こうと思う。
最短距離ではないだろうしこれからも多くの人に迷惑をかけるだろうけど、もしも僕の「回り道」の途中でその灯火を誰かに分け与えることができたのなら、人類に対して少しは貢献できたと言えるんじゃないかな。
2018年2月7日、200万人と共に「熱狂」したFalcon Heavyの打ち上げは、紛れもなく僕にとってのアポロだった。
2018年2月9日 好日
今度こそVimを攻略したい:neovimをインストールして最高のdev UXを手に入れるまで(その1)
先日の記事に様々な反響をいただいたことをきっかけに「アウトプットやっぱ大事だなー」と思ったので、アドベントカレンダーに関係ないタイミングでも記事を書いてみようと思います。
僕のエディタ遍歴
- ~2014年夏:Pages
大学では歴史学を専攻していました。当時はレポートさえ書ければ良かったのでMacデフォルトのPagesを使用。プログラミングのプの字も知らなかった時代。
- 2014年夏 ~ 2015年:Sublime Text 2
仕事の合間にdotinstallでHTMLとかCSS勉強し始めた時代。プラグインも何も入れずになんとなくかっこいいなーという理由でSublimeを使っていた。この頃はWordpressの本を読んで会社サイトとか作ってました
- 2016年前半:Vim
社内で仕事をお願いしていたエンジニアが黒い画面でよく分からないことやってるの見てすごいなーという憧れでVimを使い始めた。なんとなく .dotfiles
リポジトリとか作ってみたけど .vimrc
の中身は全てネットで見たやつのコピペ。使ってる機能は1割くらいしかなかったと思います。
この頃からRails書き始めましたが、開発するには同時多発的にいろいろなファイルを触らなきゃいけないので当時のVim力では少し厳しかったです。 NERDTree
入れてたけど全然活用できなかった思い出
- 2016年後半 ~ 2017年春:Sublime Text 3
本格的にプロダクト作りたいなーとなって使い慣れたSublimeに戻ってきました。ショートカットやプラグインの使い方もいくつか覚えて体感でこれまでの3倍くらいに開発速度も向上。ブワーっとスクロールして任意のファイルの中身をザッピングできるGUIのありがたさを実感
- 2017年春 ~ 現在:Atom
サイドバーのファイルアイコンが可愛いという理由だけでAtomに乗り換え
あとは痛エディタにしたくて背景画像もこんな感じにしてました
Atomのプラグインやショートカットの手触り感はSublimeと大差ないのですが、いかせん重すぎて開く気にすらならない!!! 最近は案件でXcodeも動かすことが増えてきてだんだん辛くなってきました。。。
Vimに戻るかー
ということで主に以下の理由でVimに戻ることにしました。
いろいろなエディタを触る中で自分が開発に必要とする機能が具体的に見えてきた
昔Vimを使っていたころよりも髪の毛1本ほどは黒い画面の操作に慣れてきたので今度こそいけるやろ感
他のエディター候補としてはMSに行ったときに紹介していただいたVSCodeがとてもとても魅力的だったのですが、「Electronで動くアプリはSlackだけで十分!!」という強い意思を持ってVimを頑張っていきたいと思います。
要件
Vimは何度も挫折を繰り返しているので触り始める前に意識すべき点として以下の項目を挙げました
- 設定ファイルをキチッと管理すること
- カーソル移動のしやすさを最優先にすること
- シームレスにファイルツリーの確認とファイルの移動が行えること
1についてはいうまでもないですが、2と3は過去にVimを捨ててSublimeに走ったクリティカルな理由なので確実に攻略していきたいと思います
neovimのインストール
今回は以前から良いと評判を聞いていたneovimを利用します。(* Mac vimによくわからない破壊的変更を加えすぎて手がつけられない)
Homebrewから neovim
をインストール
$ brew install neovim/neovim/neovim
設定ファイルにpathを通す
デフォルトでneovimは ~/.config/nvim/init.vim
を設定ファイルとして参照しますが(vimでいう .vimrc
)、dotfilesを一限管理したかったので以下のようにシンボリックリンクを貼りました
$ ln -sf ~/dev/dotfiles/nvim/init.vim ~/.config/nvim/init.vim
これでdotfiles以下を変わらずGit管理できます
dein.vimでプラグイン管理
昔は NeoBundle
を用いてプラグインの管理を行なっていた記憶がありますが、今は dein.vim
というのが良いらしいですね。
init.vim
に以下のような設定を追記
let s:dein_path = expand('~/.vim/dein') " dein Scripts----------------------------------------------- if &compatible set nocompatible endif " Required: set runtimepath+=~/.vim/dein/repos/github.com/Shougo/dein.vim " Let dein mange itself if dein#load_state(s:dein_path) " Required: call dein#begin(s:dein_path) " Add or remove your plugins here: call dein#add('Shougo/dein.vim') " Required: call dein#end() call dein#save_state() endif " Install uninstalled plugins on startup if dein#check_install() call dein#install() endif " Required: filetype plugin indent on " End dein Scripts------------------------------------------- syntax enable
call dein#add(<plugin name>)
というように追加したいプラグインを記述するとneovim起動時にそのプラグインが自動でインストールされます。
また、まだ試していませんが TOML
という形式のファイルを別に作成してそれを dein.vim
から読み込むこともできるらしいので、もう少しプラグインの数が増えたら試してみます
カーソルの移動速度を上げる
これは多分Mac独自のHack。「システム環境設定」 -> 「キーボード設定」を見るとキー入力に対するディレイとリピート速度が設定できるので、こちらから適度なスピードに変更。
tmux上でのモード切り替え速度を上げる
インサートモードからノーマルモードへの切り替えがもっさりしていたので調査。どうやらtmux側でescキーに対して入力待ちをしていたのが原因のよう。デフォルトで500msくらいの待ちが発生していたようなので ~/.tmux.conf
に設定を追記
set -g escape-time 0
tmuxをリフレッシュすると動作がサクサク快適になりました
NERDTreeを入れる
neovimの中から別のファイルを開く方法としては基本的に :e <file name>
で十分な気もしますが、視覚的にディレクトリ構造を把握した上で任意のファイルを開きたいという欲求があったので NERDTree
をインストールしました。
call dein#add('scrooloose/nerdtree')
という一行を追記するだけ。
また、ファイルツリーを開く際にいちいち :NERDTreeToggle
などと打つわけにもいかないので以下のkeymapを init.vim
に追加
map <C-t> :NERDTreeToggle<CR>
これで ctrl + t
でファイルツリーを開けるようになりました。
また、 NERDTree
上でのファイルの視認性が悪かったので、以下の設定を追記して拡張子ごとにHighlightするようにしました
" NERDTress File highlighting function! NERDTreeHighlightFile(extension, fg, bg, guifg, guibg) exec 'autocmd filetype nerdtree highlight ' . a:extension .' ctermbg='. a:bg .' ctermfg='. a:fg .' guibg='. a:guibg .' guifg='. a:guifg exec 'autocmd filetype nerdtree syn match ' . a:extension .' #^\s\+.*'. a:extension .'$#' endfunction call NERDTreeHighlightFile('py', 'yellow', 'none', 'yellow', '#151515') call NERDTreeHighlightFile('md', 'blue', 'none', '#3366FF', '#151515') call NERDTreeHighlightFile('yml', 'yellow', 'none', 'yellow', '#151515') call NERDTreeHighlightFile('config', 'yellow', 'none', 'yellow', '#151515') call NERDTreeHighlightFile('conf', 'yellow', 'none', 'yellow', '#151515') call NERDTreeHighlightFile('json', 'yellow', 'none', 'yellow', '#151515') call NERDTreeHighlightFile('html', 'yellow', 'none', 'yellow', '#151515') call NERDTreeHighlightFile('styl', 'cyan', 'none', 'cyan', '#151515') call NERDTreeHighlightFile('css', 'cyan', 'none', 'cyan', '#151515') call NERDTreeHighlightFile('rb', 'Red', 'none', 'red', '#151515') call NERDTreeHighlightFile('js', 'Red', 'none', '#ffa500', '#151515') call NERDTreeHighlightFile('php', 'Magenta', 'none', '#ff00ff', '#151515') call NERDTreeHighlightFile('vue', 'Green', 'none', '#4fc08d', '#4fc08d')
その他
Vueファイルのシンタックスハイライトを追加する
Vue.jsのSingle File Componentである .vue
だけシンタックスハイライトがなくて寂しかったので以下のプラグインを追加しました
まれに動作が不安定な時もありましたが、以下の設定を init.vim
に追記して解決
" autohighlight vue file autocmd FileType vue syntax sync fromstart
emmetを入れる
本業がマークアッパーなのでemmetは必須。ということでdein.vimから emmet-vim
入れました
call dein#add('mattn/emmet-vim')
また、デフォルトだとemmetのkeymapが <C-y>
なのでAtomやSublimeを使ってた人間からするとちょっと不便。
" Configure emmet-vim " set trigger key let g:user_emmet_leader_key='<C-e>'
こんな感じに書くとAtom風にkeymapを変更できます。
実際に呼び出す際は ctrl + e + ,
というように末尾にカンマが必要なので注意
動いた 👏👏
個人的に便利だなーと思ったこと
今回新しくゼロから学んでみて、個人的に便利だなーと思ったneovim(vim)の機能を羅列します。始めてVimを触ったときに知っておきたかった...
o
で次の行を空けてインサートモードに移行:
なんでいままで行末に移動 → インサートモードに移行 → 改行、なんて面倒なことをやっていたんだろうw
0
で前の行を空けてインサートモードに移行:
上に同じ。
r
キーで1文字だけreplace
TypoScriptの使い手なので「1文字だけ修正したい」というケース非常に多いのでとてもありがたい。
I
で行の先頭に移動してインサートモードに移行:A
で行末に移動してインサートモードに移行:ctrl + o
で直前に開いていたファイルに戻るctrl + i
で上記の逆
などなど挙げればキリがないので、続きはまた別の記事にまとめたいと思います。
Vim楽しくなってきたのでもっと使いこなすぞー
Storybook for Vueでエンジニアとデザイナーの協業を加速させる
この記事はCAMPHOR- Advent Calendar 2017の23日目の記事です。
はじめに
アプリケーションの機能を「カプセル化」、「コンポーネント化」しようというのは、フロントエンド/バックエンド問わずに近年のWeb開発におけるトレンドのひとつです。
Web業界も5年もの、10年ものと呼ばれるシステムが増える中で「最初から完璧なシステムを作ることなんて無理なんじゃないか」と多くの人が気づきはじめました。 その流れを受けて「どうせ改修が必要なら、小さなスコープで新しいものに置き換え可能な仕組みを作ろうぜ!」というのが「カプセル化」、「コンポーネント化」の大きなモチベーションであると、個人的には理解しています。
Vue.jsとコンポーネント
JavaScriptのフレームワークであるVue.jsも、例に漏れずコンポーネントドリブンな開発に適した仕組みの1つです。
SFC(Single File Component)として知られる .vue
ファイルに template
や script
を切り離せるだけでなく、 Scoped CSS
の仕組みを用いてスタイリングでさえ1つのコンポーネントに限定して適用できるなど、非常に再利用性の高いコンポーネント設計が行えて重宝しています。
またVue.jsの大きな特徴として、既存のHTMLとさほど変わらないシンタックスでコンポーネントが記述できるという点が挙げられます(もちろんJSXで記述することもできます)。HTMLやCSSについての基本を抑えていればJSが苦手なWebデザイナーさんにも作成・改修依頼が投げられるというのは、常に人材不足に泣かされる中小Web制作会社としては非常にありがたいですね!
今回紹介するSrotybook for Vueは、そんな現場レベルでデザイナーさんとフロントエンドエンジニアの協業を加速させるためのツールです。
Storybookとは
Storybookとは、iframeを用いたサンドボックス上でコンポーネントの挙動をチェックできるUI開発環境です。ただのテストツールとしてではなく、スタイルガイドとしての利用も想定されているため、エンジニアだけでなくデザイナーさんにも役立つツールとして期待されています。
StorybookはもともとReactユーザー向けのツールでしたが、 v3.2.0
からVueもサポートされ、現在はReact Native Webにも対応しました。
事例諸々
公式ページより様々な企業の導入事例を見ることができます。
https://storybook.js.org/examples/
各社ユニークなStorybookを用意していて眺めているだけで面白いです。会社の顔にもなるようなスタイルガイドを簡単に作れるなんてワクワクしますね。
今回はこのStorybookの導入 → Storyと呼ばれるStorybook内のページにVueコンポーネントを追加するまで、の流れを追っていきたいと思います。
本記事の対象
- ES6分かるマン/ウーマン
- Vue.jsなんとなく分かるマン/ウーマン
- Storybookにとりあえず興味あるマン/ウーマン
本記事のゴール
いつも前置きが長く申し訳ないですが、本記事は以下のことを目的として書かれています
- Storybookの概要を知ってもらう
- 「Storybook、意外とカンタンやん!」と思ってもらう
- 社内で投入する前に個人的に試した内容の作業ログを残したい
まぁ、ほとんど3つ目がメインです。それでは上記を踏まえた上で早速Storybookを動かしてみましょう。
Storybookを導入する
まずはvue-cliでアプリを作成
$ vue init webpack sample // console上で対話しながらアプリケーションを作成 $ cd sample $ yarn $ yarn run dev
Storyobookの公式ページにはQuick start guideの他に、Slow start guideというページが用意されているので今回はそちらを参考にします。
$ yarn add -D @storybook/vue // devDependenciesにstorybookを追加
Yarn scriptに起動コマンドを記述
{ "scripts": { "storybook": "start-storybook -p 9001 -c .storybook" } }
.storybook/config.js
に設定を記述
import { configure } from '@storybook/vue' // ストーリーの読み込み function loadStories() { require('../src/stories') } configure(loadStories, module)
読み込むStoryを作成する前に、ボタンを表示するコンポーネントを雑に用意します
<template> <button>Hello Vue</button> </template> <style scoped> button { color: green; border-radius: 5px; font-size: 18px; line-height: 1.5; padding: 0 10px; } </style>
// src/stories/index.js import { storiesOf } from '@storybook/vue' import MyButton from '../components/MyButton.vue' storiesOf('Buttons', module) .add('simple', () => ({ components: { MyButton }, template: '<MyButton/>' }))
Yarn scriptで Storybook
を起動
yarn storybook
ブラウザで localhost:9001
にアクセスしてStorybookが表示されていることを確認します
無事にコンポーネントがiframe上に描画されました。
またWebpackのHMR(Hot Module Replacement)が有効になっているので、コンポーネントファイルを編集すると変更が動的に反映されることが確認できます。
Addonsを使う
このままでは少し寂しいのでStorybookにAddonsを追加して機能や見た目を拡張していきましょう
Storybook Addon Actions
Storybook Addon Actions
はイベントハンドラから渡ってきたデータの確認やロギングができるAddonです。
Yarnでインストール
$ yarn add -D @storybook/addon-actions
新しくAddonsを追加する際は .storybook/addons.js
に追記する必要があります
// .storybook/addons.js import '@storybook/addon-actions/register'
Addonから action
関数をimportして、ボタンの onClick
イベントと紐づけてみます
import { storiesOf } from '@storybook/vue' import { action } from '@storybook/addon-actions' import MyButton from '../components/MyButton.vue' storiesOf('Buttons', module) .add('simple', () => ({ components: { MyButton }, template: '<MyButton @click.native="action"/>', methods: { action: action('button-clicked') }, }))
コンポーネントの @click
に対して .native
修飾子をつけると、root要素のイベントを監視できるんですね。初めて知りました。
上記のコードを確認してみます
Storybook内に「ACTION LOGGER」というパネルが表示され、コンポーネントのイベントにフックしたログが表示されるようになりました。これを活用すると、より細かくコンポーネントの挙動を確認することができますね!
storybook-addon-vue-info
storybook-addon-vue-info
は、コンポーネント情報の表示を改善してくれるAddonです
Yarnでインストール
$ yarn add -D storybook-addon-vue-info
Exampleを参考に decorator
として実装
import { storiesOf } from '@storybook/vue' import { action } from '@storybook/addon-actions' import VueInfoAddon from 'storybook-addon-vue-info' import MyButton from '../components/MyButton.vue' storiesOf('Buttons', module) .addDecorator(VueInfoAddon) .add('simple', () => ({ components: { MyButton }, template: '<MyButton @click.native="action"/>', methods: { action: action('button-clicked') }, }))
ついでに MyButton.vue
も少し改修
<template> <button>{{ text }}</button> </template> <script> export default { props: { text: { type: String, default: 'Hello Vue' } } } </script>
props
でボタンに表示するテキストを受け取るようにしました。デフォルトは "Hello Vue"にしています。この状態で表示チェック
このように、 decorator
をつけたStory内のコンポーネントについての使用例とコンポーネントの持つことができるprops等が体系的に表示されました!
お手軽便利系のAddonです。
Knobs
GUIからコンポーネントの持つプロパティの情報を更新できるAddonです。
Yarnでインストール
$ yarn add -D @storybook/addon-knobs
addons.js
に追記
import '@storybook/addon-knobs/register'
decolator
としてStoryに追加します。今回は props
として label
と backgroundColor
を受け取る ButtonWarning
コンポーネントを用意しました
import { storiesOf } from '@storybook/react' import { withKnobs, text, color } from '@storybook/addon-knobs' import ButtonWarning from '@/js/components/ButtonWarning' ... storiesOf('Buttons', module) .addDecorator(withKnobs) .add('warning', () => { const label = text('Label', 'Warning') const backgroundColor = color('Color', '#ffffff') return { components: { ButtonWarning }, template: `<ButtonWarning label="${label}" backgroundColor="${backgroundColor}" />` } })
text()
, color()
という関数を利用することで、それぞれの値に対する input
フォームのようなUIが表示されるようになります
色の調整や文字列の変更が誰でもできるようになって最高 :clap::clap:
Links
Story内から別のStoryを表示する(遷移する)ためのAddon。
詳細は割愛
その他のAddon
基本的にUIをスッキリさせる系のAddonsが多い印象ですが、今回は全て試せませんでした。公式にGalleryが用意されているので、興味のある方は以下のリンクからご確認ください。痒いところに手がとどくAddonが見つかるかもしれません
https://storybook.js.org/addons/addon-gallery/
実際に使ってみた
手元にあったコンポーネントを突っ込んで作成したStorybookがこちらになります
デザイナーはすぐに見た目のレビューができるし、エンジニアはデザインの変更を差分で管理できるしで、なかなか幸せな世界に近づいたのではないでしょうか
まとめ
Storybook本体のVue.js対応が行われたばかりということもありまだVue.jsに対応していないAddonsが多いようですが、スタイルガイドとしては必要十分な仕組みが備わっているように感じました。
最初の設定はクセがありますが、一度導入してしまえば機械的にコンポーネントを追加していくだけなので中規模以上のSaasを運用するケース、受託案件を小さく大量に回すケース、どちらでも活用できるのではと思います。
社内での本格的な実践投入はこれからですが、再利用可能なコード資産が1つでも多く残せるよう時間をかけて育てていきたいです。
明日はohmurakenの記事です。お楽しみに!
Yet Another Bundler - Parcel + Vue.jsの可能性を模索した話 -
この記事は Vue.js #1 Advent Calendar 2017 - Qiita 15日目の記事です。
今年もアドベントカレンダーの季節がやってきました! ブログ書くのは1年ぶりですねw
まずはネタ探しということで最近はReact Nativeを書いている時間が長いのもあり、はじめはVue.jsでモバイルアプリが作れるWeexについての記事を書こうといろいろ準備していました。
そんな穏やかな冬の午後・・・
またなんか出た
ちょっと待ってくれ
先週社内でWebpackの勉強会したばっかなんだけど・・・
↑↑ やりきった感のある投稿の様子
正直、
(ほんともう勘弁してくれ〜〜〜)
って感じだしBrowserifyやWebpackをはじめとしたバンドラ論争に振り回されたみなさんの中には怒りすら覚えた人もいるのではないでしょうか
とは言っても
触ってみないことには良いも悪いもわからないので、話題のParcelについて調査してみました。
- 筆者はフロントエンド歴1年未満
- Parcelを触りはじめてから1週間くらい経つけど、実質触ったのは3日くらい
- Parcel自体の開発速度が早く、閲覧いただいている時点では情報が古いかもしれません。記事執筆時点では
v1.1.0
を使ってます
上記にご留意の上、お楽しみください
本記事の対象
webpack.config.js
を書いたことがある人- なんとなく
webpack.config.js
が読める人 - とりあえず新しい技術に飛びついてみたい人
「フロントエンドよくわからん」って人にはよくわからんかも知れないけど、僕もよくわからんのでそのへんは雰囲気で
Parcelとは
本記事のテーマであるParcelとは、AdobeのエンジニアであるDevon Govettさんが開発したJavaScript製モジュールバンドラです。
モジュールバンドラとは複数のファイル(モジュール)に書かれたJSのコードを1つに合体させて(バンドリング)吐き出してくれるツールで、同様の機能を持ったものとしてはBrowserifyやWebpackなどが有名です。
開発自体がスタートしたのは今年(2017年)の8月のようですが、爆発的にGitHubスター数が増えはじめたのは12月の頭に v 1.0.1
がリリースされてからのこと。
記事執筆時点ではそれから9日間で10,000近くのスターを集めています。
何が新しいの?
フロントエンドエンジニアの中には兼ねてよりバンドラ周りの設定の複雑さに辟易とする人が多くいました。(いわゆる「Webpack疲れ」)
エントリポイントと出力先を指定するだけなのに、なんでわざわざ外部ライブラリまで使ってあんな面倒な設定書かなあかんねんというご意見には、僕もわかりみしかない。。。
さらにそこにローダーの設定とそれらを通したいファイルの拡張子を正規表現で指定して、対象外のディレクトリを指定して、プラグインを設定して、といったオプションが上積みされていき、気づいたときには立派な秘伝のタレが出来上がっているわけです。(メンテを押し付けてしまった後輩くん、本当に申し訳ない・・・)
そんな中、流星の如くParcelは現れました
zero configuration web application bundler
というメッセージからもわかるように、Parcelはカオスな複雑化の一途を辿るフロントエンド界に新しい風を吹かせようという想いで産み出されたツールです。
後ほどまた触れますがParcelの主な特徴は以下の通り
- 設定ファイルを全く書かなくてもモジュールバンドリングできる(zero config)
- プロジェクト内でトランスパイラの設定ファイルを検知すると、自動でトランスパイルしてくれる(Parcelの設定は必要なし)
- デフォルトでHMR(Hot Module Replacement)に対応済み
- 速い!(*公式ベンチで対Browserify比最大8.7倍、対Webpack比最大7.8倍)
これが全て本当ならワクワクしますね。さっそく試してみましょう!
まずは動作確認
Yarnでインストール
$ yarn init -y $ yarn add parcel-bundler
Parcelはモジュールバンドリングのエントリーポイントとしてどのような拡張子のファイルも受け取れるようですが、公式ではHTMLもしくはJavaScriptファイルを指定する事が推奨されています。
今回は index.html
を起点にパス解決を試してみましょう。
<!-- index.html --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Parcel Test</title> </head> <body> <h1>Hello World!</h1> <script src="./index.js"></script> </body> </html>
// index.js import { hoge } from './hoge'; console.log(hoge);
//hoge.js export var hoge = 'Hoge';
ファイルの準備ができたら parcel
コマンドにエントリーポイントとなるファイル名を指定して実行してみます。シンプルで分かりやすいですね。
$ node_modules/.bin/percel index.html
上記コマンドを実行するとNodeのホスティングサーバーが立ち上がるはず
デフォルトのポート番号として 1234
が割り当てられるので http://localhost:1234/
にブラウザからアクセスしてチェック・・・
・
・
・
・
・
・
・
・
・
・
・
ところがエラー!!
どうやらPercelがコンパイルしたファイルに構文エラーが含まれているようです
いろいろ試しても解決方法がわからず困っていたところ、コミュニティに質問を投げると秒速で回答をいただきました
感謝感謝!!
手元のNodeバージョンが v7.10.0
だったので、アドバイスに従ってnodebrewで v8.1.0
に変更 & 再チャレンジ。
今度はちゃんとモジュールバンドリングに成功しました :muscle: :muscle:
↑↑ hoge.js
の中身が index.html
に読み込まれて出力されている様子
公式のissueにも上がっていましたね。
毎回コマンドを打つのが大変なので起動スクリプトを設定しておきましょう。
{ "name": "parcel", "version": "1.0.0", "main": "index.js", "license": "MIT", "scripts": { "start": "./node_modules/.bin/parcel index.html", "watch": "./node_modules/.bin/parcel watch index.html" }, "dependencies": { "parcel-bundler": "^1.1.0" } }
また、Parcelを実行する際に watch
コマンドを実行すると配信サーバーは起動せずにファイルの変更だけ検知させることができます
Parcelは何をしているのか
もう少し詳しくParcelの挙動を見ていきましょう
上記で Parcel
コマンドを実行するとディレクトリ内に /.cache
と /dist
という2つのディレクトリが新たに生成されます。
実際に ./dist/parcel.js
をのぞいて見ると、Webpackで生成した bundle.js
にそっくりなモジュールバンドリング済みJSファイルであることがわかりますね。
Parcelは起動時に /.cache
ディレクトリの中身をヒントにコンパイルを行い、 /dist
以下のファイルをNodeサーバーから配信しているようです
Babelでトランスパイルする
ここまで設定なしでモジュールバンドリングをすることができました。 今度はES7のトランスパイルを行なってみましょう。
Webpackでは正規表現でターゲットのファイルタイプを指定して babel-loader
を設定することでビルド時にトランスパイルが行えましたが、Parcelは実行したディレクトリ内に .babelrc
があるのを検知すると自動でやってくれます(← 便利)
まずは babel
のインストール
$ yarn add babel-core babel-preset-env babel-polyfill
.babelrc
を記述
{ "presets": ["env"] }
ES7からの新機能である async/await
を用いてParcelのGitHhubレポジトリにいくつスターが付いているか fetch
してみます。
// index.js import "babel-polyfill"; import { fetchStars } from './fetchStars'; const SOURCE = "https://api.github.com/repos/parcel-bundler/parcel"; fetchStars(SOURCE);
// fetchStars.js export const fetchStars = async source => { // fetch console.log("Start fetching...") let response = await fetch(source); // parse console.log("Start parsing..."); const json = await response.json(); const name = json.name; const stargazers_count = json.stargazers_count; console.log(`${name} has ${stargazers_count} stars!`); }
$ yarn run start
を実行してParcelを起動
.babelrc
を記述するだけで、無事にES7のコードが動きました!!
うーん確かにこれは便利だ。
その他のローダーへの対応
筆者は未確認ですが、記事執筆時点で以下の項目についてzero config(Parcel側の設定なし)でトランスフォームしてくれるらしいです
- Babel (.babelrc)
- PostCSS
- PostHtml
- CSS Module
- LESS
- SASS
- Stylus
- TypeScript
Parcel + Vue.js
ParcelとVue.jsの相性はどうでしょうか?
まずはVueインスタンスを生成して動作確認してみます。
$ yarn add vue
<body> <div id="app"> <h1>{{ msg }}</h1> </div> <script src="./index.js"></script> </body>
// index.js import Vue from 'vue/dist/vue.esm.js'; const vm = new Vue({ el: "#app", data () { return { msg: "Hello Vue!" } } })
ここまでは動作成功
シングルファイルコンポーネントとどう戦うか
Vue.jsにはSFC(Single File Component)という仕組みが備わっており、.vue
という拡張子のファイルにHTMLライクなシンタックスでコンポーネントの要素を記述できます。
これまで、SFCを組み込んだアプリケーションのビルド時にはvue-loader
、もしくは vueify
というライブラリをWebpackまたはBrowserifyから呼び出すことでSFCのコンパイルを行なっていました。
ではParcelでこの .vue
を読み込むにはどうすれば良いのでしょうか?
先に結論
先に結論を言ってしまうと、
ParcelでSFCを扱うことはできませんでした!!
力及ばずでほんとうに申し訳ない・・・
だけど可能性は見えた(気がする)
「できませんでした」
だけでは師走の記事として少し寂しいので、今後チャレンジする人のために自分が試したことをツラツラと書き出してみたいと思います
1. Parcel Pluginについて調べてみた
Parcelの公式ドキュメントから「Advanced」の項目を見るとプラグインの作り方や、Parcel内部で任意のファイルタイプがどのようにパースされ、トランスフォームされるのかという概要を把握できます
これを見ながらParcelでSFCを処理するためのダミープラグインをまずは作ってみました。また、Parcelがバズった初日に神速でTS向けのプラグインを作ってくれたfathybさんのソースがとても参考になったので感謝です
2. .vue
ファイルをパースしてみた
SFCは template
, script
, style
という3つの要素で構成されているため、コンパイルを実行する前に一度パースしてあげる必要があります。
パーサーを自分で書く能力がなかったのでこちらは本家の vue-template-es2015-compiler
を利用しました
vue-template-es2015-compiler
は vue-loader
と vueify
の内部で利用されているライブラリです。
ドキュメントが用意されていなかったので、実際の利用方法は vue-loader
と vueify
のソースを読んでぼんやり把握しました。
parse()
メソッドを使ってSFCのパースに一応成功
3. コンパイルしてみた(かった)
実際に .vue
ファイルを .js
ファイルにコンパイルする処理です。
これは現在も嵌り中...
vue-template-compiler
だけでは上手くできなかったり、 vueify
のそれっぽいAPIもそれ単体で外部から呼び出してもうまく動かなかったり、そもそもParcel自身がコンパイルをミスってたりで記事執筆時点ではまだ成功していません。無念。
Parcel + Vue.jsのこれからとvue-component-compiler
今回の「 SFCをParcelで読み込みたい」という取り組みの中で、同様の思いを持った多くの人々に助けていただきました。 特に12/9(バズった日)より参加させていただいているParcelの公式Slackコミュニティではたくさんの「ParcelとVue.jsを一緒に使いたい!」という人々に出会う事ができ、12/12には #vueチャンネルが立ち上がるまでになりました
現在もこちらのSlackでParcelのアップデートやプラグインの追加について日夜議論が繰り広げられています(Slackの通知がほとんどこれになったw)
個人的にこの規模のOSSコミュニティの立ち上げを目にする経験は初めてなので、とても良い刺激をもらっています。
また、SFCのコンパイルについて調べていくうちにVue公式チームが vue-component-compiler
というライブラリをリリース予定であることも分かりました。
現在はまだDesigning Threadの状態ですが、「バンドラに依存しないSFCのコンパイル用API」という位置付けで2018年にリリース予定とのことです。
確かに今回 vue-loader
と vueify
のソースを読む中でロジックが全く共通化されてなくてマズイなーという感想を抱いたので、 vue-component-compiler
がリリースされるのが楽しみです。
みんなでkazuponさんを信じて待ちましょう!!
(ParcelでSFC使えるようになったらvue-cliのテンプレート作ってOSS活動したいなー)
結局Webpackから乗り換えるべきなの?
今回実際にParcelをいろいろと触ってみましたが、
まだWebpackは手放せない!
というのが正直な感想です。
確かに「Zero configuration web application bundler」という触れ込みは大変魅力的です。
僕自身、みなさんと同じよう近年のフロントエンドの煩雑さは常軌を逸していると感じている一人であり、Webpackの設定など苦痛そのものだと考えています。
だからといって、
「煩雑な設定が多すぎる」
という問題に対して
「なにも設定しなくて大丈夫!」
というソリューションを採用するのもいささか極端な発想であり、みんなが幸せになる考えでもない気がしています。
最新のECMAScriptで全てのコードが記述され、あらゆるデータが型を持ち、そして地球上の全てのブラウザが遍く最新のWeb標準仕様に対応した世界こそ我々フロントエンドエンジニアにとってのユートピアですが、残念なことにまだ人類はその理想郷にたどり着く事ができていません。
これからもしばらくはプロジェクトごとに .babelrc
を書き、ファイルの種類ごとに適切なローダーを割り当てる運用はなくならないでしょう。
そう考えたときに、まだリリース直後のParcelには自由度が少なすぎるため、開発要件を満たすのに必要十分とは言えません。
今後の可能性に期待!
Parcelはまだ歩き始めたばかりのプロジェクトです。裏を返せば伸び代しかありませんw この1週間、Slack上で秒速でバグがつぶされていく様子や、爆速で新機能が追加されている様子をみていると、その将来はとても明るいものになる気がしています。
また、コミュニティ全体で「zero config」の哲学が浸透しているだけでなく、
Zero config doesn't mean zero configurable
という合言葉も頻繁に用いられていることからもわかるよう、様々なユースケースに対応したPluginsやExamplesが絶賛開発中です。 本番投入はまだ無理でも、個人で開発しているプロダクトでガンガンドッグフーディングしていこうと思います。
長文に最後まで目を通していただき本当にありがとうございます。 Happy Vue Life!!
追記(2017/12/15 16:08)
lc60005457さんが parcel-plugin-vue
を作ってくれたようです!
実際に .vue
ファイルを用意して試してみたところちゃんと動作しました!どうやら vueify
のAPIを利用しているようですね。
これでVueアプリケーションの開発が捗ります。ありがとうございます!!
【第二回】Rubyで作ったSlack BotとSpotify APIで遊んでみた
この記事はCAMPHOR- Advent Calendar 2016の17日目の記事です
謝罪
いきなり謝罪です。Advent Calendar上で予告していたタイトル「Rubyで作ったSlack BotとRhymerで遊んでみた」ですが、大嘘であることをここに謝罪します。ごめんなさい。
もともとは今年の中頃に一部界隈をおおいに賑わせたRhymerを使って遊ぼうと思っていたのですが、諸般の事情(スベりそう)から止むを得ず内容を変更させていただきました。興味のある方は以下のリンクより Rhymer
をお楽しみください↓↓
ごあいさつ
先日の記事は多くの方に読んでいただけたようで非常に嬉しく思います。本日は予告通り2本立ての2本目にあたる内容です。
みなさん、Spotify使ってますか?
Subscription系の音楽サービスとしては近年「Apple Music」「AWA」「LINE Music」など多くのプレイヤーが参入してきましたが、特に洋楽好きの方などはまだまだ「Spotify」人気が根強いのではないでしょうか。今回はみんな大好きSpotifyのAPIを使ってSlack Botを強化していきたいと思います。
概要
- Bot本体は前回の記事で使用したファイルをそのまま使ってます
bgm
というコマンドを入力することでSlackのタイムライン上にSpotifyの埋め込みリンクを表示するBotを作ります- 楽曲、アーティスト、アルバム、プレイリストのそれぞれで検索機能を実装
- ジャンルをもとにしたレコメンド機能を実装
- より複雑な機能を実装しようとおもったけど断念(後述)
- 正規表現の理解度がダメダメなのでツッコミお待ちしています
目次
- RSpotify
- 検索機能の実装
- レコメンド機能の実装
- 個人利用のためのカスタマイズ(断念)
環境
- macOS Sierra 10.12.2 Beta
- MacBook Air (13-inch, Early 2014)
- ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
参考
やっていくぞ!!
1. RSpotify
RSpotifyはGuilherme Sad氏によるSpotify Web APIのRubyラッパーです
1.1. 開発用キーの設定
Spotify Developer Pageから新規アプリケーションを作成し、 Client ID
と Client Secret
の2つのトークンを取得します。
トークンを取得したらそれぞれ SPOTIFY_CLIENT_ID
および SPOTIFY_CLIENT_SECRET
という環境変数として保存します。方法は前回の記事を参考にしてください。
1.2. RSpotifyのインストール
前回作成した Gemfile
に追記
# Gemfile source 'https://rubygems.org' ruby "2.3.1" gem 'http' gem 'json' gem 'faye-websocket' gem 'eventmachine' gem 'rspotify'
$ bundle
コマンドでGemをインストール
1.3. RSpotifyの動作確認
RSpotify
と関連するGemのインストールが完了したら動作をテストしてみましょう。前回同様、 bot.rb
に追記していきます。
# bot.rb require 'http' require 'json' require 'eventmachine' require 'faye/websocket' require 'rspotify' # RSpotifyの読み込み # アプリの認証情報 RSpotify.authenticate(ENV['SPOTIFY_CLIENT_ID'], ENV['SPOTIFY_CLIENT_SECRET']) (省略) ws.on :message do |event| data = JSON.parse(event.data) # data['text']が存在しなければスキップし、存在すればmsg変数に代入 next if data['text'].nil? msg = data['text'] p [:message, data] if msg == 'こんばんは' ws.send({ type: 'message', text: "こんばんは <@#{data['user']}> さん"+data['text'].split(" ").first, channel: data['channel'] }.to_json) end # "bgm"という単語から始まるテキストが入力された時の処理 if msg.match(/^bgm/) test_url = RSpotify::Track.find('5CwhBU7eqQgkOVMnRNuzzT').external_urls['spotify'] ws.send({ type: 'message', text: test_url, channel: data['channel'] }.to_json) end end (省略)
bgm
という単語から始まるテキストがSlackに投稿された時に Spotify
から 5CwhBU7eqQgkOVMnRNuzzT
というIDに該当する曲を探し、その埋め込み用リンクを返すような処理です。
このコードを実行してみましょう。
ID: 5CwhBU7eqQgkOVMnRNuzzT
の曲、つまりGet Wildの埋め込みリンクが無事タイムラインに投稿されました!
2. 検索機能
2.1. 楽曲を検索できるようにする
無限にGet Wildを聴き続けるのもよいですが、せっかくなら楽曲を検索して表示したいものです。
bgm song (クエリ)
というテキストが入力されたらクエリに該当する楽曲を検索
# bot.rb ... if msg.match(/^bgm/) text = "No result" if matched_msg = msg.match(/^bgm song (.*)/) track = RSpotify::Track.search(matched_msg[1]).first text = track.external_urls['spotify'] unless track.nil? end ws.send({ type: 'message', text: text, channel: data['channel'] }.to_json) end ...
実行
2.2 アーティスト、アルバム、プレイリストの検索機能
上記のコードと同じ要領でアーティストやアルバム、プレイリストについても検索機能を実装していきます
# bot.rb ... if msg.match(/^bgm/) text = "No result" if matched_msg = msg.match(/^bgm song (.*)/) track = RSpotify::Track.search(matched_msg[1]).first text = track.external_urls['spotify'] unless track.nil? elsif matched_msg = msg.match(/^bgm artist (.*)/) artist = RSpotify::Artist.search(matched_msg[1]).first text = artist.external_urls['spotify'] unless artist.nil? elsif matched_msg = msg.match(/^bgm album (.*)/) album = RSpotify::Album.search(matched_msg[1]).first text = album.external_urls['spotify'] unless album.nil? elsif matched_msg = msg.match(/^bgm playlist (.*)/) playlist = RSpotify::Playlist.search(matched_msg[1]).first text = playlist.external_urls['spotify'] unless playlist.nil? end ws.send({ type: 'message', text: text, channel: data['channel'] }.to_json) end ...
実行!
YOSAGE(ガッツポーズの絵文字)
3. レコメンド機能
音楽のジャンルごとに楽曲をレコメンドしてくれる機能を実装します。 bot.rb
に追記
# bot.rb ... if msg.match(/^bgm/) text = "No result" if matched_msg = msg.match(/^bgm song (.*)/) track = RSpotify::Track.search(matched_msg[1]).first text = track.external_urls['spotify'] unless track.nil? elsif matched_msg = msg.match(/^bgm artist (.*)/) artist = RSpotify::Artist.search(matched_msg[1]).first text = artist.external_urls['spotify'] unless artist.nil? elsif matched_msg = msg.match(/^bgm album (.*)/) album = RSpotify::Album.search(matched_msg[1]).first text = album.external_urls['spotify'] unless album.nil? elsif matched_msg = msg.match(/^bgm playlist (.*)/) playlist = RSpotify::Playlist.search(matched_msg[1]).first text = playlist.external_urls['spotify'] unless playlist.nil? # 追記部分 elsif matched_msg = msg.match(/^bgm recommend (.*)/) result = RSpotify::Recommendations.generate(seed_genres: [matched_msg[1]]).tracks.sample text = result.external_urls['spotify'] unless result.nil? end ws.send({ type: 'message', text: text, channel: data['channel'] }.to_json) end ...
bot recommend
から始まる入力が与えられたときに RSpotify::Recommendations.generate
を実行しています。 RSpotify::Recommendations.generate
からはおすすめの track
20曲分(デフォルト時)の配列が得られるため、その中からランダムで1曲を抜き出して埋め込みリンクを表示するような処理です。
レコメンド機能を試してみましょう。
こちらもYOSAGEですね。ちなみに2016年12月16日現在レコメンド機能がカバーしているジャンルは以下の通りです
{ "genres" : [ "acoustic", "afrobeat", "alt-rock", "alternative", "ambient", "anime", "black-metal", "bluegrass", "blues", "bossanova", "brazil", "breakbeat", "british", "cantopop", "chicago-house", "children", "chill", "classical", "club", "comedy", "country", "dance", "dancehall", "death-metal", "deep-house", "detroit-techno", "disco", "disney", "drum-and-bass", "dub", "dubstep", "edm", "electro", "electronic", "emo", "folk", "forro", "french", "funk", "garage", "german", "gospel", "goth", "grindcore", "groove", "grunge", "guitar", "happy", "hard-rock", "hardcore", "hardstyle", "heavy-metal", "hip-hop", "holidays", "honky-tonk", "house", "idm", "indian", "indie", "indie-pop", "industrial", "iranian", "j-dance", "j-idol", "j-pop", "j-rock", "jazz", "k-pop", "kids", "latin", "latino", "malay", "mandopop", "metal", "metal-misc", "metalcore", "minimal-techno", "movies", "mpb", "new-age", "new-release", "opera", "pagode", "party", "philippines-opm", "piano", "pop", "pop-film", "post-dubstep", "power-pop", "progressive-house", "psych-rock", "punk", "punk-rock", "r-n-b", "rainy-day", "reggae", "reggaeton", "road-trip", "rock", "rock-n-roll", "rockabilly", "romance", "sad", "salsa", "samba", "sertanejo", "show-tunes", "singer-songwriter", "ska", "sleep", "songwriter", "soul", "soundtracks", "spanish", "study", "summer", "swedish", "synth-pop", "tango", "techno", "trance", "trip-hop", "turkish", "work-out", "world-music" ] }
4. 個人利用のためのカスタマイズ(...だがしかし断念)
当初の予定ではここからユーザー情報で OAuth
認証してSlackから個人のプレイリストに曲追加したりいろいろやりたいことがあったけど、Advent Calendar担当日のタイムリミットが来たので断念...
近いうちにリベンジしたいです。
おわりに
日本でのサービスイン以前からSpotifyを利用しているヘビーユーザーなのでAPIを叩くだけで遊べるのはとてもありがたいです。 Slack Botに限らず今後もいろんな機会で使っていきたいと思います。
明日はmurata_atsumiの記事です
Let's Get Wild!
【第一回】超簡単!RubyでSlack Botを作る方法
この記事はCAMPHOR- Advent Calendar 2016の13日目の記事です
ごあいさつ
今年もAdvent Calendarの季節がやってきましたね。 せっかくなのでこれを機にTech関連の記事を残すため、はてなブログはじめました。 相変わらず見習いエンジニアの域を出ない@andoshin11 です。 今回の記事は2本立ての構成になっています。(2本目の記事は12/17に公開予定)
またまた長文になりますがお付き合いよろしくお願いします。
昨年度の記事はこちら↓↓
概要
- プログラミング初心者でも記事を読めばBotが作れるよう意識して書きました*1
- 昨年は
Googla Apps Script
を使用しましたが、今年はRuby
でSlack Botを実装します - Slack公式が提供する
Real Time Messaging API
を利用します - Botを作成し、外部サーバー(Heroku)で動かすところまでを目標にします
- rubotyやlitaのようなライブラリは利用せず、勉強も兼ねて自前での実装を目指します
- 質問あればコメントください!
目次
環境
- macOS Sierra 10.12.2 Beta
- MacBook Air (13-inch, Early 2014)*2
- ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin15]
参考
やっていくぞ!!
1. Slack API 入門
幸いなことにSlack自身がすでに豊富なAPIを整えてくれているので、その使い方さえ理解すれば比較的容易に手元のマシンからでもメッセージの送受信ができます。
1.1. APIのテスト
何はともあれ Ruby
で Slack API
を叩いて遊んでみましょう!
まずは作業ディレクトリ内に Gemfile
を作成します。
# Gemfile source 'https://rubygems.org' gem 'http' gem 'json'
次に本体である test.rb
の作成です
# test.rb require 'http' require 'json' response = HTTP.post("https://slack.com/api/api.test") puts JSON.pretty_generate(JSON.parse(response.body))
2つのファイルの用意ができたら $ bundle exec ruby test.rb
でスクリプトを実行します。
POSTしたリクエストへのレスポンスとして "ok":true
が返ってきましたね。Slack本体のサーバーと対話ができた証拠です。
1.2. Authentication
次はもう一歩踏み込んでチーム固有の情報を取得できるよう、 Authentication
を行なっていきたいと思います。
先ほどはhttps://slack.com/api/api.testというURLにリクエストを送りましたが今度はhttps://slack.com/api/auth.testというアドレスにリクエストを送ってみます。
test.rb
を編集
# test.rb require 'http' require 'json' response = HTTP.post("https://slack.com/api/auth.test") puts JSON.pretty_generate(JSON.parse(response.body))
実行
"ok":false, "error": "not_authed"
と怒られてしまいました。これはリクエスト時に Token
が設定されていないことが原因です。
Token
は、管理画面から Bots Integration
を追加することで取得できます。
発行された Token
をコピーして環境変数として保存しましょう。
POSTリクエストに params[:token]
を追加。
require 'http' require 'json' response = HTTP.post("https://slack.com/api/auth.test", params: { token: ENV['SLACK_API_TOKEN'] }) puts JSON.pretty_generate(JSON.parse(response.body))
実行
成功しました!今度は認証が認められ、加えて Token
に紐づいたチームの情報やユーザーの情報も返ってきています。
余談ですがSlack内で割り振られている team_id
は先頭が T
から始まり、 user_id
は U
から始まるという仕様のようです。
1.3. Post Message
認証が通るようになったので、実際にSlackへメッセージを投稿してみましょう。
メッセージ投稿用APIのURLはhttps://slack.com/api/chat.postMessageです。パラメータに投稿先のチャンネルや、投稿したいテキストを指定してリクエストを送ることでメッセージの投稿が可能になります。
test.rb
を編集
require 'http' require 'json' response = HTTP.post("https://slack.com/api/chat.postMessage", params: { token: ENV['SLACK_API_TOKEN'], channel: "#general", text: "こんにちは!", as_user: true, }) puts JSON.pretty_generate(JSON.parse(response.body))
as_user: true
としているのはデフォルトの Bots Integration
としてではなく、自分で Configure
したBotユーザーに投稿させたいからです。
スクリプトを実行
メッセージの投稿に成功しました!このときレスポンス内に投稿されたメッセージの関する情報が含まれているのもわかりますね(タイムスタンプ等)
ここまでで基本的な Slack API
の使い方を把握できました!
Cron
等で定期的にこのメッセージ投稿APIを叩くだけでも簡易Botが作れそうですね。
2. Real Time Messaging API
前節ではあくまで一方通行のメッセージの投稿方法を確認しました。
ですが実際の運用を想定すると常時双方向通信を監視し、ユーザーからの投稿に合わせて適切な出力を返してあげる必要があるでしょう。
ここからはSlackの備える Real Time Messaging API
と低コストで双方向通信を可能にする Web Socket
の仕組みを利用して、より実用的なBotを作っていきます。
2.1. Real Time Messaging APIとは
Slackには既に Outgoing Webhook
というユーザーの投稿内容を外部のサイトやアプリに出力してくれる仕組みがありますが、 Outgoing Webhook
の扱える情報は特定のキーワードから始まるメッセージのみです。
対して Real Time Messaging API
はその名の通り24時間チームを監視しユーザーの全ての投稿内容だけでなく、「チャンネルの新規作成」「チャンネルへのユーザーの参加/脱退」などといった1つ1つのイベントの情報すら出力してくれる仕組みです。
この仕組みを用いることでより複雑なBotの実装が可能になります。
2.2. Real Time Messaging APIでデータを取得する
まずは Gemfile
を編集して2つの新たなGemを追加します
# Gemfile source 'https://rubygems.org' gem 'http' gem 'json' gem 'faye-websocket' gem 'eventmachine'
faye-websocket
によってRubyでWeb Socketサーバーを立てることが容易になり、 eventmachine
は並列処理等を可能にしてくれるものです
早速、https://slack.com/api/rtm.startにリクエストを送り Web Socket
のURLを確認しましょう。
# test.rb require 'http' require 'json' require 'eventmachine' require 'faye/websocket' response = HTTP.post("https://slack.com/api/rtm.start", params: { token: ENV['SLACK_API_TOKEN'] }) rc = JSON.parse(response.body) puts rc['url']
実行
レスポンスの JSON
の中の['url']
にアドレスが含まれているのが分かりますね。このアドレスに対して双方向通信を確立するよう、 Web Socket
を動かしていきます。 Real Time Messaging API
からは常に情報が降ってくるので、並列処理のための Event Machine
もお忘れなく。
# test.rb require 'http' require 'json' require 'eventmachine' require 'faye/websocket' response = HTTP.post("https://slack.com/api/rtm.start", params: { token: ENV['SLACK_API_TOKEN'] }) rc = JSON.parse(response.body) url = rc['url'] EM.run do # Web Socketインスタンスの立ち上げ ws = Faye::WebSocket::Client.new(url) # 接続が確立した時の処理 ws.on :open do p [:open] end # RTM APIから情報を受け取った時の処理 ws.on :message do |event| p [:message, JSON.parse(event.data)] end # 接続が切断した時の処理 ws.on :close do p [:close, event.code] ws = nil EM.stop end end
実行!
一番上に接続が確立したことを示す [:open]
が表示されていますね。
二行目の [:message]
に含まれる {"type"=>"hello"}
というのはSlack側が接続確立時に送信してくるものです。三行目は無視して構いません。
四行目の内容ですが {"type"=>"presence_change"...}
というメッセージからも分かる通り、ユーザーのステータスが変わったことを示すイベントをキャッチしてReal Timeでこちらの Web Socket Server
に送信してくれています。
このプログラムを走らせたまま、もう少しSlack側でいろいろいじってみましょう。
みなさんお気付きのように Real Time Messaging APi
ではユーザーが投稿する時だけでなく、「入力中」であることや「リアクション」を取った事すらも細かく取得することがわかりました。これで様々な種類のBotが実装できますね!
2.3 ユーザーの投稿に合わせてメッセージを返す
ここまでで常時ユーザーの投稿内容が取得できるようになりました。
次は投稿に合わせたレスポンスを返せるよう test.rb
を修正していきます。
# test.rb ... ws.on :open do p [:open] end ws.on :message do |event| data = JSON.parse(event.data) p [:message, data] if data['text'] == 'こんにちは' ws.send({ type: 'message', text: "こんにちは <@#{data['user']}> さん", channel: data['channel'] }.to_json) end end ws.on :close do p [:close, event.code] ws = nil EM.stop end ...
ユーザーが「こんにちは」と投稿したら、「こんにちは (ユーザー名)さん」と同じチャンネルで返すようなシンプルなスクリプトです。
実行!
意図した通りに動きましたね。
1つ注意しなくてはいけないのが、Botが投稿した内容もまた RTM API
によって返ってくるということです。Bot同士の会話が一生終わらないという事態が無いように気をつけてください。
RTM API
で受信したJSON内に含まれる情報を上手く利用することで双方向対話ができるようになりました。おめでとうございます!
3. 作ったBotを公開する
ここまででLoaclのマシン上でBotが動くようになりましたが、せっかくなので外部サーバーでホスティングして常時稼働させてあげたいものです。
今回は Heroku
にデプロイすることでこの課題を解決していきます。
事前準備として heroku toolbelt
を導入するところまでは進めておいてください。
参考リンク:Heroku登録〜Macで環境整備〜お試しWebアプリを作るまで
3.1. Gitの設定
Heroku上で動かすにあたって Gemfile
に Ruby
のバージョンに関する情報を追記します。
# Gemfile source 'https://rubygems.org' ruby "2.3.1" gem 'http' gem 'json' gem 'faye-websocket' gem 'eventmachine'
また test.rb
の名前をカッコ悪いので bot.rb
に変更し、「こんばんは」というコマンドに反応するよう修正しました。
# bot.rb ... ws.on :message do |event| data = JSON.parse(event.data) p [:message, data] if data['text'] == 'こんばんは' ws.send({ type: 'message', text: "こんばんは <@#{data['user']}> さん", channel: data['channel'] }.to_json) end end ...
お決まりの $ git init
$ git add .
$ git commit -m "Initial commit"
までの流れで Git
の初期化を行います
3.2. Heroku側の設定
Heroku
のアカウントを取得し Heroku Toolbelt
の設定も済んでいる方はコマンドラインからログインができます。
$ heroku login
実行後ログイン情報を入力
初期状態では Heroku
上に Ruby
の実行環境が存在しないため、公式の提供する Heroku Buildpack for Ruby
を利用してアプリケーションの初期化を行います。
$ heroku create --buildpack https://github.com/heroku/heroku-buildpack-ruby.git
を実行
$ git push heroku master
でファイルをデプロイ!
Token
を Heroku
の環境変数として登録します
さぁ、ここまでで準備完了です。実際に Heroku
上で Ruby
のスクリプトを動かしてみましょう!
$ heroku run bundle exec ruby bot.rb
を実行
動いたー!!
おわりに(...そして予告)
お疲れ様でした。Slackの強力なAPIと Web Socket
の力でシンプルなスクリプトでもBotを作れるようになりましたね。やっている事は本当に単純なのでどんな言語でも応用が効くことでしょう。
冒頭でもお伝えしましたが今回は2本立てです。 次回の内容は、今回作成したプログラムにアップデートを加えてより実用的(????)なBotを作る手段を記事にします。 お楽しみに!
明日はsiriusjackの記事です