じまろぐ

めめ

VueコンポーネントのnameからCSSのクラスを付与するディレクティブを作ってみた

VueのSFCでのCSSの命名について以前書いた。

nakajmg.hatenablog.com

この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>

nametemplateで参照してなんとか楽をできないかと考えた。

コンポーネント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した。

www.npmjs.com

使い方

インストール

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クライアントを作ってみた

f:id:nakajmg:20180306194547p:plain

タイトルの通り、背景が透明なSlackクライアントを開発合宿で作った。

モチベ

  • 画面共有してるときにチャット見える状態にしたい(ウィンドウのサイズは小さくしたくない)
  • 作業集中するとき公式クライアント終了させたいけど、案件のチャンネルとか見ておかないといけないチャンネルだけ見れるようにしておきたい

ということで考えたのが透明なSlackクライアント

Slack Real Time Messaging API

SlackのAPIにはいくつか種類がある。以前ステータスを変更するアプリを作ったときに使ったのはいわゆる普通のWeb API nakajmg.hatenablog.com

api.slack.com

これとは別に、Slack上で起こっているイベントをリアルタイムに受け取れるAPIがReal Time Messaging API。超雑に説明すると、このAPIを使えばSlackクライアントが作れる。

api.slack.com

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と組み合わせれば過去ログも辿れるようにできるが、今回の目的と異なるので見送り。

使ったやつ

package.json

開発合宿ではあまり詳しくないものを使うようにしてるので、Vueを使わずReact+MobXを使ってTypeScriptで書いた。

SlackのAPIとのやり取りは公式のライブラリで十分だった(型定義がなくてつらかったけど) github.com

絵文字ピッカーはemoji-martにSlackに登録してあるカスタム絵文字を登録して使えるようにした。 github.com

f:id:nakajmg:20180307143032p:plain

emoji-martはVueで使える版もあって絵文字ピッカーつけたいときは重宝している。

使い方

electron-webpackとelectron-builderの作法を把握しきれず、パッケージングして動く状態にするのがめんどくさくて諦めた。

なので使いたい人がいたらgit cloneしてnpm iしてnpm run startでお願いします…

そのほか

アプリにサインインするにはManage PermissionでSign in with Slackを有効にする必要があります。

f:id:nakajmg:20171124185352p:plain

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日で金沢を満喫しつつ仕事してきた。

f:id:nakajmg:20180217132226j:plain

三度目の金沢

金沢に行くのは三度目。前回の訪問が1年半前くらいで、観光地はほとんど訪問済み。

それでも金沢に行きたい理由は日本酒とご飯。金沢の日本酒好きだし、どこでお寿司食べてもだいたい美味しい。

今回は妻が長めの休みを取れたのと、金沢行きたい欲が高まってたタイミングが重なったので、長めの滞在を決断した。

Airbnbで宿探し

連泊になるとホテルは高い。そしてホテルだとくつろげないと思い、初めてAirbnbを使ってみた。

金沢で検索すると結構な数でてくる。そして安い。

www.airbnb.jp

この中から次の条件で探した。

近江町市場に徒歩3分くらいで行ける立地の部屋が見つかり予約。2名8泊でかかった金額👇

¥ 5850 x 8泊¥ 46800
清掃料金¥ 3000
サービス料¥ 6451
合計¥ 56251

部屋の感想

綺麗なワンルームのマンション。家電もそろってて2日目からは自宅のようにくつろげた。

3日経つとで「金沢に引越してきたんだっけ?」てくらい普通に生活してた。

写真は備え付けのテレビのHDMI外部入力を探す自分。

f:id:nakajmg:20180217130313j:plain

Switchの簡易ドック持っていってレゴワールドで遊んでた。

Wi-Fiが弱かった

泊まった部屋のホストが企業だったらしく、同じマンションの数部屋を管理してた。Wi-Fiが部屋ごとではなく、数部屋まとめて飛ばしてる感じで電波強度が弱くて使い物にならず。

結局IIJテザリングで仕事した。IIJめっちゃ速いし安定してて最高。クーポンオフにして3Gで使ってても気にならなかった。

金沢でのすごし方

自分は平日の日中は部屋でもくもくと仕事、お昼は外で妻とランチ。

妻は好き放題に金沢市街を探索。

寿司うまい

f:id:nakajmg:20180217130319j:plain

近くの市場で昼にお寿司食べて部屋に戻って仕事するのがとてもよかった。

カレーうまい

f:id:nakajmg:20180217132230j:plain

好き。

日本酒うまい

f:id:nakajmg:20180217130334j:plain

日本酒も存分に堪能。金沢のお酒はほんとに好みに合うのが多い。

日本酒の店で横にいた地元の人から美味しいおでん屋とか聞いたり、そういうのもよかった。

8泊した感想

すご くよい。超リフレッシュ。

観光で来るのとはまったく違う体験ができた。

もし東京から出るときには長めに民泊して、街を知ってから引っ越すのよさそうだな〜と思った。

金沢はまた行く。

勉強会とかなんかしらイベントやってるタイミングがあれば合わせるのもありかも。

Vueコンポーネントのビルド時に不要な属性をtemplateから取り除く

追記(2019/02/12)

vue-cli v3向けにはプラグインがある

github.com

テスト用にdata-test属性を使ってる

VueコンポーネントのテストをJest + vue-test-utilsで書いてる。

dataとかpropsの値によって状態が変化する要素のテストをするとき、要素の特定のためにクラス名使うといろいろ大変だからテスト用にdata-test属性を使ってる。

blog.kentcdodds.com

data-test属性を消したい

テストするときには便利だけど、あくまでテスト用で、リリースするときには消しておきたい。

特定の属性を消すReact用のbabelプラグインがあったけど、Vue用のは見つけられなかった。代わりにフォーラムで見つけたのがこれ。

forum.vuejs.org

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.jsbuild.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
          }
        }]
      }
    },
  }
}

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モニタ

これ買った。作業が捗る。

こたつ

www.nitori-net.jp

オフィスにこたつが導入されたのに引っ張られる形でこたつを購入。毎日のようにこたつでダメになっている。

でかい冷蔵庫

日立の555のやつ。 kadenfan.hitachi.co.jp

真空チルドが最高な感じ。

容量がでかくなって買い置きも作り置きもいっぱいできるようになった。日本酒買いまくって材料が入れられないてのがなくなったのも最高。QOL👆👆。

ドラム式洗濯機

パナソニックのスリム型。

www.sharp.co.jp

乾燥までできるおかげで洗濯に使う時間が相当減った。その分の時間を仕事とか料理とかいろんなことに使えるようになったので、QOL👆👆。

別の一回り大きいやつ頼んだら洗濯機置き場が小さくて持って帰ってもらった。サイズは幅だけでなく奥行きも考えて通路の幅を測りましょう…。

Anova

New: Anova Precision Cooker - WIFI 2nd Gen (900 Watts)

New: Anova Precision Cooker - WIFI 2nd Gen (900 Watts)

セールで購入。紀伊国屋のうまい牛肉で作るとなんでもうまい。

豚肉は値段に関わらずうまくなってコスパが大変良い。

電気フライヤー

あげもの超うまい。

象印 あげあげ 電気フライヤー メタリックカカオ EFK-A10-TJ

象印 あげあげ 電気フライヤー メタリックカカオ EFK-A10-TJ

からあげととんかつおいしい☺

来年は

料理の腕を上げていきたい所存💪

2017年振り返り

今年はいろいろな面で成長を実感できた年でした。

今年作ったもの

GitHub風のdiffを生成するライブラリ

技術記事のコードブロックをdiffにしてみたらどうか、と思いたって作ったやつ。作ったといっても実際はライブラリを2つくっつけただけなんだけど。

github.com

Performance系のAPIで取れるデータを蓄積して可視化するツール

f:id:nakajmg:20171231153458p:plain

  • Performance系API
    • Navigation Timing API
    • User Timing API
    • Resource Timing

を使ってjson-serverをストアにしてローカル環境での開発時にクライアントサイドのパフォーマンスデータを蓄積してく。DevToolsでやりゃいいやつだけど、モバイルのブラウザとかSafariとか、クロスプラットフォームな感じでログを残せるようにしたい、というモチベで作ったやつ。

勉強がてらにReact+MobXで作成した。

github.com

esa-pages.io

Slackのユーザーステータスの変更を可視化するやつ

Electron + Vue + Slack API

詳しくは過去のエントリで

nakajmg.hatenablog.com

github.com

ほか

privateなリポジトリのままで公開してないのがいくつか。完成させるのはやはり勢いが必要だ。

今年印象に残ったライブラリとか

お仕事、個人プロジェクトを通して使ったもろもろ。中でも👇のやつが印象深い。

  • Vue
  • Nuxt
  • Firebase

去年から引き続き、案件のほとんどでVueを採用した。慣れているというのが一番の理由だが、悩むことなく進められるのはやはり良い。

Nuxtは個人プロジェクトで少しさわったあと、案件で採用してみた。今のところ開発体験を向上させてくれる良いもの、という印象。2018年はNuxtに乗っかっていく年になりそう。

Firebaseには大変お世話になりました。連載で解説も書いた。

app.codegrid.net

個人プロジェクトで何かつくるとき、バックエンドのデータストアを用意する手間も悩みも解消。functionsに色々と処理を任せられるのも大きい。

OAuthで認証するAPIとかはコールバックURLの登録が必須で、Electronで使う場合に困ってたのが、functionsに丸投げすることで解消できて最高だった。

プライベートのはなし

5月に入籍しました。大変幸せに暮らしております。

2018年もいい年になりますように🙏