VueコンポーネントのnameからCSSのクラスを付与するディレクティブを作ってみた
このSFCSSをやってくうえでクラス名を記述するのをなんとか楽できないか考えた。
この記事はその試行錯誤の軌跡である。
はじめに結論
コンポーネントのname
からクラス名を付与するディレクティブを作ってプラグインをnpmに公開したが、最終的には普通にせっせと書くのが一番ベターなのでは?というところに辿りついたというお話。
めんどくさポイント
命名規則によって命名の手間は減ったが、class
をフルで記述する必要があって変わらずめんどうだった。
<template> <div class="MyComponent"> <h1 class="MyComponent_Heading"> heading </h1> </div> </template> <script> export default { name: 'MyComponent', } </script> <style lang="scss" scoped> .MyComponent { &_Heading {} } </style>
name
をtemplate
で参照してなんとか楽をできないかと考えた。
コンポーネントのname
の参照
コンポーネントのname
につけた名前は、$options._componentTag
で参照できるので、:class
を使って次のように書ける
<template> <div :class="[$options._componentTag]"> <h1 :class="[`${$options._componentTag}_Heading`]"> heading </h1> </div> </template>
が、かなりめんどうだしむしろ手間が増えてるような…🙄
methodsに定義してmixinとか…?
じゃあクラス名を返すメソッドを定義してヘルパーっぽく。mixinにすれば共通化できるし…
<template> <div :class="[className()]"> <h1 :class="[className('_Heading')]"> heading </h1> </div> </template> <script> export default { name: 'MyComponent', methods: { className(childNode = '') { return `${this.$options._componentTag}${childNode}` } } } </script>
うーん微妙。:class="[className()]"
とか毎回書くのだるそう
ならばディレクティブだ
ディレクティブにしたらまだマシになりそう
<template> <div v-class-name> <h1 v-class-name="'_Heading'"> heading </h1> </div> </template> <script> function bindClassName(el, binding, vnode) { const componentName = vnode.context.$options._componentTag const className = `${componentName}${binding.value || ''}` if (el.className.indexOf(className) !== -1) return el.className = `${className}${el.className ? ' ' + el.className :''}` } export default { name: 'MyComponent', directives: { className: { bind: bindClassName, update: bindClassName, inserted: bindClassName, } } } </script>
ディレクティブに文字列として渡さないといけなくて"'_Heading'"
としないとならないのが癪に障るけど、それっぽさは出てる。
これがレンダリングされるとこうなる。
<div class="MyComponent"> <h1 class="MyComponent_Heading"> heading </h1> </div>
vue-class-nameプラグインとしてpublish
👆のやつをプラグインにしてnpmにpublishした。
使い方
インストール
npm i vue-class-name
import vClassName from 'v-class-name' import Vue from 'vue' Vue.use(vClassName)
<template> <div v-class-name> <h1 v-class-name="'_Heading'"> heading </h1> <div> </template> <script> export default { name: 'MyComponent', } </script>
:class
での動的なクラスの切り替えと親コンポーネントからのclass
のマージについては動作確認済み。
おわりに
なんとかならんかと試して、最終的にプラグインとして公開してみたものの、処理の内容的にどこかしらパフォーマンスに影響でそうで微妙だから自分で使わなそう🤔
宣言的に書くのがtemplate
の良いところだと思うので、めんどくさくてもCSSのクラス名は静的に書くのがベターなのではと思った。
おしまい
透明なSlackクライアントを作ってみた
タイトルの通り、背景が透明なSlackクライアントを開発合宿で作った。
モチベ
- 画面共有してるときにチャット見える状態にしたい(ウィンドウのサイズは小さくしたくない)
- 作業集中するとき公式クライアント終了させたいけど、案件のチャンネルとか見ておかないといけないチャンネルだけ見れるようにしておきたい
ということで考えたのが透明なSlackクライアント
Slack Real Time Messaging API
SlackのAPIにはいくつか種類がある。以前ステータスを変更するアプリを作ったときに使ったのはいわゆる普通のWeb API nakajmg.hatenablog.com
これとは別に、Slack上で起こっているイベントをリアルタイムに受け取れるAPIがReal Time Messaging API。超雑に説明すると、このAPIを使えばSlackクライアントが作れる。
WebSocketでリアルタイムにSlackで起こってる全イベントを受け取れるので、イベントをさばいて必要な情報をストアしたり表示したりすることでクライアントを構築する。
Electronで透明アプリ
Electronを使うと、背景色の透明なアプリができる。
new BrowserWindow({ frame: false, transparent: true, })
body { background-color: rgba(0,0,0,0); }
作った
GitHub - nakajmg/SlaCast: slack comment viewer
実装した機能は次のとおり
- チャンネルの選択
- 選択したチャンネルのチャット表示
- スレッドの展開
- カスタム絵文字対応絵文字ピッカー
- リアクションの表示
- メッセージの送信
チャットの表示はアプリを起動したタイミング以降のものだけが表示できる。
Web APIと組み合わせれば過去ログも辿れるようにできるが、今回の目的と異なるので見送り。
使ったやつ
開発合宿ではあまり詳しくないものを使うようにしてるので、Vueを使わずReact+MobXを使ってTypeScriptで書いた。
SlackのAPIとのやり取りは公式のライブラリで十分だった(型定義がなくてつらかったけど) github.com
絵文字ピッカーはemoji-martにSlackに登録してあるカスタム絵文字を登録して使えるようにした。 github.com
emoji-martはVueで使える版もあって絵文字ピッカーつけたいときは重宝している。
使い方
electron-webpackとelectron-builderの作法を把握しきれず、パッケージングして動く状態にするのがめんどくさくて諦めた。
なので使いたい人がいたらgit clone
してnpm i
してnpm run start
でお願いします…
そのほか
アプリにサインインするにはManage PermissionでSign in with Slack
を有効にする必要があります。
SlackのApp Directoryに乗せる審査を通していないので、Teamの設定でNon distributedなappのインストールが許可されてない場合にはサインインでエラーになります 。(PermissionのOnly allow apps from the Slack App Directory
が有効な場合)
また、インストールにAdminの許可が必要な場合(Approved Apps
が有効な場合)にもサインインでエラーがでますが、インストールが許可されると使えるようになります。
Slack APIの可能性
今回Real Time Messaging APIを使ってみて、めんどくさいながらもSlackクライアントが自分で作れることが確認できた。
公式クライアントは複数チームに所属してる場合の体験があまりよくないように感じるので
- 複数チームでサインイン
- 選択したチャンネルを横並びに表示
できるようなクライアント作れば便利そうだなと思った
Airbnbで金沢8泊リモートワークをした話
1月の中頃から8泊9日で金沢を満喫しつつ仕事してきた。
三度目の金沢
金沢に行くのは三度目。前回の訪問が1年半前くらいで、観光地はほとんど訪問済み。
それでも金沢に行きたい理由は日本酒とご飯。金沢の日本酒好きだし、どこでお寿司食べてもだいたい美味しい。
今回は妻が長めの休みを取れたのと、金沢行きたい欲が高まってたタイミングが重なったので、長めの滞在を決断した。
Airbnbで宿探し
連泊になるとホテルは高い。そしてホテルだとくつろげないと思い、初めてAirbnbを使ってみた。
金沢で検索すると結構な数でてくる。そして安い。
この中から次の条件で探した。
近江町市場に徒歩3分くらいで行ける立地の部屋が見つかり予約。2名8泊でかかった金額👇
¥ 5850 x 8泊¥ 46800 清掃料金¥ 3000 サービス料¥ 6451 合計¥ 56251
部屋の感想
綺麗なワンルームのマンション。家電もそろってて2日目からは自宅のようにくつろげた。
3日経つとで「金沢に引越してきたんだっけ?」てくらい普通に生活してた。
写真は備え付けのテレビのHDMI外部入力を探す自分。
Switchの簡易ドック持っていってレゴワールドで遊んでた。
Wi-Fiが弱かった
泊まった部屋のホストが企業だったらしく、同じマンションの数部屋を管理してた。Wi-Fiが部屋ごとではなく、数部屋まとめて飛ばしてる感じで電波強度が弱くて使い物にならず。
結局IIJのテザリングで仕事した。IIJめっちゃ速いし安定してて最高。クーポンオフにして3Gで使ってても気にならなかった。
金沢でのすごし方
自分は平日の日中は部屋でもくもくと仕事、お昼は外で妻とランチ。
妻は好き放題に金沢市街を探索。
寿司うまい
近くの市場で昼にお寿司食べて部屋に戻って仕事するのがとてもよかった。
カレーうまい
好き。
日本酒うまい
日本酒も存分に堪能。金沢のお酒はほんとに好みに合うのが多い。
日本酒の店で横にいた地元の人から美味しいおでん屋とか聞いたり、そういうのもよかった。
8泊した感想
すご くよい。超リフレッシュ。
観光で来るのとはまったく違う体験ができた。
もし東京から出るときには長めに民泊して、街を知ってから引っ越すのよさそうだな〜と思った。
金沢はまた行く。
勉強会とかなんかしらイベントやってるタイミングがあれば合わせるのもありかも。
Vueコンポーネントのビルド時に不要な属性をtemplateから取り除く
追記(2019/02/12)
テスト用にdata-test属性を使ってる
VueコンポーネントのテストをJest + vue-test-utilsで書いてる。
data
とかprops
の値によって状態が変化する要素のテストをするとき、要素の特定のためにクラス名使うといろいろ大変だからテスト用にdata-test
属性を使ってる。
data-test属性を消したい
テストするときには便利だけど、あくまでテスト用で、リリースするときには消しておきたい。
特定の属性を消すReact用のbabelプラグインがあったけど、Vue用のは見つけられなかった。代わりにフォーラムで見つけたのがこれ。
vue-loaderのオプションで属性消せるよとのこと。
次のコードはフォーラムのコードからNODE_ENV
の値見てるとことlodash依存を排除したやつ。
{ compilerModules: [{ preTransformNode(astEl) { const { attrsMap, attrsList } = astEl if (attrsMap['data-test']) { delete attrsMap['data-test'] const index = attrsList.findIndex(x => x.name == 'data-test' ) attrsList.splice(index, 1) } return astEl } }] }
これでdata-test
属性が消えて万歳🎉
nuxt.jsで同じことしたい
nuxt.config.js
のbuild.extend
でvue-loaderのオプションを指定する。
module.exports = { build: { extend (config, ctx) { if (!ctx.isDev) { const vueLoader = config.module.rules.find(rule => rule.loader === 'vue-loader') vueLoader.options.compilerModules = [{ preTransformNode(astEl) { const { attrsMap, attrsList } = astEl if (attrsMap['data-test']) { delete attrsMap['data-test'] const index = attrsList.findIndex(x => x.name == 'data-test' ) attrsList.splice(index, 1) } return astEl } }] } }, } }
Circle CI 2.0 timezoneの設定
config.yml
の environment
で TZ: Asia/Tokyo
を指定する
version: 2 jobs: build: docker: - image: node:8.9.0 environment: TZ: Asia/Tokyo
2017年買ってよかったもの
家電をアップグレードしてQOLが向上した年。
Switch * 2
自分用と妻用、2台のSwitchを必死こいて購入。スプラ2、マリオデ、DLソフトなどいろいろ楽しんだ。これによってゲーム熱が高まり、ゲーム用PCを購入するに至った。
ゲーム用Win機
Steamのゲームがやりたい、とくにCupheadがやりたくてゲーム用のWin機を購入。買ったのはこれ
メモリとHDD足してこんな感じのスペック
CPU: Core i5-7500 ( 3.40GHz 2400MHz 6MB ) メモリ: 24GB(8.0GB PC4-19200 DDR4 UDIMM 2400MHz * 3) ストレージ: SSD 256GB + HDD 4T グラボ: NVIDIA GeForce GTX 1060 6GB GDDR5
とりあえずどのゲームも快適にやれてる。3ヶ月で50くらいのゲーム購入。
Dead Cellsが一番のお気に入り。おもしろい store.steampowered.com
4Kモニタ
LG モニター ディスプレイ 27UD88-W 27インチ/4K(3840×2160)/IPS 非光沢/USB Type-C、HDMI×2、DisplayPort/高さ調節、ピボット対応
- 出版社/メーカー: LG Electronics Japan
- 発売日: 2016/04/15
- メディア: Personal Computers
- この商品を含むブログを見る
これ買った。作業が捗る。
こたつ
オフィスにこたつが導入されたのに引っ張られる形でこたつを購入。毎日のようにこたつでダメになっている。
でかい冷蔵庫
日立の555のやつ。 kadenfan.hitachi.co.jp
真空チルドが最高な感じ。
容量がでかくなって買い置きも作り置きもいっぱいできるようになった。日本酒買いまくって材料が入れられないてのがなくなったのも最高。QOL👆👆。
ドラム式洗濯機
パナソニックのスリム型。
乾燥までできるおかげで洗濯に使う時間が相当減った。その分の時間を仕事とか料理とかいろんなことに使えるようになったので、QOL👆👆。
別の一回り大きいやつ頼んだら洗濯機置き場が小さくて持って帰ってもらった。サイズは幅だけでなく奥行きも考えて通路の幅を測りましょう…。
Anova
New: Anova Precision Cooker - WIFI 2nd Gen (900 Watts)
- 出版社/メーカー: Anova
- メディア: ホーム&キッチン
- この商品を含むブログを見る
セールで購入。紀伊国屋のうまい牛肉で作るとなんでもうまい。
豚肉は値段に関わらずうまくなってコスパが大変良い。
電気フライヤー
あげもの超うまい。
象印 あげあげ 電気フライヤー メタリックカカオ EFK-A10-TJ
- 出版社/メーカー: 象印(ZOJIRUSHI)
- メディア: ホーム&キッチン
- 購入: 3人 クリック: 105回
- この商品を含むブログ (10件) を見る
からあげととんかつおいしい☺
来年は
料理の腕を上げていきたい所存💪
2017年振り返り
今年はいろいろな面で成長を実感できた年でした。
今年作ったもの
GitHub風のdiffを生成するライブラリ
技術記事のコードブロックをdiffにしてみたらどうか、と思いたって作ったやつ。作ったといっても実際はライブラリを2つくっつけただけなんだけど。
Performance系のAPIで取れるデータを蓄積して可視化するツール
を使ってjson-serverをストアにしてローカル環境での開発時にクライアントサイドのパフォーマンスデータを蓄積してく。DevToolsでやりゃいいやつだけど、モバイルのブラウザとかSafariとか、クロスプラットフォームな感じでログを残せるようにしたい、というモチベで作ったやつ。
勉強がてらにReact+MobXで作成した。
Slackのユーザーステータスの変更を可視化するやつ
Electron + Vue + Slack API
詳しくは過去のエントリで
ほか
privateなリポジトリのままで公開してないのがいくつか。完成させるのはやはり勢いが必要だ。
今年印象に残ったライブラリとか
お仕事、個人プロジェクトを通して使ったもろもろ。中でも👇のやつが印象深い。
- Vue
- Nuxt
- Firebase
去年から引き続き、案件のほとんどでVueを採用した。慣れているというのが一番の理由だが、悩むことなく進められるのはやはり良い。
Nuxtは個人プロジェクトで少しさわったあと、案件で採用してみた。今のところ開発体験を向上させてくれる良いもの、という印象。2018年はNuxtに乗っかっていく年になりそう。
Firebaseには大変お世話になりました。連載で解説も書いた。
個人プロジェクトで何かつくるとき、バックエンドのデータストアを用意する手間も悩みも解消。functionsに色々と処理を任せられるのも大きい。
OAuthで認証するAPIとかはコールバックURLの登録が必須で、Electronで使う場合に困ってたのが、functionsに丸投げすることで解消できて最高だった。
プライベートのはなし
5月に入籍しました。大変幸せに暮らしております。
2018年もいい年になりますように🙏