うしろのこの本ください

なんでもかきます

Vue.jsで全然使ってない機能とかが割とあるって思って

吾輩はなんか使ってない/使う機会がないみたいなVue.jsの機能がある。理由はまだない。

最初に言っちゃうとグローバルで使うようなのは殆ど書いてない。Vue.useくらい?

filter

<!-- mustaches -->
{{ message | capitalize }}

<!-- v-bind -->
<div v-bind:id="rawId | formatId"></div>
filters: {
  capitalize: function (value) {
    if (!value) return ''
    value = value.toString()
    return value.charAt(0).toUpperCase() + value.slice(1)
  }
}

マスタッシュ{{}}かv-bindでパイプ演算子をフィルタにかけたいdataに繋げていくことで使える。パイプは複数連結できて、前から順番に通る。

便利じゃん。なんで使ってないんだろう?って思ったけどdataの加工は全部computedでやってるからかな。よくなさそう。使おう。Vue.filterで使えばグローバルに定義もできる。こういうのはグローバルに生えてても良いのかもしれない。目的が明確だしね。

mixin

// `myOption` カスタムオプションにハンドラを注入する
Vue.mixin({
  created: function () {
    var myOption = this.$options.myOption
    if (myOption) {
      console.log(myOption)
    }
  }
})

new Vue({
  myOption: 'hello!'
})
// => "hello!"

嘘です使ってない理由あります。グローバルmixinは主語がデカくて嫌。スコープを持てない奴は万死。みたいな感じ。なんかそういう事するときはprovideinjectがあるのでそっち使う。

jp.vuejs.org

一応、Vue 3.0からmixinを経由してもクラスAPIでの型が消えないようにはなってるらしいけど。。。使う気起きないな。

observable

const state = Vue.observable({ count: 0 })

const Demo = {
  render(h) {
    return h('button', {
      on: { click: () => { state.count++ }}
    }, `count is: ${state.count}`)
  }
}

2.6から追加された新参者、今後超重要なポジションに付く予定の逸材。しかし書いたことはない。新しいから仕方ないね。

簡単に言えば渡したオブジェクトをリアクティブにできるという機能。オブジェクトは再帰的に探索され、Object.definePropertyを通ってgetterとsetterが生える。2.x系では渡されたオブジェクトを直接弄るが3.0以降は別オブジェクトが返るようになる。

何故この機能の存在が重要かというのはVue.jsのrfcを眺めて見ると何となくわかる。

github.com

ワクワクするrfcだがあまり反響がないように感じる。。。何故。。。

render

render: function (createElement) {
  return createElement('h1', this.blogTitle)
}

所謂描画関数。ReactみたいにJSXがさらっとかける訳でもなく、そもそもtemplate捨ててる時点でVueの良さが死んでる気がして中々手を出し辛い。

templateにfunctionalって書く奴は稀に使う。あれはいいよね、なんか軽そうだし(適当)

Vue 3.0でfunctional componentは遂にただの関数になります!って言われてたけどよく分からない。そうですか。。。

updated

updated: function () {
  this.$nextTick(function () {
    // ビュー全体が再レンダリングされた後にのみ実行されるコード
  })
}

ReactのcomponentDidUpdateに相当するって考えると出番多そうだけど、何故か一回も書いたことがない。

コード例のように$nextTickで子のコンポーネントの再描画を待つことが出来る。便利。しかし書いたことはない。createdmountedは頻繁に書くのにね。

思うに値の変更監視はcomputedでできるVueでは更新時の処理を更新時のライフサイクルメソッドで書かないことが多いんじゃないかと。自分だけなのかな?

ref

<!-- vm.$refs.p は DOM ノード -->
<p ref="p">hello</p>

<!-- vm.$refs.child は child-component のインスタンス -->
<child-component ref="child"></child-component>

全く使った事がないわけではないけど、めったに書かない。要するに子への直接的な参照が欲しい時にrefへ公開させアクセスする。

konva系のライブラリを触った時にcanvasへの参照が必要で書いた。なんかやんちゃ方面なAPIって気がしてる。少なくとも連打して良いもんじゃない。参照を持つってそいつに束縛されるって事だもんね。

cloak

<div v-cloak>
  {{ message }}
</div>
[v-cloak] {
  display: none;
}

上記はv-cloakが付いたDOMはVueインスタンスコンパイル終了時まで見えなくなる。v-cloakCSSと組み合わせて、インスタンスコンパイル終了まで残り続けるcloakを作ることが出来る。(cloakってマントって意味らしいよ)

なにこれ便利じゃん知らんかったわ。使います。

おわり

細かい所言うとVue.versionとか全く使わないけど流石にスルーで。APIのページは結構読んでるつもりだけど知らないのもあって面白かった。

Vue 3.0になった時にまた大きく更新されるだろうし、それも楽しみですね。早くこないかな~~~~~~~~~~~~~~~

おわり

暫くTOKYO

です。インターン行ってきます。

フロントエンドのおしごとします。楽しみです。

東京おうち高いです。暮らすだけでせいいっぱいです。友達がいてよかったと思います。

自宅のPC達ともしばらくはお別れです。それが一番寂しいです。こんなに愛しているのに。

ブログは普通に更新するしMacもってくからコードも書けるのでリクエストあれば対応します。

おわり

最近のミリシタカード事情、スコアタとか

別に研究してるわけでもないので自分が感じていることだけ。間違ってたらTwitterのリプかなんかで言ってくれれば直すし、GitHubでプルリクもOK。

github.com

それから旧フェス限(紬、歌織)と特化限定を比べた時の差の情報も欲しい。わかる人教えて。

スキルについて

先日フェアリー組のフェス限が追加され、これでALL楽曲のサポートメンバーがすべてフェス限で埋まるようになった(と思う)。

センター効果は通常のタイプバフ90%、1色限定編成時タイプバフ95%の2種。

スキルは信号機とPFが持つダブルブースト(以下DB)と、通常のコンボボーナスより少し強い28%バフのフェス限コンボナ(以下Co)がある。

VoDaVi別にまとめると以下のようになる。(Exは省略)

Vo Da Vi 合計枚数
Fa 90%/Co,95%/DB (95%/Co)*2 95%/DB 5
An (95%/Co)*2 95%/DB 90%/Co,95%/DB 5
Pr 95%/DB 90%Co,95%/DB 95%/Co 4

全種95%編成ができるようになり、各タイプ2か所ずつDB持ちを組み込むことができる。

また、Prを除き強化Co持ちを2枚使う事ができる編成もある。

スコアについて

色々な計算式はググれば全部出てくるためここでは省略。計算結果から見て取れる傾向のみに触れる。

当然DB持ちを編成すると理論値は大幅に上がる。PF組が追加されるまでは総アピール値の差もあり「DBを編成に組み込むと理想が伸びて1%~周りが落ちる」という状況だったが現状はアピール値の差が詰まり、DB持ち編成が上回るケースもある。これは志保+伊織のFaDa編成と、貴音+紬のFaVo編成、静香編成等を比べると分かりやすい。

ミリシタにおいてスキル発動率の上限が40%である限り(発動しない確率の方が高い限り)「発動したら強い」カードよりも「発動しなかった時のロスが少ない」カードの方が重要視される。7秒間隔で4秒間発動するスキルが強いという理屈はこれ。

しかし、「7秒は強い」は真だが「7秒より13秒は弱い」は偽。また「偶数秒は弱い」も違う。楽曲の長さによって7秒スキルとの相性は変わるため、ある曲では探偵紬の方がスコアが伸びるけどある曲では限定ロコの方が伸びるという現象は平気で起きる。

基本7秒/4秒や9秒/5秒のようなコスパの良いカードは強いため即採用される。スコア2:コンボナ2~3(orコンボナ2: DB1)のバランスがもっとも良いとされている現在では相方のカードを変更する事が多いが、これは楽曲の長さに合わせなければロスするので注意。ここら辺は書き始めると面倒だから今はスルーで。

コンボナ3>スコア3の理屈はWikiで(誤差)

スコア計算

今後引かなければならないガシャ

特化ステータスカードを所持しているか否かが大きく影響する状態だが、今後はすべてのパターンでこれが発生しかねないためスコアタに影響のないカードだから引かない戦略がし辛くなった。全パターンで95%センター編成できるようになった影響。

今のところ優先順位は以下のようになる。

引いた方が良い

  • 特化ステカード

スルーして良い

  • フェス限と被る発動率のコンボナ

特化ステ律子の例を見ると7秒/4秒と9秒/5秒の特化ステータスカードは一度確保すれば半年以上使っていける。

それ以外は楽曲ごとに対応できるよう1枚は持っておきたい。

旧フェス限カードについて

冒頭でも触れたが、旧フェス限カードの性能はいつか通常限定SSRに追い抜かれる。

対象はフェス限の紬、歌織、星梨花、エミリーで、全員28%コンボボーナス持ち。特化ステータスのインフレが進んで26%コンボナでもそっちを使った方が良いみたいな状況になればフェス限だとしてもリストラする羽目になる。まだ先だとは思うけど気にしておくと良いかもしれない。

退職した

した!!!!!!!!!!!!!!

俺は二―ト!!!!!!!!!!!!!!!!!!!!!!!!!

f:id:apple19940820:20190329223625p:plain

先輩に貰った宝物、大切にします。

おまけ

転職活動中ですがお金がないのでプログラミングのバイトやろうかなと悩んでいます。

Vue/Nuxtできます。依頼はDMかメールで。

人は5分間だけだったら教師になれるかも

って先日鷲崎さんがラジオで喋っててなるほどなって思った。自分は何種類くらい教師になれるだろうと思って考えて見た。

何となくだけどパブリックイメージとして教師=間違ったことを教えてはいけないみたいなところがあるから「これはできるぞ」って思ったものは相応に自身があるものって事になる。

例えば自分なら

  • ポケモンに関する知識
  • (昔の)遊戯王に関する知識
  • 簡単な野球に関する知識
  • 推理SFに関する知識

あたりは5分くらいなら教師できると思っている。ポケモン遊戯王はもはや今の自分を作り上げたといっても良いくらいどっぷりだったし、昔は野球少年だったし、中高、高専時代はよく本を読んだ。

これらは自分の中で枯れた知識になっているため、バックボーンが厚く自信を持つことが出来るわけだ。

逆にこういうのは自身がない。

  • プログラミングに関する知識
  • ラジオに関する知識
  • 歌、音楽に関する知識
  • アイマスの知識

これが何かと考えると、今の自分を構成している要素だった。つまり現在進行形でハマっている or やっているものについて自分はまだ教師が出来るなんて思えるほど自信を持ててないということか。

それから共通点を探すと、これらは割と大人になってから途中参戦したものだった。まだ思い出がないから思い出をバックボーンにして語る事ができない。

人が人に教える時って多分自分の体験を元にすることが多い。それができるのは自分の中で知識が枯れていて、まー喋ってもいいかな間違ってへんやろうしという納得感と、話の材料になる思い出がないと出来ないんだと思った。それでそれが自信という奴になる。

それで5分という短い時間で話したい事、つまりプレゼン資料の中で最優先に伝えたいことを喋ってくれることが期待できる。5分教師というしくみとても面白いですね。

鷲崎さんは知らないお姉さんとかに5分だけ先生やってよ何でもいいからって話を振るのが面白いって言ってた。確かに、得意&好き&伝えたいのコンボプレゼンが面白くないわけないな。

ついでに今の自分のステータスが何となく把握できてそれも面白かった。

おわり

Vue 3.0で入る(予定の)Class APIについてのRFCを読んだ

github.com

Evanが先日VueのRFCに投げたやつ。VueのコンポーネントがES6 Class Syntaxで記述できるよう拡張するというもの。

ブラウザ(CDN版)

class App extends Vue {
  // options declared via static properties (stage 3)
  // more details below
  static template = `
    <div @click="increment">
      {{ count }} {{ plusOne }}
    </div>
  `

  // reactive data declared via class fields (stage 3)
  // more details below
  count = 0

  // lifecycle
  created() {
    console.log(this.count)
  }

  // getters are converted to computed properties
  get plusOne() {
    return this.count + 1
  }

  // a method
  increment() {
    this.count++
  }
}

SFC

<template>
  <div @click="increment">
    {{ count }} {{ plusOne }}
    <Foo />
  </div>
</template>

<script>
import Vue from 'vue'
import Foo from './Foo.vue'

export default class App extends Vue {
  static components = {
    Foo
  }

  count = 0

  created() {
    console.log(this.count)
  }

  get plusOne() {
    return this.count + 1
  }

  increment() {
    this.count++
  }
}
</script>

これに伴い今までのオブジェクトベースで記述する際に行っていた new Vueによるマウントは行わず、別に専用のグローバルなAPIを生やしてそっちでやるようになる。ReactDOM的な?

なんでクラスAPIを入れるか、というのはとても丁寧にEvanが書いてくれているので本文を読んで欲しい。

一応要約すると既存のオブジェクトベースの構文では型推論が効き辛い部分があるため、TypeScriptとの相性改善という面が強い。vue-class-componentの利用も考えられるが、vueのcoreとの互換性維持のオーバヘッドがあって、ならcoreに取り込んだれという感じ。

オブジェクトベースな書き方が出来なくなるわけじゃなく、公式のドキュメントも双方確認できるようにするっぽい。描画関数がどんどん希薄な存在になってる気がするけど。例にあるように、基本はVueのサブクラスを作って使う。

data

dataはクラスフィールドとして宣言できるけど、Field declarationsはまだstage 3なのでTSかBabelが必要。

class MyComponent extends Vue {
  count = 0
}

TypeScriptでは型注釈付けられる。

class MyComponent extends Vue {
  count: number = 1

  created() {
    this.count // number
  }
}

それ以外では普通にconstructorthis.count = 0みたいな奴が考えられる。こっちはコンストラクタの中でsuper()が必須になる。

ただこれは非推奨とされていて、何故かというとコンストラクタの中にいるインスタンスをライフサイクルメソッドからthisで指すことが出来ないため。ライフサイクルメソッドから見たthisは実際には本体のインスタンスを指している。

let instance

class MyComponent extends Vue {
  constructor() {
    super()
    instance = this // actual instance
  }

  created() {
    console.log(this === instance) // false, `this` here is the Proxy
  }
}

というわけで、トランスパイルする手段のない環境では以下のようにオブジェクトベースで書いていたものそのままでも良いようだ。

class MyComponent extends Vue {
  data() {
    return {
      count: 0
    }
  }
}

ライフサイクルフック

ライフサイクルフックはクラスメソッドとして記述する。普通。

class MyComponent extends Vue {
  created() {
    console.log('created')
  }
}

props

propsが結構特殊でなんやかんやあってこれだけデコレータ使うんだけど、ちゃんとその理由も順を追ってサンプルコードと一緒に説明されている。Evanのドキュメントはかなり読みやすい。英語も簡単で紛らわしい表現がなくて助かる。

まず、propsを使うだけならば静的プロパティとして書けばおk。

class MyComponent extends Vue {
  // props declarations are fully compatible with v2 options
  static props = {
    msg: String
  }

  created() {
    // available on `this`
    console.log(this.msg)

    // also available on `this.$props`
    console.log(this.$props.msg)
  }
}

全部$props経由でもアクセスできる。ここはv2と変わりない。v3では宣言自体省略できる。

class MyComponent extends Vue {
  created() {
    console.log(this.$props.msg)
  }
}

TypeScriptによる静的な型のチェックのために@propデコレータが提供されるみたいだ。以下は静的解析時のみに動き、実行時ではstatic props = ["count"]と等価になる。

import { prop } from 'vue'

class MyComponent extends Vue {
  @prop count: number

  created() {
    this.count // number
  }
}

またより具体的な検証のためのオプションオブジェクトも渡せるようになる。

import { prop } from 'vue'

class MyComponent extends Vue {
  @prop({
    validator: val => {
      // custom runtime validation logic
    }
  })
  msg: string = 'hello'

  created() {
    this.count // number
  }
}

propsのデフォルト値を設定したい場合TypeScript側の制限で@props count: number = 1みたいには書けない。オプションオブジェクトのプロパティとして渡す方法が提供されている。

class MyComponent extends Vue {
  @prop({ default: 1 }) foo: number
  bar = this.foo + 1
}

TypeScriptではインターフェイスを定義して渡すことが出来る。

interface MyProps {
  msg: string
}

interface MyData {
  count: number
}

class MyComponent extends Vue<MyProps, MyData> {
  count: number = 1

  created() {
    this.$props.msg
    this.$data.count
  }
}

いいっすね~~~

computed

本家と前後したけどcomputedプロパティはクラスのgetterとして記述する。内部ではVueの算出プロパティに変換され、計算結果やキャッシュを返す。

class MyComponent extends Vue {
  count = 0

  get doubleCount() {
    return this.count * 2
  }
}

methods

普通にクラスメソッドとして書く。ライフサイクルフックもこれ扱い。

class MyComponent extends Vue {
  count = 0

  created() {
    this.logCount()
  }

  logCount() {
    console.log(this.count)
  }
}

このthisは自動的にインスタンスにバインドされ、this.hoge.bind(this)をしなくても良くなっている。

その他

クラスベースAPIにないものは静的フィールドとして宣言する必要がある。たとえばtemplate

class MyComponent extends Vue {
  static template = `
    <div>hello</div>
  `
}

静的クラスフィールドはstage 3なのでトランスパイルが必要。だめならテンプレートリテラルObject.assignなどで取り付ける。

class MyComponent extends Vue {}

MyComponent.template = `
  <div>hello</div>
`

または

class MyComponent extends Vue {}

Object.assign(MyComponent, {
  template: `
    <div>hello</div>
  `
})

継承

普通に extends で継承していける。

class A extends Vue {}
class B extends A {}
class C extends B

Vue.extendでこうするのと同じ意味。

const A = Vue.extend({})
const B = A.extend({})
const C = B.extend({})

UIコンポーネントの直接継承は有用ではないとしている。そのロジックだけを継承し、レンダリングに関してカバーできないため。代わりにmixinかslotによるコンポジション集約をする方が良い。まあ継承の継承は変更に弱くなるのでそもそもアレ。GUIは特に変更が多い領域だし、Javaとかのそれより継承とは相性が悪い。基底クラスからの派生以外ではやらない方がいいと思う。

mixins

型推論が飛ばないようにするにはmixin自体をVueのサブクラスとして宣言する必要があるらしい。実際に使う時はサブクラス化したmixinからさらに拡張して使う。

ただし、型推論が必要ないならオブジェクトベースの書き方でも良い。

import Vue, { mixins } from 'vue'

class MixinA extends Vue {
  // class-style mixin
}

const MixinB = {
  // object-style mixin
}

class MyComponent extends mixins(MixinA, MixinB) {
  // ...
}

その他質問とか

本文読んで。1つだけ紹介すると、Reactはhooksでてクラスから離れていってるよ?っていうのに対してEvanは「Reactのコンポーネントモデルの概念はクラスと相性が良くないけど、本質的にクラスが悪いってわけじゃなくてVueではReactのそれよりも適している。hooksみたいなクラス&オブジェクトベースと同等の機能を持つものも提供するかもしれないけど、まだ先のことだね」とのこと。

その他にも色々考えたけど結局こうなったみたいなのが書いてあって読んでて面白かった。nuxt-tsもリリースされたことだしVue3に向けて素振りしておくと良いかもしれない。Vue.extend or vue-class-component で迷うのはあるけど。

個人的な感想

twitterを眺める限り反応よさげ。自分も良いと思ってます。1つ気になったのがVue.extendについて言及がなかった点だけど、既出だったみたい。

t.co

やりとりを見てるとクラスAPIはこれの置き換えな存在っぽい?Vue.extendの型推論を強化するか、クラスAPIへの機械的(又は内部的)な変換が出るか、まだ結論出てない様子。

はい

@rickyruiz

The RFC does not mention anything about Vue.extend explicitly. As a TypeScript user, I've never needed vue-class-component.

Using classes will be the recommended option for TypeScript users? Are there going to be any disadvantages if I keep using Vue.extend instead of classes? Vue.extend will continue to work as part of the existing object-based API support. However, if you are indeed using TypeScript, it's recommended to use classes in v3 as that's where we will be focusing on in the future in terms of >improving type inference.

ようするに、残すけど型のサポート強化されるしクラスで書いた方が良いと思うよってことらしい

おわり

ミリシタ担当アイドルシートをウェブでつくれるやつつくった

million-tantou-gen.netlify.com

はい

スコア計算機に比べて超省エネだけどまあね。

スマホで一々画像読み込んで配置してってやるよりマシだと思う。Canvasで色々やってるからスマホ対応が面倒でやってない。

ただPWAモジュール入れてるからオフラインでも動くし、PCならChromeのDesktop for PWAでデスクトップアプリ化もできる。メリット分からんけど。最初画像沢山読むけどキャッシュされるから2回目以降は軽い。計算機と一緒。

使ったのはvue-konvaっていうkonvaをvueでラップしたやつ。

github.com

Canvas使うの初めてだったから最初は分けわかんなかったけど何とかなった。ゲーム作ってる人たちはこういうのでゴリゴリやってるんだと思うと正気じゃないね。

こういう軽めのをポンポンあげていきたいとは思いつつ、身が入り切らなくてやべーコード量産しかねないというジレンマがある。これも相当ヤバいからリポジトリ貼りたくないし。見るなら探してご勝手にって感じ。書き捨てだから許して欲しい…

そのうち使いやすくするかもしれん。来週の自分にまかせた。

おわり

ミリシタのスコア計算をする簡易ツールつくった

つくった

millionlive-simple-score-calc.me

みりしたつーるさんのAPIと姫のAPIで成り立ってる。リポジトリはこれ。

github.com

使い方は楽曲選んで、5枚カード選んで、任意の総アピール値を入れて、計算を押す。そうすると1計算で1万回分のライブシミュレーションを行う。編成とアピ値は端末ごとに保存できて呼び出すことが出来る。

シミュ結果はこういう情報。

f:id:apple19940820:20190217040323p:plain

そのチーム編成での楽曲ベーススコアと理論値~50%の確率で達成できるスコア。あとアイコンはFantasiaへの個別カードリンクになってる。同僚は自分のリーダーと同じになるようにしてある。(手抜いた)

詳細はそのカードのスキルがその楽曲プレイ時に何回まで発動するかと、シミュ1万回で合計何回発動したかが書いてある。今思えばリザルトに総アピール値書いてないな。。。まあいいや

f:id:apple19940820:20190217034717p:plain

ほぼみりしたつーるのAPIで返って来る値まま。

情報量が少なくてさくっと動いて、自分の使ってる編成が使い物になるかどうか分かるだけで良かったから余計だと思った機能は全部削った。

スマホならホーム画面に追加をするとアプリ化できる。PWAってやつ。PCもChromeでメニューからインストールみたいなのするとデスクトップアプリ化できる。

f:id:apple19940820:20190217044615p:plain

f:id:apple19940820:20190217044632p:plain

f:id:apple19940820:20190217044728p:plain

オフラインでも動くと行きたいけどシミュ1万回をブラウザでやるのは結構色々準備がいるのでまだ。実装は試すかも、そしたらネットに繋がってなくてもシミュ回せるようになる。

技術的な方の話

Nuxt.js + Element UIで作ってデータは全部API経由で取得する。一部は自分で建てたFirebaseのcloud functionsを経由している。(モバイル対応)

ホストはNetlifyで、GitHubのmasterが更新されたら自動的にNuxt generateが走って静的なサイトがデプロイされる。

PWAモジュールを雑に突っ込んであって、1発目の読み込み以降はキャッシュが効いて早くなる。楽曲データに関してはlocalStorageに保存して、最後尾楽曲のidをリクエストで投げて更新があれば差分が戻って来るようにした。(API追加のissueを出して対応して貰った、ありがとうございました)

チーム編成もlocalStorageに保存してある。というか、vuex-persistedstateでストアと同期している。これめっちゃ便利ね。

github.com

これ作り始めたのが去年の年末で、ラウンジのメンバーにフィードバック貰いつつこの形に落ち着いた。今後はTSで置き換えられるところは置き換えていきたいのと、スクショからチームをセットできる機能を付けたい。やっぱポチポチ面倒だし総アピ値いちいち入れるのもだるい。

あとこのアプリに実装するかは分からないけど、手持ち一覧のスクショから強そうなチームを作って提案するとか。こっちは色々事情があって難しそうだけど。あれば便利。

要望あればリプでもDMでもissueでもなんでもいいので投げて貰えれば出来るときにやります。

おわり

Element UIのel-tableでslot-scopeを使っていた人はVue2.6.xにあげるのは待った方がいいかも

先日Vue2.6.0がリリースされてv-slotが追加されたので、ついでにNuxtと一緒にバージョンアップしようとしたら既存コンポーネントが動かなくなった。

Element UIのel-tableはel-table-column内にslotを差し込むことで任意の要素を表示できる。この部分で今まではslot-scopを使っていたがVue2.6.0での変更によって壊れてしまったみたいだ。

issue

github.com

自分が壊れたのを確認したのは以下のコードだ

<el-table :data="selectedCardList" target-order="push" max-height="960">
  <el-table-column label="カード">
      <template slot-scope="scope">
        <a :href="createImgUrl(scope.row.id)" target="_blunk"><img :src="scope.row.resourceId" style="max-width: 100px; width: 100%;"/></a>
      </template>
  </el-table-column>
  <el-table-column label="ボーカル値">
      <template slot-scope="scope">
        <span>{{ scope.row.vocalMaxAwakened }}<br>{{ "(" + `${scope.row.vocalMaxAwakened + scope.row.vocalMasterBonus * 4}` + ")" }}</span>
      </template>
  </el-table-column>
  <el-table-column label="ビジュアル値">
      <template slot-scope="scope">
        <span>{{ scope.row.visualMaxAwakened }}<br>{{ "(" + `${scope.row.visualMaxAwakened + scope.row.visualMasterBonus * 4}` + ")" }}</span>
      </template>
  </el-table-column>
  <el-table-column label="ダンス値">
      <template slot-scope="scope">
        <span>{{ scope.row.danceMaxAwakened }}<br>{{ "(" + `${scope.row.danceMaxAwakened + scope.row.danceMasterBonus * 4}` + ")" }}</span>
      </template>
  </el-table-column>
</el-table>

ミリシタのカードデータ表示部分で使っていた。特にURLを整形してPrincessへのリンクを貼るところとか他にどうしようもないし、一旦Nuxtごとバージョンを戻した。

対処法

scope.row ? scope.row.title : '' のようにv-ifでscope-rowの値を見ると通る。恐らくv-slotが親のレンダリングサイクルから分離し、子としてインライン関数に展開される最適化がされているため起こったもの。

v-slotと親テーブルのレンダリング処理が分離したので、v-slotより先に親テーブルがコンパイルされて、未定義の子を参照しようとして落ちるという話。

v-ifでv-slotがレンダリングされるまでは空を返してやれば良いということだ。

v-slotに合わせてslot-scopeも同様の動作になるよう変更されている。つまり現状v-ifを付けない限り解決はできない。(代替手段がない)

ただし、テーブルコンポーネントのような要素の多いものにv-ifを付けて回るのもアレなので余程急ぎでもない限りElementUI自体のアプデを待った方が賢明だろう。

Nuxtだけバージョン上げてNuxtが使うVueのバージョンだけ下げるみたいなこと出来ないのかな。いやできるだろうけど、出来るだけそういうので苦労はしたくない。

おわり

ミリシタライブシミュレーションAPI 「API for TD Score Calculation 」をNuxt.jsで使う

多分みんな使ってる編成とか出してくれるツールの計算部分だけAPIに切り出して公開してくれたもの。まだ試験運用らしい。

api.megmeg.work

ツールの方

megmeg.work

んで作った奴

github.com

使い方というか、GETで投げる時のパラメータが必要でそれの情報源としてmatsurihi.me使う前提な感じあるので前作った奴を拡張する形で進めた。

その時の記事

ushirock.hateblo.jp

megmeg.work が提供しているのは以下の3つ

  • 楽曲情報
  • 単体チーム編成で指定楽曲のライブシミュレーション
  • 複数チーム編成で指定楽曲のライブシミュレーション

つまり、計算に用いる楽曲の情報も提供している。(計算式の関係もあるだろうしそりゃそう)

楽曲情報にはそれぞれIDが振られていて指定すれば1つずつ取れるが、今回はページロード時に楽曲選択用コンポーネントのcreatedで全曲分取ってVuexストアに入れている。

components/songs/SongSelectionView.vue

  async created() {
    await this.$store
      .dispatch('fetchMusicData')
      .then(() => {
        this.$notify.success({
          title: '成功',
          message: '楽曲情報を更新しました',
          position: 'top-right',
          duration: '3000'
        })
      })
      .catch(err => {
        this.$notify.error({
          title: '失敗',
          message: `${err}`,
          position: 'top-right',
          duration: '3000'
        })
      })
  },

取得した楽曲から1つ選んで指定、チームをポチポチして計算開始ボタンを押すと単体チーム編成で指定楽曲のライブシミュレーションをするAPIに計算に必要なデータを整形して飛ばす。

これもストア経由だが返却値が3種あって扱いやすいように配列に詰めなおしている。fetchLiveSimulationData → setLiveSimulationData → liveSimulationData → getterから値取得の流れ。

store/index.js

export const state = () => ({
  //...省略
  liveSimulationData: []
})

export const getters = {
  //...省略
  liveSimulationData: state => state.liveSimulationData
}

export const mutations = {
  //...省略
  setLiveSimulationData(state, data) {
    data.forEach(x => {
      state.liveSimulationData.push(x)
    })
  }
}

export const actions = {
  //...省略
  async fetchLiveSimulationData({ commit }, payload) {
    const resultData = await this.$axios.$get(
      `https://api.megmeg.work/mltd/v1/score/singleunit/`,
      {
        params: payload
      }
    )
    commit('setLiveSimulationData', resultData)
  }
}

actions で引数として受け取るpayloadには単体チーム編成でのシミュに必要な情報が入っている。以下がmatsurihi.meとmegmeg.workから得たカード、楽曲情報を詰め替えてpayloadにする部分。

components/cards/CardTransfer.vue

const music = this.selectedMusic
const team = this.selectedCardList
const SongId = music[0].SongId
const Course = 4
const AppealValue = this.appealValue
const Unitlds = team.map(x => {
    return x.id
})
const GuestId = team[0].id
const SkillLvs = [10, 10, 10, 10, 10]
const TryNumber = 10000
const Prob = [0.1, 1, 50]
const Minimize = false

const requestParams = {
    SongId: SongId,
    Course: Course,
    AppealValue: AppealValue,
    UnitIds: Unitlds,
    GuestId: GuestId,
    SkillLvs: SkillLvs,
    TryNumber: TryNumber,
    p: Prob,
    Minimize: Minimize
}

そのままactionsにdispatchする。ここら辺の値についてはAPIドキュメントを読む方が早い。

サンプルコードがjQueryなのでaxiosとオプションの名前が違う点は注意。axiosではGETリクエストパラメータはdataではなくparams。それからチームのアピール値が必須なんだけど、ここを計算で出す場合matsurihi.meから得られる情報を使って求めることになる。面倒だし人によって変動が大きいため手動が無難。本家ミリシタツールも手入力。

動作画面はこんな感じ。

f:id:apple19940820:20190121002711g:plain

複数チームでのシミュレーションはまだ試してない。

matsurihi.meと同じく使う場合注意。また、サービスとして公開するならmegmeg.workの表記も必要。

追記

楽曲を毎回全件取得するのもあれなので、1回取ったらlocalStorageに突っ込んで楽曲更新があれば差分取得するようにした。みりしたつーるさんにincrementalUpdateの実装をお願いしたら1日で実装してくれた。ありがとうございました。

おわり

React+TypeScriptの勉強を兼ねてポートフォリオつくった

つくった

ushironoko2.me

TSのサポートのお陰でほぼ実行時エラーに悩まされることはなくなったけど、Material-UIのコンポーネントの型とかで結構苦労した。

今思えば新しくReactとTypeScriptとMaterial-UIとJSXを同時に始めるってのはカロリー高い。とくに+TypeScriptの面が辛かった。いやマジで。

あとOGPまでやる体力がなかった。上司に風邪うつされてかなりしんどい。。。

感想

完走した感想ですが、やっぱりVue.jsよりコスト高い。HTMLベースで直感的に書けるVue.jsとは違って全てがJavaScriptの世界だから、特にCSS周りで苦戦する。

最初はstyled-components使ってたんだけど一応ポートフォリオなんで素直にUIコンポーネントに頼る事にした。結果かなり時間使ってしまったが。

それと、Reactは現在も成長中なのでコンポーネントの書き方が複数あって混乱する。とりあえずコンポーネントのエンドポイントになる親のみクラスで書いて、子は全部FCにしたけど、FCに渡すpropsの型がMaterial-UIが絡むとおよよ…ってなる。

最初はMaterial-UIのWithStylesと一緒に渡すとsuper(props)って出来なくて、後から&で複数の型を指定できることを知った。

ググっても2015年あたりの古い記事が結構出てくる(日本語)。componentWillMountは廃止予定らしいが、Hooks使ってくれって事?

ライフサイクルメソッドもまだ勉強しきれてない。とりあえずFCには書けないので親が持つstateを書き換えてpropsを更新する感じになる。この辺はそれぞれのコンポーネントインスタンスを保持するVue.jsとは結構違う(FCだと)。

てか苦労の80%はMaterial-UI+TypeScript関連なんですけど。マジで辛かった。ドキュメントも多いとは言えない。これは続けていれば英語に強くなるタイプのアレだ。

総評

総じてやんちゃ出来ないなという印象。+TSで型を縛るとなるほど堅牢。フロントはゆるふわで行きたいんです~って人には向いてないと思った。書く前はJavaプログラマとかはむしろ向いてるんじゃない?って思ってたけど、フロントで消耗したくない適当に書きたいって人が出そうなくらいガチガチだったから微妙。個人的には印象は良かった半面Vue.jsの緩さが恋しくなった。

今後

書く優先度的には Nuxt > React = Vue くらいになりそう。Nuxtの考えなくてもある程度の設計を保証してくれる世界観は貴重っぽい(あと日本語)。Reactはフロントでサーバーサイドプログラミングしてる気分になる。

個人的な趣味でSPA作るうえでVue.jsの緩さだと危くなるような場面があまり思い浮かばないが、TSに慣れれば手なりで書けることも増えて今よりは苦労しなくなるだろう。多分。そこそこ書けるようになってからが型の恩恵の本領だから。(デザイン周りもうちょいなんとかならんか)

おわり

ミリシタのラウンジ名でTwitterエゴサしてDiscordに飛ばす奴

最近ミリシタ関連のものしか作ってねーな

github.com

前のocrの奴の流用。基盤自体が出来てるから検索ワードを変えてフィルタリング処理増やしただけ。

あとついでに全部TypeScriptで書き直した。VSCodeとの相性は評判通り物凄い良い。自製ライブラリもないので大概@typesに型定義が転がってるのも楽で良かった。

型推論バリバリ効くからElasticsearchのレスポンスの中身がしっかり予測変換で出てきて助かる。こういうのがJavaScriptで出来るだけで体験が全く変わって来るね。

今回のはdiscordに対してwebhookで投げてるだけだからいいけど、これをウェブアプリとかにするとなるとクライアント側からのリクエストのルーティングだとかページネーションだとかを実装しないといけない。

結構面倒だから先にディスコ版つくったのが経緯。ウェブ版需要あるなら作るけど今一ElasticsearchのScroll APIが分かってない。まあなんとかなるでしょ。

クライアント側はReact+TSで作るつもりだけどカロリー高そうだったらVueかNuxtでやっちゃうと思う。休み長い訳じゃないしね。

おわりだよ~

ミリシタライブレポートから実績情報をOCRで読み取るやつ

お試しでつくった

github.com

簡単な実装しかしてないけど、一応動く。技術スタックは以下

  • Elasticsearch
  • Logstash
  • Tesseract.js

詳しくはリポジトリに書いてある。Elasticsearch に Logstash が取得したライブレポートの Twitter 情報を送ってため込む。

Erasticsearch の REST API 叩いて必要な情報(主に画像URL)を取得したら、request で画像をダウンロードして Tesseract へ渡す。それだけ。

なんで Elasticsearch なのかっていうと別件で AWS に Logstash と一緒に建ててたから。結局そっちの方は色々あって駄目になったんだけど、Logstash の Twitter input plugin の検索ワードだけ変えれば流用出来る事に気づいたのでそのまま使った。

Tesseract の部分は本来 Cloud VisionAWS Rekognition になる予定だったけど手元で実行できればとりあえず良かったので見送り。

そもそも GCP でやるつもりだった。Amazon Elastic Service がかなり楽だったし、余ってる EC2 インスタンスもあったので AWS で完結させた。

画像は今はディレクトリに突っ込んでるけど本来は S3 に投げつけてアップロードイベントで Lambda を発火してその中で Rekognition 呼ぶ構成だった。色々妥協したし Node のコードもかなり雑。サーバーサイドjsの非同期なコード真面目に書くの初めてだったから結構大変だった。お陰で AWS と Node の知見はそこそこ溜まった。

Tesseract.js は出力結果を JSON で吐いてくれないし、得た結果は Elasticsearch に戻そうと思ってたからここは S3 に突っ込む部分と一緒に Rekognition で再実装すると思う。完成したらまた記事書く。

結局これで何がしたいかって言うと、ある程度データが溜まったらリザルトレポートの画像からプレイの評価をしてくれるTwitterBotが作りたかった。フォローしてるとリザルト投稿した時に自動でリプして評価してくれるみたいな。出来るか分からんけどとりあえずデータ収集から入った形。

あと白よりの情報源が欲しかったってのもある。解析とかしてそうなもの結構あるんだけど、それ本番サービスで使い辛いなって思って自前でデータ用意するなら自動化したいというお気持ちが出てきた。まあそんな感じ。

結果例。流石に精度悪い。座標も何も渡してないし仕方ない。途中でスコアの前に#が入って VSCode がカラーコード扱いで色付けてるの面白かった。

f:id:apple19940820:20190108232844p:plain

おわり

ミリシタチームアナライザー使用感メモ

作ってるツールで実装に迷ったら、その時点でベータ版にしてある程度使ってみると良い。というわけでミリシタイベントRtF中に今作りかけのチーム編成最適化ツールを使ってみた。

その使用感メモ。リポジトリはこれ

github.com

欲しくなった機能

  • カード能力の偏りで検索(VoDaViタイプ)
  • 総合アピ値表示
  • 単体アピ値表示
  • 曲との相性表示
  • 3人でのスキル発動被り
  • スコア/コンボ でスキル発動被り検知の分割

その内欲しくなりそうな機能

  • チーム保存
  • チーム単位での比較

issue に積んどく

おわり

Twitterに投稿されたミリシタのプレイリザルトからGCPのVision API OCRで情報を積む試み

っていうのができそう。画像はテキストでTwitterスクレイピングした奴を Cloud Storage にため込む。んで Storage のアップロードトリガーで Cloud Functions を蹴って、Functions の内部で Vision API を呼び出すって感じ。スクレイピングも Functions で書けば GCP で完結させることもできるね。別に他で実装して GAE でもいいけど。図にするとこんな感じ。

f:id:apple19940820:20190104043622j:plain

以下参考記事

Cloud Functions と Vision API を連携して画像解析を試してみる - Qiita

光学式文字認識(OCR)  |  Cloud Vision API ドキュメント  |  Google Cloud

Puppeteer + GCP Functionsでサーバレスなスクレイピング - Qiita

Twitterをスクレイピングするスクリプトをgithubに公開しました! - ブロックチェーンエンジニアとして生きる

ネックになりそうなのはやったことない Functions での Puppeteer 使ったスクレイピングVision API 回りだけど、あんまり心配してない。それよりも Twitter OAuth の使い方完全に忘れててそっちのが面倒な気がしてる。まあ大丈夫か。

これ上手くいけばスクショから情報を積み上げる基盤になるので結構需要ありそう。API の公開はちゃんとできる自信ないからやんないけどね。

明日(今日)から試しに書いてみる。使いすぎると GCP の無料枠超える事があるから気を付けないと。どうせ1円とかだけど。

おわり